Added reference counting to segments. Synchronization objects (mutex, semaphore, barrier, rwlock) now keep a pointer to a segment instead of copying a vector clock for modeling causal relationships.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7727 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/drd_barrier.c b/exp-drd/drd_barrier.c
index 0d5f053..c1273cf 100644
--- a/exp-drd/drd_barrier.c
+++ b/exp-drd/drd_barrier.c
@@ -45,7 +45,7 @@
   UWord       tid;           // A DrdThreadId
   Word        iteration;     // iteration of last pthread_barrier_wait()
                              // call thread tid participated in.
-  VectorClock vc[2];         // vector clocks corresponding to the last two
+  Segment*    sg[2];         // Segments of the last two
                              // pthread_barrier() calls by thread tid.
 };
 
@@ -77,15 +77,15 @@
 {
   p->tid = tid;
   p->iteration = iteration;
-  vc_init(&p->vc[0], 0, 0);
-  vc_init(&p->vc[1], 0, 0);
+  p->sg[0] = 0;
+  p->sg[1] = 0;
 }
 
 /** Deallocate the memory that was allocated in barrier_thread_initialize(). */
 static void barrier_thread_destroy(struct barrier_thread_info* const p)
 {
-  vc_cleanup(&p->vc[0]);
-  vc_cleanup(&p->vc[1]);
+  sg_put(p->sg[0]);
+  sg_put(p->sg[1]);
 }
 
 /** Initialize the structure *p with the specified client-side barrier address,
@@ -112,7 +112,6 @@
   tl_assert(sizeof(((struct barrier_thread_info*)0)->tid)
             >= sizeof(DrdThreadId));
   p->oset = VG_(OSetGen_Create)(0, 0, VG_(malloc), VG_(free));
-  vc_init(&p->finished_threads_vc, 0, 0);
 }
 
 /** Deallocate the memory allocated by barrier_initialize() and in p->oset. 
@@ -141,7 +140,6 @@
     barrier_thread_destroy(q);
   }
   VG_(OSetGen_Destroy)(p->oset);
-  vc_cleanup(&p->finished_threads_vc);
 }
 
 /** Look up the client-side barrier address barrier in s_barrier[]. If not
@@ -192,7 +190,7 @@
     if (reinitialization)
     {
       VG_(message)(Vg_UserMsg,
-                   "[%d/%d] barrier_reinit    %s 0x%lx count %d -> %d",
+                   "[%d/%d] barrier_reinit    %s 0x%lx count %ld -> %ld",
                    VG_(get_running_tid)(),
                    thread_get_running_tid(),
                    barrier_get_typename(p),
@@ -263,20 +261,20 @@
   p = barrier_get(barrier);
   if (p == 0 && barrier_type == gomp_barrier)
   {
-    VG_(message)(Vg_UserMsg, "");
+    VG_(message)(Vg_UserMsg, "%s", "");
     VG_(message)(Vg_UserMsg,
                  "Please verify whether gcc has been configured"
                  " with option --disable-linux-futex.");
     VG_(message)(Vg_UserMsg,
                  "See also the section about OpenMP in the DRD manual.");
-    VG_(message)(Vg_UserMsg, "");
+    VG_(message)(Vg_UserMsg, "%s", "");
   }
   tl_assert(p);
 
   if (s_trace_barrier)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] barrier_pre_wait  %s 0x%lx iteration %d",
+                 "[%d/%d] barrier_pre_wait  %s 0x%lx iteration %ld",
                  VG_(get_running_tid)(),
                  thread_get_running_tid(),
                  barrier_get_typename(p),
@@ -292,8 +290,7 @@
     VG_(OSetGen_Insert)(p->oset, q);
     tl_assert(VG_(OSetGen_Lookup)(p->oset, &word_tid) == q);
   }
-  vc_assign(&q->vc[p->pre_iteration], &thread_get_segment(tid)->vc);
-  tl_assert(q->vc[p->pre_iteration].size > 0);
+  thread_get_latest_segment(&q->sg[p->pre_iteration], tid);
 
   if (--p->pre_waiters_left <= 0)
   {
@@ -313,7 +310,7 @@
   if (s_trace_barrier)
   {
     VG_(message)(Vg_UserMsg,
-                 "[%d/%d] barrier_post_wait %s 0x%lx iteration %d",
+                 "[%d/%d] barrier_post_wait %s 0x%lx iteration %ld",
                  VG_(get_running_tid)(),
                  tid,
                  p ? barrier_get_typename(p) : "(?)",
@@ -340,10 +337,10 @@
     {
       if (r != q)
       {
-        thread_combine_vc2(tid, &r->vc[p->post_iteration]);
+        tl_assert(r->sg[p->post_iteration]);
+        thread_combine_vc2(tid, &r->sg[p->post_iteration]->vc);
       }
     }
-    thread_combine_vc2(tid, &p->finished_threads_vc);
 
     thread_new_segment(tid);
 
@@ -366,7 +363,6 @@
     struct barrier_thread_info* q;
     const UWord word_tid = tid;
     q = VG_(OSetGen_Remove)(p->oset, &word_tid);
-    vc_combine(&p->finished_threads_vc, &q->vc[p->post_iteration]);
     barrier_thread_destroy(q);
     VG_(OSetGen_FreeNode)(p->oset, q);
   }
diff --git a/exp-drd/drd_clientobj.h b/exp-drd/drd_clientobj.h
index 9302b2a..abc92f5 100644
--- a/exp-drd/drd_clientobj.h
+++ b/exp-drd/drd_clientobj.h
@@ -63,7 +63,7 @@
   MutexT      mutex_type;      // pthread_mutex_t or pthread_spinlock_t.
   int         recursion_count; // 0 if free, >= 1 if locked.
   DrdThreadId owner;           // owner if locked, last owner if free.
-  VectorClock vc;              // vector clock associated with last unlock.
+  Segment*    last_locked_segment;
 };
 
 struct cond_info
@@ -72,8 +72,8 @@
   ObjType type;
   void    (*cleanup)(union drd_clientobj*);
   int     waiter_count;
-  Addr    mutex; // Client mutex specified in pthread_cond_wait() call, and null
-                 // if no client threads are currently waiting on this cond.var.
+  Addr    mutex; //Client mutex specified in pthread_cond_wait() call, and null
+                 //if no client threads are currently waiting on this cond.var.
 };
 
 struct semaphore_info
@@ -84,7 +84,7 @@
   UWord       value;             // Semaphore value.
   UWord       waiters;           // Number of threads inside sem_wait().
   DrdThreadId last_sem_post_tid; // Thread ID associated with last sem_post().
-  VectorClock vc;                // Vector clock of last sem_post() call.
+  Segment*    last_sem_post_segment;
 };
 
 struct barrier_info
@@ -99,7 +99,6 @@
   Word     pre_waiters_left;  // number of waiters left for a complete barrier.
   Word     post_waiters_left; // number of waiters left for a complete barrier.
   OSet*    oset;              // Thread-specific barrier information.
-  VectorClock finished_threads_vc;
 };
 
 struct rwlock_info
diff --git a/exp-drd/drd_mutex.c b/exp-drd/drd_mutex.c
index ba37e31..2d55c31 100644
--- a/exp-drd/drd_mutex.c
+++ b/exp-drd/drd_mutex.c
@@ -62,11 +62,11 @@
   tl_assert(mutex != 0);
 
   tl_assert(p->a1 == mutex);
-  p->cleanup         = (void(*)(DrdClientobj*))&mutex_cleanup;
-  p->mutex_type      = mutex_type;
-  p->recursion_count = 0;
-  p->owner           = DRD_INVALID_THREADID;
-  vc_init(&p->vc, 0, 0);
+  p->cleanup             = (void(*)(DrdClientobj*))&mutex_cleanup;
+  p->mutex_type          = mutex_type;
+  p->recursion_count     = 0;
+  p->owner               = DRD_INVALID_THREADID;
+  p->last_locked_segment = 0;
 }
 
 /** Deallocate the memory that was allocated by mutex_initialize(). */
