about summary refs log tree commit diff
path: root/linuxthreads/pthread.c
diff options
context:
space:
mode:
Diffstat (limited to 'linuxthreads/pthread.c')
-rw-r--r--linuxthreads/pthread.c66
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