Fixed semaphore vector clock updating / simplified semaphore tracing.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@8836 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/drd/drd_semaphore.c b/drd/drd_semaphore.c
index 0f16305..2cc59dc 100644
--- a/drd/drd_semaphore.c
+++ b/drd/drd_semaphore.c
@@ -31,6 +31,7 @@
 #include "pub_tool_libcassert.h"  // tl_assert()
 #include "pub_tool_libcprint.h"   // VG_(printf)()
 #include "pub_tool_machine.h"     // VG_(get_IP)()
+#include "pub_tool_mallocfree.h"  // VG_(malloc), VG_(free)
 #include "pub_tool_threadstate.h" // VG_(get_running_tid)()
 
 
@@ -47,6 +48,39 @@
 
 // Function definitions.
 
+static void segment_push(struct semaphore_info* p, Segment* sg)
+{
+  Word n;
+
+  tl_assert(sg);
+  n = VG_(addToXA)(p->last_sem_post_seg, &sg);
+#if 0
+  VG_(message)(Vg_UserMsg, "0x%lx push: added at position %ld/%ld",
+               p->a1, n, VG_(sizeXA)(p->last_sem_post_seg));
+#endif
+  tl_assert(*(Segment**)VG_(indexXA)(p->last_sem_post_seg, n) == sg);
+}
+
+static Segment* segment_pop(struct semaphore_info* p)
+{
+  Word sz;
+  Segment* sg;
+
+  sz = VG_(sizeXA)(p->last_sem_post_seg);
+#if 0
+  VG_(message)(Vg_UserMsg, "0x%lx pop:  removed from position %ld/%ld",
+               p->a1, sz - 1, sz);
+#endif
+  sg = 0;
+  if (sz > 0)
+  {
+    sg = *(Segment**)VG_(indexXA)(p->last_sem_post_seg, sz - 1);
+    tl_assert(sg);
+    VG_(dropTailXA)(p->last_sem_post_seg, 1);
+  }
+  return sg;
+}
+
 void semaphore_set_trace(const Bool trace_semaphore)
 {
   s_trace_semaphore = trace_semaphore;
@@ -64,7 +98,8 @@
   p->value     = value;
   p->waiters   = 0;
   p->last_sem_post_tid = DRD_INVALID_THREADID;
-  p->last_sem_post_segment = 0;
+  p->last_sem_post_seg = VG_(newXA)(VG_(malloc), "drd.sg-stack",
+                                    VG_(free), sizeof(Segment*));
 }
 
 /** Free the memory that was allocated by semaphore_initialize(). Called by
@@ -72,6 +107,8 @@
  */
 static void semaphore_cleanup(struct semaphore_info* p)
 {
+  Segment* sg;
+
   if (p->waiters > 0)
   {
     SemaphoreErrInfo sei = { p->a1 };
@@ -82,7 +119,9 @@
                             " upon",
                             &sei);
   }
-  sg_put(p->last_sem_post_segment);
+  while ((sg = segment_pop(p)))
+    sg_put(sg);
+  VG_(deleteXA)(p->last_sem_post_seg);
 }
 
 static
@@ -180,15 +219,6 @@
   struct semaphore_info* p;
 
   p = semaphore_get_or_allocate(semaphore);
-  if (s_trace_semaphore)
-  {
-    VG_(message)(Vg_UserMsg,
-                 "[%d/%d] semaphore_pre_wait  0x%lx value %u",
-                 VG_(get_running_tid)(),
-                 thread_get_running_tid(),
-                 semaphore,
-                 p->value);
-  }
   tl_assert(p);
   tl_assert((int)p->waiters >= 0);
   p->waiters++;
@@ -203,17 +233,20 @@
                          const Bool waited)
 {
   struct semaphore_info* p;
+  Segment* sg;
 
   p = semaphore_get(semaphore);
   if (s_trace_semaphore)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] semaphore_post_wait 0x%lx value %u",
+                 "[%d/%d] semaphore_wait      0x%lx value %u -> %u",
                  VG_(get_running_tid)(),
                  thread_get_running_tid(),
                  semaphore,
+                 p ? p->value : 0,
                  p ? p->value - 1 : 0);
   }
+  tl_assert(p);
   tl_assert(p->waiters > 0);
   p->waiters--;
   tl_assert((int)p->waiters >= 0);
@@ -230,20 +263,25 @@
   }
   p->value--;
   tl_assert((int)p->value >= 0);
-  if (p->last_sem_post_tid != tid
-      && p->last_sem_post_tid != DRD_INVALID_THREADID)
+  sg = segment_pop(p);
+  if (sg)
   {
-    tl_assert(p->last_sem_post_segment);
-    thread_combine_vc2(tid, &p->last_sem_post_segment->vc);
+    if (p->last_sem_post_tid != tid
+        && p->last_sem_post_tid != DRD_INVALID_THREADID)
+    {
+      thread_combine_vc2(tid, &sg->vc);
+    }
+    sg_put(sg);
+    thread_new_segment(tid);
+    s_semaphore_segment_creation_count++;
   }
-  thread_new_segment(tid);
-  s_semaphore_segment_creation_count++;
 }
 
 /** Called before sem_post(). */
 void semaphore_pre_post(const DrdThreadId tid, const Addr semaphore)
 {
   struct semaphore_info* p;
+  Segment* sg;
 
   p = semaphore_get_or_allocate(semaphore);
   p->value++;
@@ -251,20 +289,20 @@
   if (s_trace_semaphore)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] semaphore_post      0x%lx value %u",
+                 "[%d/%d] semaphore_post      0x%lx value %u -> %u",
                  VG_(get_running_tid)(),
                  thread_get_running_tid(),
                  semaphore,
-                 p->value);
+                 p->value - 1, p->value);
   }
 
-  if (p->value == 1)
-  {
-    p->last_sem_post_tid = tid;
-    thread_new_segment(tid);
-    thread_get_latest_segment(&p->last_sem_post_segment, tid);
-    s_semaphore_segment_creation_count++;
-  }
+  p->last_sem_post_tid = tid;
+  thread_new_segment(tid);
+  sg = 0;
+  thread_get_latest_segment(&sg, tid);
+  tl_assert(sg);
+  segment_push(p, sg);
+  s_semaphore_segment_creation_count++;
 }
 
 /** Called after sem_post() finished successfully. */