Fixed bug in vector clock updating for semaphores with non-zero initial value.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@8854 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/drd/drd_clientobj.h b/drd/drd_clientobj.h
index 98f4fd9..f9c9446 100644
--- a/drd/drd_clientobj.h
+++ b/drd/drd_clientobj.h
@@ -89,6 +89,7 @@
   ObjType     type;
   void        (*cleanup)(union drd_clientobj*);
   ExeContext* first_observed_at;
+  UInt        initial_value;     // Value assigned through sem_init().
   UInt        value;             // Semaphore value.
   UWord       waiters;           // Number of threads inside sem_wait().
   DrdThreadId last_sem_post_tid; // Thread ID associated with last sem_post().
diff --git a/drd/drd_semaphore.c b/drd/drd_semaphore.c
index 2cc59dc..df3c886 100644
--- a/drd/drd_semaphore.c
+++ b/drd/drd_semaphore.c
@@ -87,16 +87,16 @@
 }
 
 static
-void semaphore_initialize(struct semaphore_info* const p,
-                          const Addr semaphore, const UWord value)
+void semaphore_initialize(struct semaphore_info* const p, const Addr semaphore)
 {
   tl_assert(semaphore != 0);
   tl_assert(p->a1 == semaphore);
   tl_assert(p->type == ClientSemaphore);
 
-  p->cleanup   = (void(*)(DrdClientobj*))semaphore_cleanup;
-  p->value     = value;
-  p->waiters   = 0;
+  p->cleanup           = (void(*)(DrdClientobj*))semaphore_cleanup;
+  p->initial_value     = 0;
+  p->value             = 0;
+  p->waiters           = 0;
   p->last_sem_post_tid = DRD_INVALID_THREADID;
   p->last_sem_post_seg = VG_(newXA)(VG_(malloc), "drd.sg-stack",
                                     VG_(free), sizeof(Segment*));
@@ -136,7 +136,7 @@
   {
     tl_assert(offsetof(DrdClientobj, semaphore) == 0);
     p = &clientobj_add(semaphore, ClientSemaphore)->semaphore;
-    semaphore_initialize(p, semaphore, 0);
+    semaphore_initialize(p, semaphore);
   }
   return p;
 }
@@ -151,7 +151,10 @@
 struct semaphore_info* semaphore_init(const Addr semaphore,
                                       const Word pshared, const UInt value)
 {
+  unsigned n;
   struct semaphore_info* p;
+  Segment* sg;
+  const DrdThreadId drd_tid = thread_get_running_tid();
 
   if (s_trace_semaphore)
   {
@@ -172,13 +175,19 @@
                             VG_(get_IP)(vg_tid),
                             "Semaphore reinitialization",
                             &SEI);
+    // Remove all segments from the segment stack.
+    while ((sg = segment_pop(p)))
+    {
+      sg_put(sg);
+    }
   }
   else
   {
     p = semaphore_get_or_allocate(semaphore);
   }
   tl_assert(p);
-  p->value = value;
+  p->initial_value = value;
+  p->value         = value;
   return p;
 }
 
@@ -263,17 +272,23 @@
   }
   p->value--;
   tl_assert((int)p->value >= 0);
-  sg = segment_pop(p);
-  if (sg)
+  if (p->initial_value > 0)
+    p->initial_value--;
+  else
   {
-    if (p->last_sem_post_tid != tid
-        && p->last_sem_post_tid != DRD_INVALID_THREADID)
+    sg = segment_pop(p);
+    tl_assert(sg);
+    if (sg)
     {
-      thread_combine_vc2(tid, &sg->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++;
     }
-    sg_put(sg);
-    thread_new_segment(tid);
-    s_semaphore_segment_creation_count++;
   }
 }