summaryrefslogtreecommitdiff
path: root/libpthread/linuxthreads
diff options
context:
space:
mode:
authorEric Andersen <andersen@codepoet.org>2003-02-27 18:13:05 +0000
committerEric Andersen <andersen@codepoet.org>2003-02-27 18:13:05 +0000
commit187dd78d7bd1c03fcf16e54a30314512d38e1a4a (patch)
tree9780638e5286b40da74a128c9f540a9ea720862f /libpthread/linuxthreads
parentd4d6e2c50565da18253cd0d6f3332484142b6587 (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')
-rw-r--r--libpthread/linuxthreads/condvar.c308
-rw-r--r--libpthread/linuxthreads/internals.h37
-rw-r--r--libpthread/linuxthreads/join.c18
-rw-r--r--libpthread/linuxthreads/manager.c100
-rw-r--r--libpthread/linuxthreads/mutex.c216
-rw-r--r--libpthread/linuxthreads/pthread.c416
-rw-r--r--libpthread/linuxthreads/restart.h26
-rw-r--r--libpthread/linuxthreads/semaphore.c159
-rw-r--r--libpthread/linuxthreads/semaphore.h36
-rw-r--r--libpthread/linuxthreads/signals.c3
-rw-r--r--libpthread/linuxthreads/spinlock.c616
-rw-r--r--libpthread/linuxthreads/spinlock.h132
-rw-r--r--libpthread/linuxthreads/sysdeps/alpha/pt-machine.h45
-rw-r--r--libpthread/linuxthreads/sysdeps/alpha/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/arm/pt-machine.h19
-rw-r--r--libpthread/linuxthreads/sysdeps/arm/sigcontextinfo.h75
-rw-r--r--libpthread/linuxthreads/sysdeps/arm/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/cris/pt-machine.h20
-rw-r--r--libpthread/linuxthreads/sysdeps/cris/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/i686/pt-machine.h38
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/pt-machine.h27
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/sigcontextinfo.h45
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/tls.h183
-rw-r--r--libpthread/linuxthreads/sysdeps/i386/useldt.h213
-rw-r--r--libpthread/linuxthreads/sysdeps/m68k/pt-machine.h27
-rw-r--r--libpthread/linuxthreads/sysdeps/m68k/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/mips/pt-machine.h111
-rw-r--r--libpthread/linuxthreads/sysdeps/mips/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/powerpc/pt-machine.h82
-rw-r--r--libpthread/linuxthreads/sysdeps/powerpc/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/libc-lock.h327
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/bits/libc-tsd.h35
-rw-r--r--libpthread/linuxthreads/sysdeps/pthread/tls.h81
-rw-r--r--libpthread/linuxthreads/sysdeps/sh/pt-machine.h33
-rw-r--r--libpthread/linuxthreads/sysdeps/sh/stackinfo.h28
-rw-r--r--libpthread/linuxthreads/sysdeps/sh/tls.h115
-rw-r--r--libpthread/linuxthreads/sysdeps/sparc/stackinfo.h28
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,