Fix barriers so that ptread_barrier_destroy is consistent
authorDavid Bartley <dtbartle@csclub.uwaterloo.ca>
Sun, 17 Aug 2008 10:52:30 +0000 (06:52 -0400)
committerDavid Bartley <dtbartle@csclub.uwaterloo.ca>
Sun, 17 Aug 2008 10:58:01 +0000 (06:58 -0400)
nptl/sysdeps/unix/sysv/solaris2/opensolaris-gnu/pthread_barrier_destroy.c
nptl/sysdeps/unix/sysv/solaris2/opensolaris-gnu/pthread_barrier_wait.c

index acf7cf4..e1c1527 100644 (file)
@@ -30,8 +30,18 @@ pthread_barrier_destroy (barrier)
 {
   struct pthread_barrier *ibarrier = (struct pthread_barrier *) barrier;
 
+  int errval = pthread_mutex_lock (&ibarrier->mutex);
+  if (errval != 0)
+    return EINVAL;
+
+  /* Make sure barrier is not exiting.  */
+  while (ibarrier->flag & BARRIER_EXITING)
+    errval = __cond_reltimedwait_internal ((cond_t *)&ibarrier->cond,
+        (mutex_t *)&ibarrier->mutex, NULL, 0);
+
   if (__builtin_expect (ibarrier->left != ibarrier->init_count, 0))
-    return EBUSY;
+    errval = EBUSY;
 
-  return 0;
+  (void)pthread_mutex_unlock (&ibarrier->mutex);
+  return errval;
 }
index 568df52..3561c2b 100644 (file)
@@ -36,6 +36,11 @@ pthread_barrier_wait (barrier)
   if (errval != 0)
     return errval;
 
+  /* Make sure barrier is not exiting.  */
+  while (ibarrier->flag & BARRIER_EXITING)
+    errval = __cond_reltimedwait_internal ((cond_t *)&ibarrier->cond,
+        (mutex_t *)&ibarrier->mutex, NULL, 0);
+
   /* A thread entered the barrier.  */
   --ibarrier->left;
 
@@ -44,30 +49,30 @@ pthread_barrier_wait (barrier)
       /* Increment the event counter to avoid invalid wake-ups and tell the
          current waiters that it is their turn. Also reset the barrier.  */
       ++ibarrier->curr_event;
-      ibarrier->left = ibarrier->init_count;
-
-      /* Wake other threads.  */
-      errval = pthread_cond_broadcast (&ibarrier->cond);
-      if (errval != 0)
-        return errval;
 
-      errval = pthread_mutex_unlock (&ibarrier->mutex);
-      if (errval != 0)
-        return errval;
+      ibarrier->flag |= BARRIER_EXITING;
 
-      return PTHREAD_BARRIER_SERIAL_THREAD;
+      /* Wake other threads.  */
+      (void)pthread_cond_broadcast (&ibarrier->cond);
+      errval = PTHREAD_BARRIER_SERIAL_THREAD;
+    }
+  else
+    {
+      /* Wait until the current barrier event is done.  */
+      int curr_event = ibarrier->curr_event;
+      do {
+          errval = __cond_reltimedwait_internal ((cond_t *)&ibarrier->cond,
+              (mutex_t *)&ibarrier->mutex, NULL, 0);
+      } while (errval == 0 && curr_event == ibarrier->curr_event);
     }
 
-  /* Wait until the current barrier event is done.  */
-  int curr_event = ibarrier->curr_event;
-  do
+  /* If we are the last thread notify barrier waiters.  */
+  if (++ibarrier->left == ibarrier->init_count)
     {
-      errval = __cond_reltimedwait_internal ((cond_t *)&ibarrier->cond,
-          (mutex_t *)&ibarrier->mutex, NULL, 0);
-      if (errval != 0)
-        return errval;
+      ibarrier->flag &= ~BARRIER_EXITING;
+      (void)pthread_cond_broadcast (&ibarrier->cond);
     }
-  while (curr_event == ibarrier->curr_event);
 
-  return pthread_mutex_unlock (&ibarrier->mutex);
+  (void)pthread_mutex_unlock (&ibarrier->mutex);
+  return errval;
 }