@@ -92,7 +92,8 @@
                             &MEI);
   }
 
-  vc_cleanup(&p->vc);
+  sg_put(p->last_locked_segment);
+  p->last_locked_segment = 0;
 }
 
 static
@@ -276,7 +277,10 @@
     const DrdThreadId last_owner = p->owner;
 
     if (last_owner != drd_tid && last_owner != DRD_INVALID_THREADID)
-      thread_combine_vc2(drd_tid, mutex_get_last_vc(mutex));
+    {
+      tl_assert(p->last_locked_segment);
+      thread_combine_vc2(drd_tid, &p->last_locked_segment->vc);
+    }
     thread_new_segment(drd_tid);
 
     p->owner = drd_tid;
@@ -307,7 +311,6 @@
 {
   const DrdThreadId drd_tid = thread_get_running_tid();
   const ThreadId vg_tid = VG_(get_running_tid)();
-  const VectorClock* const vc = thread_get_vc(drd_tid);
   struct mutex_info* const p = mutex_get(mutex);
 
   if (s_trace_mutex)
@@ -318,8 +321,7 @@
                  drd_tid,
                  p ? mutex_get_typename(p) : "?",
                  mutex,
-                 p ? p->recursion_count : 0,
-                 p ? p->owner : 0);
+                 p ? p->recursion_count : 0);
   }
 
   if (p == 0 || mutex_type == mutex_type_invalid_mutex)
