diff options
Diffstat (limited to 'libpthread/linuxthreads/join.c')
-rw-r--r-- | libpthread/linuxthreads/join.c | 57 |
1 files changed, 34 insertions, 23 deletions
diff --git a/libpthread/linuxthreads/join.c b/libpthread/linuxthreads/join.c index 57ea54e34..4a7c0d8ac 100644 --- a/libpthread/linuxthreads/join.c +++ b/libpthread/linuxthreads/join.c @@ -14,31 +14,38 @@ /* Thread termination and joining */ +#include <features.h> #include <errno.h> #include <sched.h> -#include <stdlib.h> #include <unistd.h> +#include <stdlib.h> #include "pthread.h" #include "internals.h" #include "spinlock.h" #include "restart.h" -#include <not-cancel.h> +#include "debug.h" /* PDEBUG, added by StS */ -void __pthread_exit(void * retval) +libpthread_hidden_proto(pthread_exit) +void pthread_exit(void * retval) { __pthread_do_exit (retval, CURRENT_STACK_FRAME); } -strong_alias (__pthread_exit, pthread_exit) +libpthread_hidden_def (pthread_exit) 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); - /* Reset the cancellation flag to avoid looping if the cleanup handlers - contain cancellation points */ - THREAD_SETMEM(self, p_canceled, 0); /* Call cleanup functions and destroy the thread-specific data */ __pthread_perform_cleanup(currentframe); __pthread_destroy_specifics(); @@ -54,7 +61,7 @@ void __pthread_do_exit(void *retval, char *currentframe) if ((mask & (__pthread_threads_events.event_bits[idx] | THREAD_GETMEM_NC(self, - p_eventbuf.eventmask.event_bits[idx]))) + p_eventbuf.eventmask).event_bits[idx])) != 0) { /* Yep, we have to signal the death. */ @@ -70,6 +77,7 @@ void __pthread_do_exit(void *retval, char *currentframe) 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 ? joining->p_pid : 0); __pthread_unlock(THREAD_GETMEM(self, p_lock)); /* Restart joining thread if any */ if (joining != NULL) restart(joining); @@ -79,25 +87,25 @@ void __pthread_do_exit(void *retval, char *currentframe) if (self == __pthread_main_thread && __pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_MAIN_THREAD_EXIT; - TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, - (char *)&request, sizeof(request))); + TEMP_FAILURE_RETRY(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. */ + * It also calls a handler within LinuxThreads which sends a process exit + * request to the thread manager. */ exit(0); } - /* Threads other than the main one terminate without flushing stdio streams - or running atexit functions. */ + /* Exit the process (but don't flush stdio streams, and don't run + atexit functions). */ _exit(0); } /* Function called by pthread_cancel to remove the thread from waiting on a condition variable queue. */ -static int join_extricate_func(void *obj, pthread_descr th) +static int join_extricate_func(void *obj, pthread_descr th attribute_unused) { - __volatile__ pthread_descr self = thread_self(); + volatile pthread_descr self = thread_self(); pthread_handle handle = obj; pthread_descr jo; int did_remove = 0; @@ -113,19 +121,20 @@ static int join_extricate_func(void *obj, pthread_descr th) int pthread_join(pthread_t thread_id, void ** thread_return) { - __volatile__ pthread_descr self = thread_self(); + volatile pthread_descr self = thread_self(); struct pthread_request request; pthread_handle handle = thread_handle(thread_id); pthread_descr th; pthread_extricate_if extr; int already_canceled = 0; + PDEBUG("\n"); /* Set up extrication interface */ extr.pu_object = handle; extr.pu_extricate_func = join_extricate_func; __pthread_lock(&handle->h_lock, self); - if (nonexisting_handle(handle, thread_id)) { + if (invalid_handle(handle, thread_id)) { __pthread_unlock(&handle->h_lock); return ESRCH; } @@ -155,7 +164,9 @@ int pthread_join(pthread_t thread_id, void ** thread_return) __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME); } + PDEBUG("before suspend\n"); suspend(self); + PDEBUG("after suspend\n"); /* Deregister extrication interface */ __pthread_set_own_extricate_if(self, 0); @@ -175,8 +186,8 @@ int pthread_join(pthread_t thread_id, void ** thread_return) request.req_thread = self; request.req_kind = REQ_FREE; request.req_args.free.thread_id = thread_id; - TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, - (char *) &request, sizeof(request))); + TEMP_FAILURE_RETRY(write(__pthread_manager_request, + (char *) &request, sizeof(request))); } return 0; } @@ -189,7 +200,7 @@ int pthread_detach(pthread_t thread_id) pthread_descr th; __pthread_lock(&handle->h_lock, NULL); - if (nonexisting_handle(handle, thread_id)) { + if (invalid_handle(handle, thread_id)) { __pthread_unlock(&handle->h_lock); return ESRCH; } @@ -213,8 +224,8 @@ int pthread_detach(pthread_t thread_id) request.req_thread = thread_self(); request.req_kind = REQ_FREE; request.req_args.free.thread_id = thread_id; - TEMP_FAILURE_RETRY(write_not_cancel(__pthread_manager_request, - (char *) &request, sizeof(request))); + TEMP_FAILURE_RETRY(write(__pthread_manager_request, + (char *) &request, sizeof(request))); } return 0; } |