void pthread_exit(void * retval) { pthread_descr self = thread_self(); pthread_descr joining; struct pthread_request request; /* Reset the cancellation flag to avoid looping if the cleanup handlers contain cancellation points */ self->p_canceled = 0; /* Call cleanup functions and destroy the thread-specific data */ __pthread_perform_cleanup(); __pthread_destroy_specifics(); /* Store return value */ acquire(self->p_spinlock); self->p_retval = retval; /* Say that we've terminated */ self->p_terminated = 1; /* See if someone is joining on us */ joining = self->p_joining; release(self->p_spinlock); /* Restart joining thread if any */ if (joining != NULL) restart(joining); /* If this is the initial thread, block until all threads have terminated. If another thread calls exit, we'll be terminated from our signal handler. */ if (self == __pthread_main_thread && __pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_MAIN_THREAD_EXIT; write(__pthread_manager_request, (char *)&request, sizeof(request)); suspend(self); } /* Exit the process (but don't flush stdio streams, and don't run atexit functions). */ _exit(0); }
void __pthread_do_exit(void *retval, char *currentframe) { pthread_descr self = thread_self(); pthread_descr joining; struct pthread_request request; PDEBUG("self=%p, pid=%d\n", self, self->p_pid); /* obey POSIX behavior and prevent cancellation functions from * being called more than once. * http://sourceware.org/ml/libc-ports/2006-10/msg00043.html */ THREAD_SETMEM(self, p_cancelstate, PTHREAD_CANCEL_DISABLE); THREAD_SETMEM(self, p_canceltype, PTHREAD_CANCEL_DEFERRED); /* Call cleanup functions and destroy the thread-specific data */ __pthread_perform_cleanup(currentframe); __pthread_destroy_specifics(); /* Store return value */ __pthread_lock(THREAD_GETMEM(self, p_lock), self); THREAD_SETMEM(self, p_retval, retval); /* See whether we have to signal the death. */ if (THREAD_GETMEM(self, p_report_events)) { /* See whether TD_DEATH is in any of the mask. */ int idx = __td_eventword (TD_DEATH); uint32_t mask = __td_eventmask (TD_DEATH); if ((mask & (__pthread_threads_events.event_bits[idx] | THREAD_GETMEM_NC(self, p_eventbuf.eventmask).event_bits[idx])) != 0) { /* Yep, we have to signal the death. */ THREAD_SETMEM(self, p_eventbuf.eventnum, TD_DEATH); THREAD_SETMEM(self, p_eventbuf.eventdata, self); __pthread_last_event = self; /* Now call the function to signal the event. */ __linuxthreads_death_event(); } } /* Say that we've terminated */ THREAD_SETMEM(self, p_terminated, 1); /* See if someone is joining on us */ joining = THREAD_GETMEM(self, p_joining); PDEBUG("joining = %p, pid=%d\n", joining, joining->p_pid); __pthread_unlock(THREAD_GETMEM(self, p_lock)); /* Restart joining thread if any */ if (joining != NULL) restart(joining); /* If this is the initial thread, block until all threads have terminated. If another thread calls exit, we'll be terminated from our signal handler. */ if (self == __pthread_main_thread && __pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_MAIN_THREAD_EXIT; TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, (char *)&request, sizeof(request))); suspend(self); /* Main thread flushes stdio streams and runs atexit functions. * It also calls a handler within LinuxThreads which sends a process exit * request to the thread manager. */ exit(0); } /* Exit the process (but don't flush stdio streams, and don't run atexit functions). */ _exit(0); }