@@ -347,7 +349,7 @@
   tl_assert(p);
   if (p->mutex_type != mutex_type)
   {
-    VG_(message)(Vg_UserMsg, "??? mutex %p: type changed from %d into %d",
+    VG_(message)(Vg_UserMsg, "??? mutex 0x%lx: type changed from %d into %d",
                  p->a1, p->mutex_type, mutex_type);
   }
   tl_assert(p->mutex_type == mutex_type);
@@ -372,8 +374,8 @@
     /* This pthread_mutex_unlock() call really unlocks the mutex. Save the */
     /* current vector clock of the thread such that it is available when  */
     /* this mutex is locked again.                                        */
-    vc_assign(&p->vc, vc);
 
+    thread_get_latest_segment(&p->last_locked_segment, drd_tid);
     thread_new_segment(drd_tid);
   }
 }
@@ -422,12 +424,6 @@
   return False;
 }
 
-const VectorClock* mutex_get_last_vc(const Addr mutex)
-{
-  struct mutex_info* const p = mutex_get(mutex);
-  return p ? &p->vc : 0;
-}
-
 int mutex_get_recursion_count(const Addr mutex)
 {
   struct mutex_info* const p = mutex_get(mutex);
diff --git a/exp-drd/drd_mutex.h b/exp-drd/drd_mutex.h
index 204388c..b44c3b8 100644
--- a/exp-drd/drd_mutex.h
+++ b/exp-drd/drd_mutex.h
@@ -51,7 +51,6 @@
 const char* mutex_get_typename(struct mutex_info* const p);
 const char* mutex_type_name(const MutexT mt);
 Bool mutex_is_locked_by(const Addr mutex, const DrdThreadId tid);
-const VectorClock* mutex_get_last_vc(const Addr mutex);
 int mutex_get_recursion_count(const Addr mutex);
 void mutex_thread_delete(const DrdThreadId tid);
 ULong get_mutex_lock_count(void);
diff --git a/exp-drd/drd_rwlock.c b/exp-drd/drd_rwlock.c
index 5ba6706..7e23173 100644
--- a/exp-drd/drd_rwlock.c
+++ b/exp-drd/drd_rwlock.c
@@ -39,11 +39,11 @@
 
 struct rwlock_thread_info
 {
-  UWord       tid;        // DrdThreadId.
-  UInt        reader_nesting_count;
-  UInt        writer_nesting_count;
-  VectorClock vc;   // Vector clock associated with last unlock by this thread.
-  Bool        last_lock_was_writer_lock;
+  UWord    tid;                 // DrdThreadId.
+  UInt     reader_nesting_count;
+  UInt     writer_nesting_count;
+  Segment* last_unlock_segment; // Segment of last unlock call by this thread.
+  Bool     last_lock_was_writer_lock;
 };
 
 
@@ -129,7 +129,7 @@
     q->tid = tid;
     q->reader_nesting_count = 0;
     q->writer_nesting_count = 0;
-    vc_init(&q->vc, 0, 0);
+    q->last_unlock_segment  = 0;
     q->last_lock_was_writer_lock = False;
     VG_(OSetGen_Insert)(oset, q);
   }
