/** \internal * \brief The system call that implements the htread_exit functionality. * * \author Wesley Peck <*****@*****.**> * * This function is the system call routine which implements the * hthread_exit functionality for hthreads. The user space function * hthread_exit invokes this function to terminate a thread. * * \param retval The return value of the thread. If the currently * running thread is in the joinable state then this * value is returned to the thread which joins with * the currently running thread, otherwise this * value is discarded. * \return This function never returns to the calling thread. */ void _syscall_exit( void *retval ) { Huint status; Huint current; Hbool destroy_flag = Hfalse; // Print out a trace message about this system call TRACE_PRINTF( TRACE_FINE, TRACE_SYSCALL, "SYSCALL: (OP=EXIT) (RET=0x%8.8x)\n", (Huint)retval ); // Grab the current thread current = _current_thread(); // Print out a trace message about this system call TRACE_PRINTF( TRACE_FINE, TRACE_SYSCALL, "SYSCALL: (OP=EXIT) (TID=0x%8.8x) (RET=0x%8.8x)\n", (Huint)current, (Huint)retval ); if( _detached_thread(current) ) destroy_flag = Htrue; // The return value needs to be saved before we // try to exit the thread (to avoid race conditions when a parent joins // a thread and trys to get the return value). Note that we don't // need to save the return value for a detached thread. threads[current].retval = retval; // FIXME: We should check the error condition during the while loop // to ensure that the error was because the ready-to-run queue is // full. Any other error is fatal and since this function never returns // to the caller we must handle this error. status = _exit_thread( current ); while( has_error(status) ) { DEBUG_PRINTF( "Exit returned an error: (STA=0x%8.8x)\n", status ); // Yield the processor to another thread. _syscall_yield(); // Try to exit again after some other thread has run. status = _exit_thread( current ); } // If the thread is a detached thread then it can be destroyed right // away. Joinable threads cannot be destroyed until they have been joined // by some other thread (see _syscall_join). if( destroy_flag ) { _destroy_thread( current ); TRACE_PRINTF( TRACE_FINE, TRACE_SYSCALL, "** DETACHED = 0x%8.8x **\n",destroy_flag); } // Print out a trace message about this system call TRACE_PRINTF( TRACE_FINE, TRACE_SYSCALL, "SYSCALL DONE: (OP=EXIT) (RET=0x%8.8x)\n", (Huint)retval ); // We have now exited. Run the scheduler and never come back. _run_sched( Hfalse ); }
void pthread_exit(void * retval) { pthread_internal_t* thread = __get_thread(); void* stack_base = thread->attr.stack_base; int stack_size = thread->attr.stack_size; int user_stack = (thread->attr.flags & PTHREAD_ATTR_FLAG_USER_STACK) != 0; sigset_t mask; // call the cleanup handlers first while (thread->cleanup_stack) { __pthread_cleanup_t* c = thread->cleanup_stack; thread->cleanup_stack = c->__cleanup_prev; c->__cleanup_routine(c->__cleanup_arg); } // call the TLS destructors, it is important to do that before removing this // thread from the global list. this will ensure that if someone else deletes // a TLS key, the corresponding value will be set to NULL in this thread's TLS // space (see pthread_key_delete) pthread_key_clean_all(); // if the thread is detached, destroy the pthread_internal_t // otherwise, keep it in memory and signal any joiners. pthread_mutex_lock(&gThreadListLock); if (thread->attr.flags & PTHREAD_ATTR_FLAG_DETACHED) { _pthread_internal_remove_locked(thread); } else { /* make sure that the thread struct doesn't have stale pointers to a stack that * will be unmapped after the exit call below. */ if (!user_stack) { thread->attr.stack_base = NULL; thread->attr.stack_size = 0; thread->tls = NULL; } /* Indicate that the thread has exited for joining threads. */ thread->attr.flags |= PTHREAD_ATTR_FLAG_ZOMBIE; thread->return_value = retval; /* Signal the joining thread if present. */ if (thread->attr.flags & PTHREAD_ATTR_FLAG_JOINED) { pthread_cond_signal(&thread->join_cond); } } pthread_mutex_unlock(&gThreadListLock); sigfillset(&mask); sigdelset(&mask, SIGSEGV); (void)sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL); // destroy the thread stack if (user_stack) _exit_thread((int)retval); else _exit_with_stack_teardown(stack_base, stack_size, (int)retval); }