Implemented segment merging.

git-svn-id: svn://svn.valgrind.org/valgrind/trunk@7750 a5019735-40e9-0310-863c-91ae7b9d1cf9
diff --git a/exp-drd/drd_thread.c b/exp-drd/drd_thread.c
index fe68c45..62eb0f3 100644
--- a/exp-drd/drd_thread.c
+++ b/exp-drd/drd_thread.c
@@ -59,6 +59,7 @@
 struct bitmap* s_danger_set;
 static Bool s_trace_context_switches = False;
 static Bool s_trace_danger_set = False;
+static Bool s_segment_merging = True;
 
 
 // Function definitions.
@@ -73,6 +74,11 @@
   s_trace_danger_set = t;
 }
 
+void thread_set_segment_merging(const Bool m)
+{
+  s_segment_merging = m;
+}
+
 __inline__ Bool IsValidDrdThreadId(const DrdThreadId tid)
 {
   return (0 <= tid && tid < DRD_N_THREADS && tid != DRD_INVALID_THREADID
@@ -538,6 +544,41 @@
   vc_cleanup(&thread_vc_min);
 }
 
+/** Merge all segments that may be merged without triggering false positives
+ *  or discarding real data races. For the theoretical background of segment
+ *  merging, see also the following paper:
+ *  Mark Christiaens, Michiel Ronsse and Koen De Bosschere.
+ *  Bounding the number of segment histories during data race detection.
+ *  Parallel Computing archive, Volume 28, Issue 9, pp 1221-1238,
+ *  September 2002.
+ */
+static void thread_merge_segments(void)
+{
+  unsigned i;
+
+  for (i = 0; i < sizeof(s_threadinfo) / sizeof(s_threadinfo[0]); i++)
+  {
+    Segment* sg;
+
+    tl_assert(sane_ThreadInfo(&s_threadinfo[i]));
+
+    for (sg = s_threadinfo[i].first; sg; sg = sg->next)
+    {
+      if (sg_get_refcnt(sg) == 1
+          && sg->next
+          && sg_get_refcnt(sg->next) == 1
+          && sg->next->next)
+      {
+        /* Merge sg and sg->next into sg. */
+        sg_merge(sg, sg->next);
+        thread_discard_segment(i, sg->next);
+      }
+    }
+
+    tl_assert(sane_ThreadInfo(&s_threadinfo[i]));
+  }
+}
+
 /** Create a new segment for the specified thread, and discard any segments
  *  that cannot cause races anymore.
  */
@@ -549,6 +590,9 @@
 
   thread_discard_ordered_segments();
 
+  if (s_segment_merging)
+    thread_merge_segments();
+
   if (tid == s_drd_running_tid)
   {
     /* Every change in the vector clock of the current thread may cause */