Bug fix: sometimes an assert was triggered if pthread_barrier_destroy() was called after the last pthread_barrier_wait() finished and before the post-pthread_barrier_wait() client request finished.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7654 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/drd_barrier.c b/exp-drd/drd_barrier.c
index 05f4fc4..dc7b46d 100644
--- a/exp-drd/drd_barrier.c
+++ b/exp-drd/drd_barrier.c
@@ -52,7 +52,9 @@
 
 // Local functions.
 
-void barrier_cleanup(struct barrier_info* p);
+static void barrier_cleanup(struct barrier_info* p);
+static const char* barrier_get_typename(struct barrier_info* const p);
+static const char* barrier_type_name(const BarrierT bt);
 
 
 // Local variables.
@@ -100,6 +102,7 @@
   tl_assert(p->a1 == barrier);
 
   p->cleanup           = (void(*)(DrdClientobj*))barrier_cleanup;
+  p->barrier_type      = barrier_type;
   p->count             = count;
   p->pre_iteration     = 0;
   p->post_iteration    = 0;
@@ -121,7 +124,7 @@
 
   tl_assert(p);
 
-  if (p->pre_waiters_left != p->count || p->post_waiters_left != p->count)
+  if (p->pre_waiters_left != p->count)
   {
     BarrierErrInfo bei = { p->a1 };
     VG_(maybe_record_error)(VG_(get_running_tid)(),
@@ -178,17 +181,44 @@
                   const BarrierT barrier_type, const Word count,
                   const Bool reinitialization)
 {
+  struct barrier_info* p;
+
+  tl_assert(barrier_type == pthread_barrier || barrier_type == gomp_barrier);
+
+  p = barrier_get_or_allocate(barrier, barrier_type, count);
+
   if (s_trace_barrier)
   {
-    VG_(message)(Vg_UserMsg,
-                 "[%d/%d] barrier_init 0x%lx",
-                 VG_(get_running_tid)(),
-                 thread_get_running_tid(),
-                 barrier);
+    if (reinitialization)
+    {
+      VG_(message)(Vg_UserMsg,
+                   "[%d/%d] barrier_reinit    %s 0x%lx count %d -> %d",
+                   VG_(get_running_tid)(),
+                   thread_get_running_tid(),
+                   barrier_get_typename(p),
+                   barrier,
+                   p->count,
+                   count);
+    }
+    else
+    {
+      VG_(message)(Vg_UserMsg,
+                   "[%d/%d] barrier_init      %s 0x%lx",
+                   VG_(get_running_tid)(),
+                   thread_get_running_tid(),
+                   barrier_get_typename(p),
+                   barrier);
+    }
   }
-  tl_assert(barrier_get(barrier) == 0);
-  tl_assert(barrier_type == pthread_barrier || barrier_type == gomp_barrier);
-  barrier_get_or_allocate(barrier, barrier_type, count);
+
+  if (reinitialization && p->count != count)
+  {
+    if (p->pre_waiters_left != p->count || p->post_waiters_left != p->count)
+    {
+      VG_(message)(Vg_UserMsg, "Error: reinitialization with active waiters");
+    }
+    p->count = count;
+  }
 }
 
 /** Called after pthread_barrier_destroy(). */
@@ -196,16 +226,18 @@
 {
   struct barrier_info* p;
 
+  p = barrier_get(barrier);
+
   if (s_trace_barrier)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] barrier_destroy 0x%lx",
+                 "[%d/%d] barrier_destroy   %s 0x%lx",
                  VG_(get_running_tid)(),
                  thread_get_running_tid(),
+                 barrier_get_typename(p),
                  barrier);
   }
 
-  p = barrier_get(barrier);
   if (p == 0)
   {
     GenericErrInfo GEI;
@@ -234,9 +266,10 @@
   if (s_trace_barrier)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] barrier_pre_wait 0x%lx iteration %d",
+                 "[%d/%d] barrier_pre_wait  %s 0x%lx iteration %d",
                  VG_(get_running_tid)(),
                  thread_get_running_tid(),
+                 barrier_get_typename(p),
                  barrier,
                  p->pre_iteration);
   }
@@ -266,18 +299,24 @@
   struct barrier_info* p;
 
   p = barrier_get(barrier);
-  tl_assert(p);
 
   if (s_trace_barrier)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] barrier_post_wait 0x%lx iteration %d",
+                 "[%d/%d] barrier_post_wait %s 0x%lx iteration %d",
                  VG_(get_running_tid)(),
                  tid,
+                 p ? barrier_get_typename(p) : "(?)",
                  barrier,
-                 p->post_iteration);
+                 p ? p->post_iteration : -1);
   }
 
+  /* If p == 0, this means that the barrier has been destroyed after     */
+  /* *_barrier_wait() returned and before this function was called. Just */
+  /* return in that case.                                                */
+  if (p == 0)
+    return;
+
   if (waited)
   {
     const UWord word_tid = tid;
@@ -322,3 +361,22 @@
     VG_(OSetGen_FreeNode)(p->oset, q);
   }
 }
+
+static const char* barrier_get_typename(struct barrier_info* const p)
+{
+  tl_assert(p);
+
+  return barrier_type_name(p->barrier_type);
+}
+
+static const char* barrier_type_name(const BarrierT bt)
+{
+  switch (bt)
+  {
+  case pthread_barrier:
+    return "pthread barrier";
+  case gomp_barrier:
+    return "gomp barrier";
+  }
+  return "?";
+}