@@ -148,7 +148,7 @@
   {
     if (q->tid != tid && (readers_too || q->last_lock_was_writer_lock))
     {
-      thread_combine_vc2(tid, &q->vc);
+      thread_combine_vc2(tid, &q->last_unlock_segment->vc);
     }
   }
 }
@@ -193,7 +193,7 @@
   VG_(OSetGen_ResetIter)(p->thread_info);
   for ( ; (q = VG_(OSetGen_Next)(p->thread_info)); q++)
   {
-    vc_cleanup(&q->vc);
+    sg_put(q->last_unlock_segment);
   }
   VG_(OSetGen_Destroy)(p->thread_info);
 }
@@ -438,7 +438,6 @@
 {
   const DrdThreadId drd_tid = thread_get_running_tid();
   const ThreadId vg_tid = VG_(get_running_tid)();
-  const VectorClock* const vc = thread_get_vc(drd_tid);
   struct rwlock_info* const p = rwlock_get(rwlock);
   struct rwlock_thread_info* q;
 
@@ -476,9 +475,9 @@
     /* This pthread_rwlock_unlock() call really unlocks the rwlock. Save the */
     /* current vector clock of the thread such that it is available when  */
     /* this rwlock is locked again.                                        */
-    vc_assign(&q->vc, vc);
-    q->last_lock_was_writer_lock = False;
 
+    thread_get_latest_segment(&q->last_unlock_segment, drd_tid);
+    q->last_lock_was_writer_lock = False;
     thread_new_segment(drd_tid);
   }
 }
diff --git a/exp-drd/drd_segment.c b/exp-drd/drd_segment.c
index 1269563..1bb186e 100644
--- a/exp-drd/drd_segment.c
+++ b/exp-drd/drd_segment.c
@@ -46,8 +46,8 @@
 
 // Function definitions.
 
-/**
- * Note: creator and created may be equal.
+/** Initialize the memory pointed at by sg.
+ *  @note The creator and created thread ID's may be equal.
  */
 static
 void sg_init(Segment* const sg,
@@ -62,9 +62,10 @@
 
   creator_sg = (creator != DRD_INVALID_THREADID
                 ? thread_get_segment(creator) : 0);
-  
+
   sg->next = 0;
   sg->prev = 0;
+  sg->refcnt = 1;
 
   if (vg_created != VG_INVALID_THREADID && VG_(get_SP)(vg_created) != 0)
     sg->stacktrace = VG_(record_ExeContext)(vg_created, 0);
@@ -82,23 +83,30 @@
   {
     char msg[256];
     VG_(snprintf)(msg, sizeof(msg),
-                  "New segment for thread %d/%d with vc ",
-                  DrdThreadIdToVgThreadId(creator), creator);
+                  "New segment for thread %d/%d for vc ",
+                  creator != VG_INVALID_THREADID
+                  ? DrdThreadIdToVgThreadId(creator)
+                  : DRD_INVALID_THREADID,
+                  creator);
     vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
                &sg->vc);
     VG_(message)(Vg_UserMsg, "%s", msg);
   }
 }
 
