void remove_thread(unsigned int thread_id) #endif { struct thread_entry *current = cores[CURRENT_CORE].running; struct thread_entry *thread = thread_id_entry(thread_id); SDL_Thread *t; SDL_sem *s; if (thread_id != THREAD_ID_CURRENT && thread->id != thread_id) return; int oldlevel = disable_irq_save(); t = thread->context.t; s = thread->context.s; thread->context.t = NULL; if (thread != current) { switch (thread->state) { case STATE_BLOCKED: case STATE_BLOCKED_W_TMO: /* Remove thread from object it's waiting on */ remove_from_list_l(thread->bqp, thread); #ifdef HAVE_WAKEUP_EXT_CB if (thread->wakeup_ext_cb != NULL) thread->wakeup_ext_cb(thread); #endif break; } SDL_SemPost(s); } THREAD_SDL_DEBUGF("Removing thread: %d (%s)\n", thread - threads, THREAD_SDL_GET_NAME(thread)); new_thread_id(thread->id, thread); thread->state = STATE_KILLED; thread_queue_wake(&thread->queue); SDL_DestroySemaphore(s); if (thread == current) { /* Do a graceful exit - perform the longjmp back into the thread function to return */ restore_irq(oldlevel); longjmp(thread_jmpbufs[current - threads], 1); } SDL_KillThread(t); restore_irq(oldlevel); }
unsigned int wakeup_thread(struct thread_entry **list) { struct thread_entry *thread = *list; if (thread != NULL) { switch (thread->state) { case STATE_BLOCKED: case STATE_BLOCKED_W_TMO: remove_from_list_l(list, thread); thread->state = STATE_RUNNING; SDL_SemPost(thread->context.s); return THREAD_OK; } } return THREAD_NONE; }
void remove_thread(unsigned int thread_id) #endif { struct thread_entry *current = cores[CURRENT_CORE].running; struct thread_entry *thread = thread_id_entry(thread_id); SDL_Thread *t; SDL_sem *s; if (thread_id != THREAD_ID_CURRENT && thread->id != thread_id) return; int oldlevel = disable_irq_save(); t = thread->context.t; s = thread->context.s; /* Wait the last thread here and keep this one or SDL will leak it since * it doesn't free its own library allocations unless a wait is performed. * Such behavior guards against the memory being invalid by the time * SDL_WaitThread is reached and also against two different threads having * the same pointer. It also makes SDL_WaitThread a non-concurrent function. * * However, see more below about SDL_KillThread. */ SDL_WaitThread(thread->context.told, NULL); thread->context.t = NULL; thread->context.s = NULL; thread->context.told = t; if (thread != current) { switch (thread->state) { case STATE_BLOCKED: case STATE_BLOCKED_W_TMO: /* Remove thread from object it's waiting on */ remove_from_list_l(thread->bqp, thread); #ifdef HAVE_WAKEUP_EXT_CB if (thread->wakeup_ext_cb != NULL) thread->wakeup_ext_cb(thread); #endif break; } SDL_SemPost(s); } THREAD_SDL_DEBUGF("Removing thread: %d (%s)\n", thread - threads, THREAD_SDL_GET_NAME(thread)); new_thread_id(thread->id, thread); thread->state = STATE_KILLED; thread_queue_wake(&thread->queue); SDL_DestroySemaphore(s); if (thread == current) { /* Do a graceful exit - perform the longjmp back into the thread function to return */ restore_irq(oldlevel); longjmp(thread_jmpbufs[current - threads], 1); } /* SDL_KillThread frees the old pointer too because it uses SDL_WaitThread * to wait for the host to remove it. */ thread->context.told = NULL; SDL_KillThread(t); restore_irq(oldlevel); }
void switch_thread(void) { struct thread_entry *current = cores[CURRENT_CORE].running; enable_irq(); switch (current->state) { case STATE_RUNNING: { SDL_UnlockMutex(m); /* Any other thread waiting already will get it first */ SDL_LockMutex(m); break; } /* STATE_RUNNING: */ case STATE_BLOCKED: { int oldlevel; SDL_UnlockMutex(m); SDL_SemWait(current->context.s); SDL_LockMutex(m); oldlevel = disable_irq_save(); current->state = STATE_RUNNING; restore_irq(oldlevel); break; } /* STATE_BLOCKED: */ case STATE_BLOCKED_W_TMO: { int result, oldlevel; SDL_UnlockMutex(m); result = SDL_SemWaitTimeout(current->context.s, current->tmo_tick); SDL_LockMutex(m); oldlevel = disable_irq_save(); if (current->state == STATE_BLOCKED_W_TMO) { /* Timed out */ remove_from_list_l(current->bqp, current); #ifdef HAVE_WAKEUP_EXT_CB if (current->wakeup_ext_cb != NULL) current->wakeup_ext_cb(current); #endif current->state = STATE_RUNNING; } if (result == SDL_MUTEX_TIMEDOUT) { /* Other signals from an explicit wake could have been made before * arriving here if we timed out waiting for the semaphore. Make * sure the count is reset. */ while (SDL_SemValue(current->context.s) > 0) SDL_SemTryWait(current->context.s); } restore_irq(oldlevel); break; } /* STATE_BLOCKED_W_TMO: */ case STATE_SLEEPING: { SDL_UnlockMutex(m); SDL_SemWaitTimeout(current->context.s, current->tmo_tick); SDL_LockMutex(m); current->state = STATE_RUNNING; break; } /* STATE_SLEEPING: */ } cores[CURRENT_CORE].running = current; if (threads_status != THREADS_RUN) thread_exit(); }