(pthread_cond_init, pthread_cond_destroy,
[kopensolaris-gnu/glibc.git] / linuxthreads / condvar.c
index ab107c1..a40ae49 100644 (file)
 #include "queue.h"
 #include "restart.h"
 
-int pthread_cond_init(pthread_cond_t *cond,
-                      const pthread_condattr_t *cond_attr)
+int __pthread_cond_init(pthread_cond_t *cond,
+                        const pthread_condattr_t *cond_attr)
 {
   __pthread_init_lock(&cond->__c_lock);
   cond->__c_waiting = NULL;
   return 0;
 }
+strong_alias (__pthread_cond_init, pthread_cond_init)
 
-int pthread_cond_destroy(pthread_cond_t *cond)
+int __pthread_cond_destroy(pthread_cond_t *cond)
 {
   if (cond->__c_waiting != NULL) return EBUSY;
   return 0;
 }
+strong_alias (__pthread_cond_destroy, pthread_cond_destroy)
 
 /* Function called by pthread_cancel to remove the thread from
    waiting on a condition variable queue. */
@@ -50,19 +52,22 @@ static int cond_extricate_func(void *obj, pthread_descr th)
 
   __pthread_lock(&cond->__c_lock, self);
   did_remove = remove_from_queue(&cond->__c_waiting, th);
-  __pthread_spin_unlock(&cond->__c_lock);
+  __pthread_unlock(&cond->__c_lock);
 
   return did_remove;
 }
 
-int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+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_FAST_NP && mutex->__m_owner != self)
+  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 */
@@ -70,6 +75,7 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
   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
@@ -85,16 +91,30 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
     enqueue(&cond->__c_waiting, self);
   else
     already_canceled = 1;
-  __pthread_spin_unlock(&cond->__c_lock);
+  __pthread_unlock(&cond->__c_lock);
 
   if (already_canceled) {
     __pthread_set_own_extricate_if(self, 0);
-    pthread_exit(PTHREAD_CANCELED);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
   }
 
   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
@@ -104,12 +124,17 @@ int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
       && 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_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
   }
 
+  /* Put back any resumes we caught that don't belong to us. */
+  while (spurious_wakeup_count--)
+    restart(self);
+
   pthread_mutex_lock(mutex);
   return 0;
 }
+strong_alias (__pthread_cond_wait, pthread_cond_wait)
 
 static int
 pthread_cond_timedwait_relative(pthread_cond_t *cond,
@@ -119,9 +144,12 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
   volatile pthread_descr self = thread_self();
   int already_canceled = 0;
   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_FAST_NP && mutex->__m_owner != self)
+  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 */
@@ -129,6 +157,7 @@ pthread_cond_timedwait_relative(pthread_cond_t *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. */
@@ -138,35 +167,49 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
     enqueue(&cond->__c_waiting, self);
   else
     already_canceled = 1;
-  __pthread_spin_unlock(&cond->__c_lock);
+  __pthread_unlock(&cond->__c_lock);
 
   if (already_canceled) {
     __pthread_set_own_extricate_if(self, 0);
-    pthread_exit(PTHREAD_CANCELED);
+    __pthread_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
   }
 
   pthread_mutex_unlock(mutex);
 
-  if (!timedsuspend(self, abstime)) {
-    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_spin_unlock(&cond->__c_lock);
-
-    if (was_on_queue) {
-      __pthread_set_own_extricate_if(self, 0);
-      pthread_mutex_lock(mutex);
-      return ETIMEDOUT;
+  spurious_wakeup_count = 0;
+  while (1)
+    {
+      if (!timedsuspend(self, abstime)) {
+       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;
+       }
+
+       /* Eat the outstanding restart() from the signaller */
+       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;
     }
 
-    /* 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,
@@ -176,9 +219,13 @@ pthread_cond_timedwait_relative(pthread_cond_t *cond,
       && 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_do_exit(PTHREAD_CANCELED, CURRENT_STACK_FRAME);
   }
 
+  /* Put back any resumes we caught that don't belong to us. */
+  while (spurious_wakeup_count--)
+    restart(self);
+
   pthread_mutex_lock(mutex);
   return 0;
 }
@@ -190,18 +237,23 @@ int pthread_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex,
   return pthread_cond_timedwait_relative(cond, mutex, abstime);
 }
 
-int pthread_cond_signal(pthread_cond_t *cond)
+int __pthread_cond_signal(pthread_cond_t *cond)
 {
   pthread_descr th;
 
   __pthread_lock(&cond->__c_lock, NULL);
   th = dequeue(&cond->__c_waiting);
-  __pthread_spin_unlock(&cond->__c_lock);
-  if (th != NULL) restart(th);
+  __pthread_unlock(&cond->__c_lock);
+  if (th != NULL) {
+    th->p_condvar_avail = 1;
+    WRITE_MEMORY_BARRIER();
+    restart(th);
+  }
   return 0;
 }
+strong_alias (__pthread_cond_signal, pthread_cond_signal)
 
-int pthread_cond_broadcast(pthread_cond_t *cond)
+int __pthread_cond_broadcast(pthread_cond_t *cond)
 {
   pthread_descr tosignal, th;
 
@@ -209,18 +261,43 @@ int pthread_cond_broadcast(pthread_cond_t *cond)
   /* Copy the current state of the waiting queue and empty it */
   tosignal = cond->__c_waiting;
   cond->__c_waiting = NULL;
-  __pthread_spin_unlock(&cond->__c_lock);
+  __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;
 }
+strong_alias (__pthread_cond_broadcast, pthread_cond_broadcast)
 
-int pthread_condattr_init(pthread_condattr_t *attr)
+int __pthread_condattr_init(pthread_condattr_t *attr)
 {
   return 0;
 }
+strong_alias (__pthread_condattr_init, pthread_condattr_init)
 
-int pthread_condattr_destroy(pthread_condattr_t *attr)
+int __pthread_condattr_destroy(pthread_condattr_t *attr)
 {
   return 0;
 }
+strong_alias (__pthread_condattr_destroy, pthread_condattr_destroy)
+
+int pthread_condattr_getpshared (const pthread_condattr_t *attr, int *pshared)
+{
+  *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;
+
+  /* For now it is not possible to shared a conditional variable.  */
+  if (pshared != PTHREAD_PROCESS_PRIVATE)
+    return ENOSYS;
+
+  return 0;
+}