+/** Deallocate the memory that was allocated by sg_init(). */
 static
 void sg_cleanup(Segment* const sg)
 {
   tl_assert(sg);
+  tl_assert(sg->refcnt == 0);
+
   vc_cleanup(&sg->vc);
   bm_delete(sg->bm);
   sg->bm = 0;
 }
 
+/** Allocate and initialize a new segment. */
 Segment* sg_new(ThreadId const creator, ThreadId const created)
 {
   Segment* sg;
@@ -114,6 +122,7 @@
   return sg;
 }
 
+static
 void sg_delete(Segment* const sg)
 {
 #if 1
@@ -135,6 +144,50 @@
   VG_(free)(sg);
 }
 
+/** Query the reference count of the specified segment. */
+int sg_get_refcnt(const Segment* const sg)
+{
+  tl_assert(sg);
+
+  return sg->refcnt;
+}
+
+/** Increment the reference count of the specified segment. */
+Segment* sg_get(Segment* const sg)
+{
+  tl_assert(sg);
+
+  sg->refcnt++;
+  return sg;
+}
+
+/** Decrement the reference count of the specified segment and deallocate the
+ *  segment if the reference count became zero.
+ */
+void sg_put(Segment* const sg)
+{
+  if (sg == 0)
+    return;
+
+  if (drd_trace_segment)
+  {
+    char msg[256];
+    VG_(snprintf)(msg, sizeof(msg),
+                  "Decrementing segment reference count %d -> %d with vc ",
+                  sg->refcnt, sg->refcnt - 1);
+    vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
+               &sg->vc);
+    VG_(message)(Vg_UserMsg, "%s", msg);
+  }
+
+  tl_assert(sg->refcnt >= 1);
+
+  if (--sg->refcnt == 0)
+  {
+    sg_delete(sg);
+  }
+}
+
 void sg_print(const Segment* const sg)
 {
   tl_assert(sg);
diff --git a/exp-drd/drd_segment.h b/exp-drd/drd_segment.h
index ae7141b..e7eeeeb 100644
--- a/exp-drd/drd_segment.h
+++ b/exp-drd/drd_segment.h
@@ -42,13 +42,17 @@
 {
   struct segment*    next;
   struct segment*    prev;
+  int                refcnt;
   ExeContext*        stacktrace;
   VectorClock        vc;
   struct bitmap*     bm;
 } Segment;
 
+
 Segment* sg_new(const ThreadId creator, const ThreadId created);
-void sg_delete(Segment* const sg);
+int sg_get_refcnt(const Segment* const sg);
+Segment* sg_get(Segment* const sg);
+void sg_put(Segment* const sg);
 void sg_print(const Segment* const sg);
 Bool sg_get_trace(void);
 void sg_set_trace(const Bool trace_segment);
diff --git a/exp-drd/drd_semaphore.c b/exp-drd/drd_semaphore.c
index 607abe9..d9c818f 100644
--- a/exp-drd/drd_semaphore.c
+++ b/exp-drd/drd_semaphore.c
@@ -64,7 +64,7 @@
   p->value     = value;
   p->waiters   = 0;
   p->last_sem_post_tid = DRD_INVALID_THREADID;
-  vc_init(&p->vc, 0, 0);
+  p->last_sem_post_segment = 0;
 }
 
 /** Free the memory that was allocated by semaphore_initialize(). Called by
@@ -82,7 +82,7 @@
                             " upon",
                             &sei);
   }
-  vc_cleanup(&p->vc);
+  sg_put(p->last_sem_post_segment);
 }
 
 static
@@ -215,8 +215,12 @@
   }
   p->value--;
   tl_assert(p->value >= 0);
-  if (p->last_sem_post_tid != tid)
-    thread_combine_vc2(tid, &p->vc);
+  if (p->last_sem_post_tid != tid
+      && p->last_sem_post_tid != DRD_INVALID_THREADID)
+  {
+    tl_assert(p->last_sem_post_segment);
+    thread_combine_vc2(tid, &p->last_sem_post_segment->vc);
+  }
   thread_new_segment(tid);
 }
 
@@ -239,7 +243,7 @@
   {
     p->last_sem_post_tid = tid;
     thread_new_segment(tid);
-    vc_assign(&p->vc, thread_get_vc(tid));
+    thread_get_latest_segment(&p->last_sem_post_segment, tid);
   }
 }
 
diff --git a/exp-drd/drd_thread.c b/exp-drd/drd_thread.c
index 17cf5a7..fe68c45 100644
--- a/exp-drd/drd_thread.c
+++ b/exp-drd/drd_thread.c
@@ -42,6 +42,7 @@
 
 static void thread_append_segment(const DrdThreadId tid,
                                   Segment* const sg);
+static void thread_discard_segment(const DrdThreadId tid, Segment* const sg);
 static void thread_update_danger_set(const DrdThreadId tid);
 
 
@@ -245,9 +246,8 @@
   return s_threadinfo[tid].stack_max;
 }
 
-/**
- * Clean up thread-specific data structures. Call this just after 
- * pthread_join().
+/** Clean up thread-specific data structures. Call this just after 
+ *  pthread_join().
  */
 void thread_delete(const DrdThreadId tid)
 {
@@ -260,7 +260,9 @@
   for (sg = s_threadinfo[tid].last; sg; sg = sg_prev)
   {
     sg_prev = sg->prev;
-    sg_delete(sg);
+    sg->prev = 0;
+    sg->next = 0;
+    sg_put(sg);
   }
   s_threadinfo[tid].vg_thread_exists = False;
   s_threadinfo[tid].posix_thread_exists = False;
@@ -350,9 +352,11 @@
         && s_drd_running_tid != DRD_INVALID_THREADID)
     {
       VG_(message)(Vg_DebugMsg,
-                   "Context switch from thread %d/%d to thread %d/%d",
+                   "Context switch from thread %d/%d to thread %d/%d;"
+                   " segments: %llu",
                    s_vg_running_tid, s_drd_running_tid,
-                   DrdThreadIdToVgThreadId(drd_tid), drd_tid);
+                   DrdThreadIdToVgThreadId(drd_tid), drd_tid,
+                   sg_get_alive_segments_count());
     }
     s_vg_running_tid = vg_tid;
     s_drd_running_tid = drd_tid;
