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); }
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); }