diff options
author | Ulrich Drepper <drepper@redhat.com> | 2000-01-05 02:09:12 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2000-01-05 02:09:12 +0000 |
commit | 1d2fc9b3c59d0e83e04139ddf633731264b76ea2 (patch) | |
tree | c738cf2a40851dc25be2c252ba5dbb7f335b5e14 /linuxthreads/pthread.c | |
parent | f19f2b34439145daf300bf12789bbc61c8d4db28 (diff) | |
download | glibc-1d2fc9b3c59d0e83e04139ddf633731264b76ea2.tar glibc-1d2fc9b3c59d0e83e04139ddf633731264b76ea2.tar.gz glibc-1d2fc9b3c59d0e83e04139ddf633731264b76ea2.tar.bz2 glibc-1d2fc9b3c59d0e83e04139ddf633731264b76ea2.zip |
Redesigned how cancellation unblocks a thread from internal cancellation points (sem_wait, pthread_join, pthread_cond_{wait,timedwait}). Cancellation won't eat a signal in any of these functions (*required* by POSIX and Single Unix Spec!).
2000-01-03 Kaz Kylheku <kaz@ashi.footprints.net>
Redesigned how cancellation unblocks a thread from internal
cancellation points (sem_wait, pthread_join,
pthread_cond_{wait,timedwait}).
Cancellation won't eat a signal in any of these functions
(*required* by POSIX and Single Unix Spec!).
* condvar.c: spontaneous wakeup on pthread_cond_timedwait won't eat a
simultaneous condition variable signal (not required by POSIX
or Single Unix Spec, but nice).
* spinlock.c: __pthread_lock queues back any received restarts
that don't belong to it instead of assuming ownership of lock
upon any restart; fastlock can no longer be acquired by two threads
simultaneously.
* restart.h: restarts queue even on kernels that don't have
queued real time signals (2.0, early 2.1), thanks to atomic counter,
avoiding a rare race condition in pthread_cond_timedwait.
Diffstat (limited to 'linuxthreads/pthread.c')
-rw-r--r-- | linuxthreads/pthread.c | 66 |
1 files changed, 65 insertions, 1 deletions
diff --git a/linuxthreads/pthread.c b/linuxthreads/pthread.c index dfde08f432..f082e95478 100644 --- a/linuxthreads/pthread.c +++ b/linuxthreads/pthread.c @@ -43,6 +43,7 @@ struct _pthread_descr_struct __pthread_initial_thread = { 0, /* int p_priority */ &__pthread_handles[0].h_lock, /* struct _pthread_fastlock * p_lock */ 0, /* int p_signal */ + ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */ NULL, /* sigjmp_buf * p_signal_buf */ NULL, /* sigjmp_buf * p_cancel_buf */ 0, /* char p_terminated */ @@ -55,6 +56,8 @@ struct _pthread_descr_struct __pthread_initial_thread = { 0, /* char p_cancelstate */ 0, /* char p_canceltype */ 0, /* char p_canceled */ + 0, /* char p_woken_by_cancel */ + NULL, /* struct pthread_extricate_if *p_extricate */ NULL, /* int *p_errnop */ 0, /* int p_errno */ NULL, /* int *p_h_errnop */ @@ -86,6 +89,7 @@ struct _pthread_descr_struct __pthread_manager_thread = { 0, /* int p_priority */ &__pthread_handles[1].h_lock, /* struct _pthread_fastlock * p_lock */ 0, /* int p_signal */ + ATOMIC_INITIALIZER, /* struct pthread_atomic p_resume_count */ NULL, /* sigjmp_buf * p_signal_buf */ NULL, /* sigjmp_buf * p_cancel_buf */ 0, /* char p_terminated */ @@ -98,6 +102,8 @@ struct _pthread_descr_struct __pthread_manager_thread = { 0, /* char p_cancelstate */ 0, /* char p_canceltype */ 0, /* char p_canceled */ + 0, /* char p_woken_by_cancel */ + NULL, /* struct pthread_extricate_if *p_extricate */ &__pthread_manager_thread.p_errno, /* int *p_errnop */ 0, /* int p_errno */ NULL, /* int *p_h_errnop */ @@ -144,6 +150,12 @@ char *__pthread_manager_thread_tos = NULL; int __pthread_exit_requested = 0; int __pthread_exit_code = 0; +/* Pointers that select new or old suspend/resume functions + based on availability of rt signals. */ + +void (*__pthread_restart)(pthread_descr) = __pthread_restart_old; +void (*__pthread_suspend)(pthread_descr) = __pthread_suspend_old; + /* Communicate relevant LinuxThreads constants to gdb */ const int __pthread_threads_max = PTHREAD_THREADS_MAX; @@ -215,13 +227,18 @@ init_rtsigs (void) __pthread_sig_cancel = SIGUSR2; __pthread_sig_debug = 0; #endif + __pthread_init_condvar(0); } else { #if __SIGRTMAX - __SIGRTMIN >= 3 current_rtmin = __SIGRTMIN + 3; + __pthread_restart = __pthread_restart_new; + __pthread_suspend = __pthread_wait_for_restart_signal; + __pthread_init_condvar(1); #else current_rtmin = __SIGRTMIN; + __pthread_init_condvar(0); #endif current_rtmax = __SIGRTMAX; @@ -447,7 +464,7 @@ int __pthread_initialize_manager(void) raise(__pthread_sig_debug); /* We suspend ourself and gdb will wake us up when it is ready to handle us. */ - suspend(thread_self()); + __pthread_wait_for_restart_signal(thread_self()); } /* Synchronize debugging of the thread manager */ request.req_kind = REQ_DEBUG; @@ -770,6 +787,53 @@ int __pthread_getconcurrency(void) } weak_alias (__pthread_getconcurrency, pthread_getconcurrency) +void __pthread_set_own_extricate_if(pthread_descr self, pthread_extricate_if *peif) +{ + __pthread_lock(self->p_lock, self); + THREAD_SETMEM(self, p_extricate, peif); + __pthread_unlock(self->p_lock); +} + +/* Primitives for controlling thread execution */ + +void __pthread_wait_for_restart_signal(pthread_descr self) +{ + sigset_t mask; + + sigprocmask(SIG_SETMASK, NULL, &mask); /* Get current signal mask */ + sigdelset(&mask, __pthread_sig_restart); /* Unblock the restart signal */ + do { + self->p_signal = 0; + sigsuspend(&mask); /* Wait for signal */ + } while (self->p_signal !=__pthread_sig_restart ); +} + +/* The _old variants are for 2.0 and early 2.1 kernels which don't have RT signals. + On these kernels, we use SIGUSR1 and SIGUSR2 for restart and cancellation. + Since the restart signal does not queue, we use an atomic counter to create + queuing semantics. This is needed to resolve a rare race condition in + pthread_cond_timedwait_relative. */ + +void __pthread_restart_old(pthread_descr th) +{ + if (atomic_increment(&th->p_resume_count) == -1) + kill(th->p_pid, __pthread_sig_restart); +} + +void __pthread_suspend_old(pthread_descr self) +{ + if (atomic_decrement(&self->p_resume_count) <= 0) + __pthread_wait_for_restart_signal(self); +} + +void __pthread_restart_new(pthread_descr th) +{ + kill(th->p_pid, __pthread_sig_restart); +} + +/* There is no __pthread_suspend_new because it would just + be a wasteful wrapper for __pthread_wait_for_restart_signal */ + /* Debugging aid */ #ifdef DEBUG |