@@ -416,18 +420,30 @@
     s_threadinfo[tid].first = sg->next;
   if (sg == s_threadinfo[tid].last)
     s_threadinfo[tid].last = sg->prev;
-  sg_delete(sg);
+  sg_put(sg);
   tl_assert(sane_ThreadInfo(&s_threadinfo[tid]));
 }
 
 VectorClock* thread_get_vc(const DrdThreadId tid)
 {
-  tl_assert(0 <= tid && tid < DRD_N_THREADS
-            && tid != DRD_INVALID_THREADID);
+  tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
   tl_assert(s_threadinfo[tid].last);
   return &s_threadinfo[tid].last->vc;
 }
 
+/** Return the latest segment of thread 'tid' and increment its reference
+ *  count.
+ */
+void thread_get_latest_segment(Segment** sg, const DrdThreadId tid)
+{
+  tl_assert(sg);
+  tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
+  tl_assert(s_threadinfo[tid].last);
+
+  sg_put(*sg);
+  *sg = sg_get(s_threadinfo[tid].last);
+}
+
 /**
  * Compute the minimum of all latest vector clocks of all threads
  * (Michiel Ronsse calls this "clock snooping" in his papers about DIOTA).
@@ -504,7 +520,7 @@
                   ", max vc is ");
     vc_snprint(msg + VG_(strlen)(msg), sizeof(msg) - VG_(strlen)(msg),
                &thread_vc_max);
-    VG_(message)(Vg_DebugMsg, "%s", msg);
+    VG_(message)(Vg_UserMsg, "%s", msg);
     vc_cleanup(&thread_vc_max);
   }
 
@@ -522,19 +538,14 @@
   vc_cleanup(&thread_vc_min);
 }
 
-/**
- * Create a new segment for the specified thread, and report all data races
- * of the most recent thread segment with other threads.
+/** Create a new segment for the specified thread, and discard any segments
+ *  that cannot cause races anymore.
  */
 void thread_new_segment(const DrdThreadId tid)
 {
-  Segment* sg;
+  tl_assert(0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID);
 
-  tl_assert(0 <= tid && tid < DRD_N_THREADS
-            && tid != DRD_INVALID_THREADID);
-
-  sg = sg_new(tid, tid);
-  thread_append_segment(tid, sg);
+  thread_append_segment(tid, sg_new(tid, tid));
 
   thread_discard_ordered_segments();
 
@@ -639,7 +650,7 @@
     if (s_threadinfo[i].first)
     {
       VG_(printf)("**************\n"
-                  "* thread %3d (%d/%d/%d/0x%x/%d) *\n"
+                  "* thread %3d (%d/%d/%d/0x%lx/%d) *\n"
                   "**************\n",
                   i,
                   s_threadinfo[i].vg_thread_exists,
@@ -773,7 +784,7 @@
     vc_snprint(msg + VG_(strlen)(msg),
                sizeof(msg) - VG_(strlen)(msg),
                &s_threadinfo[tid].last->vc);
-    VG_(message)(Vg_DebugMsg, "%s", msg);
+    VG_(message)(Vg_UserMsg, "%s", msg);
   }
 
   p = s_threadinfo[tid].last;
@@ -790,7 +801,7 @@
       vc_snprint(msg + VG_(strlen)(msg),
                  sizeof(msg) - VG_(strlen)(msg),
                  &p->vc);
-      VG_(message)(Vg_DebugMsg, "%s", msg);
+      VG_(message)(Vg_UserMsg, "%s", msg);
     }
 
     for (j = 0; j < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); j++)
