diff options
author | Eric Andersen <andersen@codepoet.org> | 2003-02-27 18:13:05 +0000 |
---|---|---|
committer | Eric Andersen <andersen@codepoet.org> | 2003-02-27 18:13:05 +0000 |
commit | 187dd78d7bd1c03fcf16e54a30314512d38e1a4a (patch) | |
tree | 9780638e5286b40da74a128c9f540a9ea720862f /libpthread/linuxthreads | |
parent | d4d6e2c50565da18253cd0d6f3332484142b6587 (diff) |
Major update for pthreads, based in large part on improvements
from glibc 2.3. This should make threads much more efficient.
-Erik
Diffstat (limited to 'libpthread/linuxthreads')
38 files changed, 3041 insertions, 754 deletions
diff --git a/libpthread/linuxthreads/condvar.c b/libpthread/linuxthreads/condvar.c index 8bc114e3c..f9c46a331 100644 --- a/libpthread/linuxthreads/condvar.c +++ b/libpthread/linuxthreads/condvar.c @@ -25,22 +25,6 @@ #include "queue.h" #include "restart.h" -static int pthread_cond_timedwait_relative_old(pthread_cond_t *, - pthread_mutex_t *, const struct timespec *); - -static int pthread_cond_timedwait_relative_new(pthread_cond_t *, - pthread_mutex_t *, const struct timespec *); - -static int (*pthread_cond_tw_rel)(pthread_cond_t *, pthread_mutex_t *, - const struct timespec *) = pthread_cond_timedwait_relative_old; - -/* initialize this module */ -void __pthread_init_condvar(int rt_sig_available) -{ - if (rt_sig_available) - pthread_cond_tw_rel = pthread_cond_timedwait_relative_new; -} - int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *cond_attr) { @@ -76,12 +60,20 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) volatile pthread_descr self = thread_self(); pthread_extricate_if extr; int already_canceled = 0; + int spurious_wakeup_count; + + /* Check whether the mutex is locked and owned by this thread. */ + if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP + && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP + && mutex->__m_owner != self) + return EINVAL; /* Set up extrication interface */ extr.pu_object = cond; extr.pu_extricate_func = cond_extricate_func; /* Register extrication interface */ + THREAD_SETMEM(self, p_condvar_avail, 0); __pthread_set_own_extricate_if(self, &extr); /* Atomically enqueue thread for waiting, but only if it is not @@ -106,7 +98,21 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) pthread_mutex_unlock(mutex); - suspend(self); + spurious_wakeup_count = 0; + while (1) + { + suspend(self); + if (THREAD_GETMEM(self, p_condvar_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; + } + __pthread_set_own_extricate_if(self, 0); /* Check for cancellation again, to provide correct cancellation @@ -119,31 +125,36 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) pthread_exit(PTHREAD_CANCELED); } + /* Put back any resumes we caught that don't belong to us. */ + while (spurious_wakeup_count--) + restart(self); + pthread_mutex_lock(mutex); return 0; } -/* The following function is used on kernels that don't have rt signals. - SIGUSR1 is used as the restart signal. The different code is needed - because that ordinary signal does not queue. */ - static int -pthread_cond_timedwait_relative_old(pthread_cond_t *cond, +pthread_cond_timedwait_relative(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec * abstime) { volatile pthread_descr self = thread_self(); - sigset_t unblock, initial_mask; int already_canceled = 0; - int was_signalled = 0; - sigjmp_buf jmpbuf; pthread_extricate_if extr; + int spurious_wakeup_count; + + /* Check whether the mutex is locked and owned by this thread. */ + if (mutex->__m_kind != PTHREAD_MUTEX_TIMED_NP + && mutex->__m_kind != PTHREAD_MUTEX_ADAPTIVE_NP + && mutex->__m_owner != self) + return EINVAL; /* Set up extrication interface */ extr.pu_object = cond; extr.pu_extricate_func = cond_extricate_func; /* Register extrication interface */ + THREAD_SETMEM(self, p_condvar_avail, 0); __pthread_set_own_extricate_if(self, &extr); /* Enqueue to wait on the condition and check for cancellation. */ @@ -162,202 +173,40 @@ pthread_cond_timedwait_relative_old(pthread_cond_t *cond, pthread_mutex_unlock(mutex); - if (atomic_decrement(&self->p_resume_count) == 0) { - /* Set up a longjmp handler for the restart signal, unblock - the signal and sleep. */ - - if (sigsetjmp(jmpbuf, 1) == 0) { - THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); - THREAD_SETMEM(self, p_signal, 0); - /* Unblock the restart signal */ - sigemptyset(&unblock); - sigaddset(&unblock, __pthread_sig_restart); - sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); - - while (1) { - struct timeval now; - struct timespec reltime; - - /* Compute a time offset relative to now. */ - gettimeofday (&now, NULL); - reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; - reltime.tv_sec = abstime->tv_sec - now.tv_sec; - if (reltime.tv_nsec < 0) { - reltime.tv_nsec += 1000000000; - reltime.tv_sec -= 1; - } - - /* Sleep for the required duration. If woken by a signal, resume waiting - as required by Single Unix Specification. */ - if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) - break; - } - - /* Block the restart signal again */ - sigprocmask(SIG_SETMASK, &initial_mask, NULL); - was_signalled = 0; - } else { - was_signalled = 1; - } - THREAD_SETMEM(self, p_signal_jmp, NULL); - } - - /* Now was_signalled is true if we exited the above code - due to the delivery of a restart signal. In that case, - we know we have been dequeued and resumed and that the - resume count is balanced. Otherwise, there are some - cases to consider. First, try to bump up the resume count - back to zero. If it goes to 1, it means restart() was - invoked on this thread. The signal must be consumed - and the count bumped down and everything is cool. - Otherwise, no restart was delivered yet, so we remove - the thread from the queue. If this succeeds, it's a clear - case of timeout. If we fail to remove from the queue, then we - must wait for a restart. */ - - if (!was_signalled) { - if (atomic_increment(&self->p_resume_count) != -1) { - __pthread_wait_for_restart_signal(self); - atomic_decrement(&self->p_resume_count); /* should be zero now! */ - } else { - int was_on_queue; - __pthread_lock(&cond->__c_lock, self); - was_on_queue = remove_from_queue(&cond->__c_waiting, self); - __pthread_unlock(&cond->__c_lock); - - if (was_on_queue) { - __pthread_set_own_extricate_if(self, 0); - pthread_mutex_lock(mutex); - return ETIMEDOUT; - } - - suspend(self); - } - } - - __pthread_set_own_extricate_if(self, 0); - - /* The remaining logic is the same as in other cancellable waits, - such as pthread_join sem_wait or pthread_cond wait. */ - - if (THREAD_GETMEM(self, p_woken_by_cancel) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE) { - THREAD_SETMEM(self, p_woken_by_cancel, 0); - pthread_mutex_lock(mutex); - pthread_exit(PTHREAD_CANCELED); - } - - pthread_mutex_lock(mutex); - return 0; -} - -/* The following function is used on new (late 2.1 and 2.2 and higher) kernels - that have rt signals which queue. */ - -static int -pthread_cond_timedwait_relative_new(pthread_cond_t *cond, - pthread_mutex_t *mutex, - const struct timespec * abstime) -{ - volatile pthread_descr self = thread_self(); - sigset_t unblock, initial_mask; - int already_canceled = 0; - int was_signalled = 0; - sigjmp_buf jmpbuf; - pthread_extricate_if extr; - - /* Set up extrication interface */ - extr.pu_object = cond; - extr.pu_extricate_func = cond_extricate_func; - - /* Register extrication interface */ - __pthread_set_own_extricate_if(self, &extr); - - /* Enqueue to wait on the condition and check for cancellation. */ - __pthread_lock(&cond->__c_lock, self); - if (!(THREAD_GETMEM(self, p_canceled) - && THREAD_GETMEM(self, p_cancelstate) == PTHREAD_CANCEL_ENABLE)) - enqueue(&cond->__c_waiting, self); - else - already_canceled = 1; - __pthread_unlock(&cond->__c_lock); + spurious_wakeup_count = 0; + while (1) + { + if (!timedsuspend(self, abstime)) { + int was_on_queue; - if (already_canceled) { - __pthread_set_own_extricate_if(self, 0); - pthread_exit(PTHREAD_CANCELED); - } + /* __pthread_lock will queue back any spurious restarts that + may happen to it. */ - pthread_mutex_unlock(mutex); + __pthread_lock(&cond->__c_lock, self); + was_on_queue = remove_from_queue(&cond->__c_waiting, self); + __pthread_unlock(&cond->__c_lock); - /* Set up a longjmp handler for the restart signal, unblock - the signal and sleep. */ - - if (sigsetjmp(jmpbuf, 1) == 0) { - THREAD_SETMEM(self, p_signal_jmp, &jmpbuf); - THREAD_SETMEM(self, p_signal, 0); - /* Unblock the restart signal */ - sigemptyset(&unblock); - sigaddset(&unblock, __pthread_sig_restart); - sigprocmask(SIG_UNBLOCK, &unblock, &initial_mask); - - while (1) { - struct timeval now; - struct timespec reltime; - - /* Compute a time offset relative to now. */ - gettimeofday (&now, NULL); - reltime.tv_nsec = abstime->tv_nsec - now.tv_usec * 1000; - reltime.tv_sec = abstime->tv_sec - now.tv_sec; - if (reltime.tv_nsec < 0) { - reltime.tv_nsec += 1000000000; - reltime.tv_sec -= 1; + if (was_on_queue) { + __pthread_set_own_extricate_if(self, 0); + pthread_mutex_lock(mutex); + return ETIMEDOUT; } - /* Sleep for the required duration. If woken by a signal, - resume waiting as required by Single Unix Specification. */ - if (reltime.tv_sec < 0 || __libc_nanosleep(&reltime, NULL) == 0) - break; + /* Eat the outstanding restart() from the signaller */ + suspend(self); } - /* Block the restart signal again */ - sigprocmask(SIG_SETMASK, &initial_mask, NULL); - was_signalled = 0; - } else { - was_signalled = 1; - } - THREAD_SETMEM(self, p_signal_jmp, NULL); - - /* Now was_signalled is true if we exited the above code - due to the delivery of a restart signal. In that case, - everything is cool. We have been removed from the queue - by the other thread, and consumed its signal. - - Otherwise we this thread woke up spontaneously, or due to a signal other - than restart. The next thing to do is to try to remove the thread - from the queue. This may fail due to a race against another thread - trying to do the same. In the failed case, we know we were signalled, - and we may also have to consume a restart signal. */ - - if (!was_signalled) { - int was_on_queue; - - /* __pthread_lock will queue back any spurious restarts that - may happen to it. */ - - __pthread_lock(&cond->__c_lock, self); - was_on_queue = remove_from_queue(&cond->__c_waiting, self); - __pthread_unlock(&cond->__c_lock); - - if (was_on_queue) { - __pthread_set_own_extricate_if(self, 0); - pthread_mutex_lock(mutex); - return ETIMEDOUT; + if (THREAD_GETMEM(self, p_condvar_avail) == 0 + && (THREAD_GETMEM(self, p_woken_by_cancel) == 0 + || THREAD_GETMEM(self, p_cancelstate) != PTHREAD_CANCEL_ENABLE)) + { + /* Count resumes that don't belong to us. */ + spurious_wakeup_count++; + continue; + } + break; } - /* Eat the outstanding restart() from the signaller */ - suspend(self); - } - __pthread_set_own_extricate_if(self, 0); /* The remaining logic is the same as in other cancellable waits, @@ -370,6 +219,10 @@ pthread_cond_timedwait_relative_new(pthread_cond_t *cond, pthread_exit(PTHREAD_CANCELED); } + /* Put back any resumes we caught that don't belong to us. */ + while (spurious_wakeup_count--) + restart(self); + pthread_mutex_lock(mutex); return 0; } @@ -378,7 +231,7 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec * abstime) { /* Indirect call through pointer! */ - return pthread_cond_tw_rel(cond, mutex, abstime); + return pthread_cond_timedwait_relative(cond, mutex, abstime); } int pthread_cond_signal(pthread_cond_t *cond) @@ -388,7 +241,11 @@ int pthread_cond_signal(pthread_cond_t *cond) __pthread_lock(&cond->__c_lock, NULL); th = dequeue(&cond->__c_waiting); __pthread_unlock(&cond->__c_lock); - if (th != NULL) restart(th); + if (th != NULL) { + th->p_condvar_avail = 1; + WRITE_MEMORY_BARRIER(); + restart(th); + } return 0; } @@ -402,7 +259,11 @@ int pthread_cond_broadcast(pthread_cond_t *cond) cond->__c_waiting = NULL; __pthread_unlock(&cond->__c_lock); /* Now signal each process in the queue */ - while ((th = dequeue(&tosignal)) != NULL) restart(th); + while ((th = dequeue(&tosignal)) != NULL) { + th->p_condvar_avail = 1; + WRITE_MEMORY_BARRIER(); + restart(th); + } return 0; } @@ -418,19 +279,18 @@ int pthread_condattr_destroy(pthread_condattr_t *attr) int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared) { - *pshared = PTHREAD_PROCESS_PRIVATE; - return 0; + *pshared = PTHREAD_PROCESS_PRIVATE; + return 0; } int pthread_condattr_setpshared (pthread_condattr_t *attr, int pshared) { - if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) - return EINVAL; + if (pshared != PTHREAD_PROCESS_PRIVATE && pshared != PTHREAD_PROCESS_SHARED) + return EINVAL; - /* For now it is not possible to share a conditional variable. */ - if (pshared != PTHREAD_PROCESS_PRIVATE) - return ENOSYS; + /* For now it is not possible to shared a conditional variable. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return ENOSYS; - return 0; + return 0; } - diff --git a/libpthread/linuxthreads/internals.h b/libpthread/linuxthreads/internals.h index ffa52aff3..45439f363 100644 --- a/libpthread/linuxthreads/internals.h +++ b/libpthread/linuxthreads/internals.h @@ -29,6 +29,9 @@ #include "semaphore.h" #include "../linuxthreads_db/thread_dbP.h" +/* Pretend to be glibc 2.3 as far as gdb is concerned */ +#define VERSION "2.3" + #ifndef THREAD_GETMEM # define THREAD_GETMEM(descr, member) descr->member #endif @@ -159,6 +162,8 @@ struct _pthread_descr_struct { struct pthread_atomic p_resume_count; /* number of times restart() was called on thread */ char p_woken_by_cancel; /* cancellation performed wakeup */ + char p_condvar_avail; /* flag if conditional variable became avail */ + char p_sem_avail; /* flag if semaphore became available */ pthread_extricate_if *p_extricate; /* See above */ pthread_readlock_info *p_readlock_list; /* List of readlock info structs */ pthread_readlock_info *p_readlock_free; /* Free list of structs */ @@ -186,7 +191,7 @@ struct pthread_request { pthread_descr req_thread; /* Thread doing the request */ enum { /* Request kind */ REQ_CREATE, REQ_FREE, REQ_PROCESS_EXIT, REQ_MAIN_THREAD_EXIT, - REQ_POST, REQ_DEBUG + REQ_POST, REQ_DEBUG, REQ_KICK } req_kind; union { /* Arguments for request */ struct { /* For REQ_CREATE: */ @@ -337,6 +342,21 @@ static inline int invalid_handle(pthread_handle h, pthread_t id) #define CURRENT_STACK_FRAME ({ char __csf; &__csf; }) #endif +/* If MEMORY_BARRIER isn't defined in pt-machine.h, assume the + architecture doesn't need a memory barrier instruction (e.g. Intel + x86). Still we need the compiler to respect the barrier and emit + all outstanding operations which modify memory. Some architectures + distinguish between full, read and write barriers. */ +#ifndef MEMORY_BARRIER +#define MEMORY_BARRIER() asm ("" : : : "memory") +#endif +#ifndef READ_MEMORY_BARRIER +#define READ_MEMORY_BARRIER() MEMORY_BARRIER() +#endif +#ifndef WRITE_MEMORY_BARRIER +#define WRITE_MEMORY_BARRIER() MEMORY_BARRIER() +#endif + /* Recover thread descriptor for the current thread */ extern pthread_descr __pthread_find_self (void) __attribute__ ((const)); @@ -425,7 +445,6 @@ void __pthread_manager_sighandler(int sig); void __pthread_reset_main_thread(void); void __fresetlockfiles(void); void __pthread_manager_adjust_prio(int thread_prio); -void __pthread_set_own_extricate_if(pthread_descr self, pthread_extricate_if *peif); void __pthread_initialize_minimal (void); extern int __pthread_attr_setguardsize __P ((pthread_attr_t *__attr, @@ -446,15 +465,15 @@ extern int __pthread_mutexattr_gettype __P ((__const pthread_mutexattr_t *__attr int *__kind)); extern void __pthread_kill_other_threads_np __P ((void)); -void __pthread_restart_old(pthread_descr th); -void __pthread_suspend_old(pthread_descr self); - -void __pthread_restart_new(pthread_descr th); -void __pthread_suspend_new(pthread_descr self); +extern void __pthread_restart_old(pthread_descr th); +extern void __pthread_suspend_old(pthread_descr self); +extern int __pthread_timedsuspend_old(pthread_descr self, const struct timespec *abs); -void __pthread_wait_for_restart_signal(pthread_descr self); +extern void __pthread_restart_new(pthread_descr th); +extern void __pthread_suspend_new(pthread_descr self); +extern int __pthread_timedsuspend_new(pthread_descr self, const struct timespec *abs); -void __pthread_init_condvar(int rt_sig_available); +extern void __pthread_wait_for_restart_signal(pthread_descr self); /* Global pointers to old or new suspend functions */ diff --git a/libpthread/linuxthreads/join.c b/libpthread/linuxthreads/join.c index ccb11b124..cc2dc4ddc 100644 --- a/libpthread/linuxthreads/join.c +++ b/libpthread/linuxthreads/join.c @@ -14,9 +14,12 @@ /* Thread termination and joining */ +#include <features.h> +#define __USE_GNU #include <errno.h> #include <sched.h> #include <unistd.h> +#include <stdlib.h> #include "pthread.h" #include "internals.h" #include "spinlock.h" @@ -74,8 +77,13 @@ PDEBUG("joining = %p, pid=%d\n", joining, joining->p_pid); if (self == __pthread_main_thread && __pthread_manager_request >= 0) { request.req_thread = self; request.req_kind = REQ_MAIN_THREAD_EXIT; - __libc_write(__pthread_manager_request, (char *)&request, sizeof(request)); + 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). */ @@ -168,8 +176,8 @@ PDEBUG("after suspend\n"); request.req_thread = self; request.req_kind = REQ_FREE; request.req_args.free.thread_id = thread_id; - __libc_write(__pthread_manager_request, - (char *) &request, sizeof(request)); + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); } return 0; } @@ -206,8 +214,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; - __libc_write(__pthread_manager_request, - (char *) &request, sizeof(request)); + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); } return 0; } diff --git a/libpthread/linuxthreads/manager.c b/libpthread/linuxthreads/manager.c index 1b513ca92..f1c9b93af 100644 --- a/libpthread/linuxthreads/manager.c +++ b/libpthread/linuxthreads/manager.c @@ -18,6 +18,8 @@ #define __getpid getpid #define __getpagesize getpagesize +#include <features.h> +#define __USE_GNU #include <errno.h> #include <sched.h> #include <stddef.h> @@ -50,8 +52,8 @@ /* Array of active threads. Entry 0 is reserved for the initial thread. */ struct pthread_handle_struct __pthread_handles[PTHREAD_THREADS_MAX] = -{ { LOCK_INITIALIZER, &__pthread_initial_thread, 0}, - { LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ }; +{ { __LOCK_INITIALIZER, &__pthread_initial_thread, 0}, + { __LOCK_INITIALIZER, &__pthread_manager_thread, 0}, /* All NULLs */ }; /* For debugging purposes put the maximum number of threads in a variable. */ const int __linuxthreads_pthread_threads_max = PTHREAD_THREADS_MAX; @@ -120,7 +122,7 @@ int __pthread_manager(void *arg) #else struct pollfd ufd; #endif - sigset_t mask; + sigset_t manager_mask; int n; struct pthread_request request; @@ -131,15 +133,19 @@ int __pthread_manager(void *arg) /* Set the error variable. */ __pthread_manager_thread.p_errnop = &__pthread_manager_thread.p_errno; __pthread_manager_thread.p_h_errnop = &__pthread_manager_thread.p_h_errno; + /* Block all signals except __pthread_sig_cancel and SIGTRAP */ - sigfillset(&mask); - sigdelset(&mask, __pthread_sig_cancel); /* for thread termination */ - sigdelset(&mask, SIGTRAP); /* for debugging purposes */ - sigprocmask(SIG_SETMASK, &mask, NULL); + sigfillset(&manager_mask); + sigdelset(&manager_mask, __pthread_sig_cancel); /* for thread termination */ + sigdelset(&manager_mask, SIGTRAP); /* for debugging purposes */ + if (__pthread_threads_debug && __pthread_sig_debug > 0) + sigdelset(&manager_mask, __pthread_sig_debug); + sigprocmask(SIG_SETMASK, &manager_mask, NULL); /* Raise our priority to match that of main thread */ __pthread_manager_adjust_prio(__pthread_main_thread->p_priority); /* Synchronize debugging of the thread manager */ - n = __libc_read(reqfd, (char *)&request, sizeof(request)); + n = TEMP_FAILURE_RETRY(__libc_read(reqfd, (char *)&request, + sizeof(request))); ASSERT(n == sizeof(request) && request.req_kind == REQ_DEBUG); #ifndef USE_SELECT ufd.fd = reqfd; @@ -201,17 +207,25 @@ PDEBUG("got REQ_FREE\n"); break; case REQ_PROCESS_EXIT: PDEBUG("got REQ_PROCESS_EXIT from %d, exit code = %d\n", - request.req_thread, request.req_args.exit.code); + request.req_thread, request.req_args.exit.code); pthread_handle_exit(request.req_thread, request.req_args.exit.code); break; case REQ_MAIN_THREAD_EXIT: PDEBUG("got REQ_MAIN_THREAD_EXIT\n"); main_thread_exiting = 1; + /* Reap children in case all other threads died and the signal handler + went off before we set main_thread_exiting to 1, and therefore did + not do REQ_KICK. */ + pthread_reap_children(); + if (__pthread_main_thread->p_nextlive == __pthread_main_thread) { restart(__pthread_main_thread); - return 0; - } + /* The main thread will now call exit() which will trigger an + __on_exit handler, which in turn will send REQ_PROCESS_EXIT + to the thread manager. In case you are wondering how the + manager terminates from its loop here. */ + } break; case REQ_POST: PDEBUG("got REQ_POST\n"); @@ -221,10 +235,14 @@ PDEBUG("got REQ_POST\n"); PDEBUG("got REQ_DEBUG\n"); /* Make gdb aware of new thread and gdb will restart the new thread when it is ready to handle the new thread. */ - if (__pthread_threads_debug && __pthread_sig_debug > 0) + if (__pthread_threads_debug && __pthread_sig_debug > 0) { PDEBUG("about to call raise(__pthread_sig_debug)\n"); raise(__pthread_sig_debug); - break; + } + case REQ_KICK: + /* This is just a prod to get the manager to reap some + threads right away, avoiding a potential delay at shutdown. */ + break; } } } @@ -246,8 +264,9 @@ int __pthread_manager_event(void *arg) } /* Process creation */ - -static int pthread_start_thread(void *arg) +static int +__attribute__ ((noreturn)) +pthread_start_thread(void *arg) { pthread_descr self = (pthread_descr) arg; struct pthread_request request; @@ -282,8 +301,8 @@ PDEBUG("\n"); if (__pthread_threads_debug && __pthread_sig_debug > 0) { request.req_thread = self; request.req_kind = REQ_DEBUG; - __libc_write(__pthread_manager_request, - (char *) &request, sizeof(request)); + TEMP_FAILURE_RETRY(__libc_write(__pthread_manager_request, + (char *) &request, sizeof(request))); suspend(self); } /* Run the thread code */ @@ -291,10 +310,11 @@ PDEBUG("\n"); p_start_args.arg)); /* Exit with the given return value */ pthread_exit(outcome); - return 0; } -static int pthread_start_thread_event(void *arg) +static int +__attribute__ ((noreturn)) +pthread_start_thread_event(void *arg) { pthread_descr self = (pthread_descr) arg; @@ -310,7 +330,7 @@ static int pthread_start_thread_event(void *arg) __pthread_unlock (THREAD_GETMEM(self, p_lock)); /* Continue with the real function. */ - return pthread_start_thread (arg); + pthread_start_thread (arg); } static int pthread_allocate_stack(const pthread_attr_t *attr, |