@@ -810,7 +821,7 @@
               vc_snprint(msg + VG_(strlen)(msg),
                          sizeof(msg) - VG_(strlen)(msg),
                          &q->vc);
-              VG_(message)(Vg_DebugMsg, "%s", msg);
+              VG_(message)(Vg_UserMsg, "%s", msg);
             }
             bm_merge2(s_danger_set, q->bm);
           }
@@ -824,7 +835,7 @@
               vc_snprint(msg + VG_(strlen)(msg),
                          sizeof(msg) - VG_(strlen)(msg),
                          &q->vc);
-              VG_(message)(Vg_DebugMsg, "%s", msg);
+              VG_(message)(Vg_UserMsg, "%s", msg);
             }
           }
       }
@@ -856,9 +867,9 @@
 
   if (0 && s_trace_danger_set)
   {
-    VG_(message)(Vg_DebugMsg, "[%d] new danger set:", tid);
+    VG_(message)(Vg_UserMsg, "[%d] new danger set:", tid);
     bm_print(s_danger_set);
-    VG_(message)(Vg_DebugMsg, "[%d] end of new danger set.", tid);
+    VG_(message)(Vg_UserMsg, "[%d] end of new danger set.", tid);
   }
 }
 
diff --git a/exp-drd/drd_thread.h b/exp-drd/drd_thread.h
index 290d4ea..66aa637 100644
--- a/exp-drd/drd_thread.h
+++ b/exp-drd/drd_thread.h
@@ -114,6 +114,7 @@
 int thread_get_synchr_nesting_count(const DrdThreadId tid);
 void thread_new_segment(const DrdThreadId tid);
 VectorClock* thread_get_vc(const DrdThreadId tid);
+void thread_get_latest_segment(Segment** sg, const DrdThreadId tid);
 void thread_combine_vc(const DrdThreadId joiner, const DrdThreadId joinee);
 void thread_combine_vc2(const DrdThreadId tid, const VectorClock* const vc);
 void thread_stop_using_mem(const Addr a1, const Addr a2);