Author: sewardj
Date: 2007-10-25 10:45:57 +0100 (Thu, 25 Oct 2007)
New Revision: 7031

Log:
Use a vector timestamp mechanism to speed up comparisons in the
happens-before graph, which can tend to dominate all other costs in
programs which generate more than a few thousand Segments.

Modified:
   branches/THRCHECK/thrcheck/tc_main.c


Modified: branches/THRCHECK/thrcheck/tc_main.c
===================================================================
--- branches/THRCHECK/thrcheck/tc_main.c        2007-10-23 22:26:12 UTC (rev 
7030)
+++ branches/THRCHECK/thrcheck/tc_main.c        2007-10-25 09:45:57 UTC (rev 
7031)
@@ -303,6 +303,7 @@
       struct _Segment* prev;   /* The previous segment in this thread */
       struct _Segment* other;  /* Possibly a segment from some other 
                                   thread, which happened-before me */
+      XArray*          vts;    /* XArray of ScalarTS */
       /* DEBUGGING ONLY: what does 'other' arise from?  
          c=thread creation, j=join, s=cvsignal, S=semaphore */
       Char other_hint;
@@ -574,6 +575,7 @@
    seg->thr        = thr;
    seg->prev       = prev;
    seg->other      = other;
+   seg->vts        = NULL;
    seg->other_hint = ' ';
    seg->magic      = Segment_MAGIC;
    seg->admin      = admin_segments;
@@ -1279,6 +1281,7 @@
 static void shmem__set_mbHasLocks ( Addr a, Bool b );
 static Bool shmem__get_mbHasLocks ( Addr a );
 static void shadow_mem_set8 ( Thread* uu_thr_acc, Addr a, UInt svNew );
+static XArray* singleton_VTS ( Thread* thr, UWord tym );
 
 static void initialise_data_structures ( void )
 {
@@ -1343,7 +1346,11 @@
    thr = mk_Thread( segid );
    seg->thr = thr;
 
-   /* and bind it in the thread-map table */
+   /* Give the thread a starting-off vector timestamp. */
+   seg->vts = singleton_VTS( seg->thr, 1 );
+
+   /* and bind it in the thread-map table.
+      FIXME: assumes root ThreadId == 1. */
    map_threads[1] = thr;
 
    tl_assert(VG_INVALID_THREADID == 0);
@@ -1482,6 +1489,8 @@
 /*--- the DAG of thread segments                               ---*/
 /*----------------------------------------------------------------*/
 
+static void segments__generate_vcg ( void ); /* fwds */
+
 /*--------------- SegmentID to Segment* maps ---------------*/
 
 static Segment* map_segments_lookup ( SegmentID segid )
@@ -1512,6 +1521,351 @@
    TC_(addToFM)( map_segments, (Word)segid, (Word)seg );
 }
 
+/*--------------- to do with Vector Timestamps ---------------*/
+
+/* Scalar Timestamp */
+typedef
+   struct {
+      Thread* thr;
+      UWord   tym;
+   }
+   ScalarTS;
+
+/* Vector Timestamp = XArray* ScalarTS */
+
+static Bool is_sane_VTS ( XArray* vts )
+{
+   UWord     i, n;
+   ScalarTS  *st1, *st2;
+   n = VG_(sizeXA)( vts );
+   if (n >= 2) {
+      for (i = 0; i < n-1; i++) {
+         st1 = VG_(indexXA)( vts, i );
+         st2 = VG_(indexXA)( vts, i+1 );
+         if (st1->thr >= st2->thr)
+            return False;
+         if (st1->tym == 0 || st2->tym == 0)
+            return False;
+      }
+   }
+   return True;
+}
+
+static XArray* new_VTS ( void ) {
+   return VG_(newXA)( tc_zalloc, tc_free, sizeof(ScalarTS) );
+}
+static XArray* singleton_VTS ( Thread* thr, UWord tym ) {
+   ScalarTS st;
+   XArray*  vts;
+   tl_assert(thr);
+   tl_assert(tym >= 1);
+   vts = new_VTS();
+   tl_assert(vts);
+   st.thr = thr;
+   st.tym = tym;
+   VG_(addToXA)( vts, &st );
+   return vts;
+}
+
+
+static Bool cmpGEQ_VTS ( XArray* a, XArray* b )
+{
+   Word     ia, ib, useda, usedb;
+   UWord    tyma, tymb;
+   Thread*  thr;
+   ScalarTS *tmpa, *tmpb;
+
+   Bool all_leq = True;
+   Bool all_geq = True;
+
+   tl_assert(a);
+   tl_assert(b);
+   useda = VG_(sizeXA)( a );
+   usedb = VG_(sizeXA)( b );
+
+   ia = ib = 0;
+
+   while (1) {
+
+      /* This logic is to enumerate triples (thr, tyma, tymb) drawn
+         from a and b in order, where thr is the next Thread*
+         occurring in either a or b, and tyma/b are the relevant
+         scalar timestamps, taking into account implicit zeroes. */
+      tl_assert(ia >= 0 && ia <= useda);
+      tl_assert(ib >= 0 && ib <= usedb);
+      tmpa = tmpb = NULL;
+
+      if (ia == useda && ib == usedb) {
+         /* both empty - done */
+         break;
+      }
+      else
+      if (ia == useda && ib != usedb) {
+         /* a empty, use up b */
+         tmpb = VG_(indexXA)( b, ib );
+         thr  = tmpb->thr;
+         tyma = 0;
+         tymb = tmpb->tym;
+         ib++;
+      }
+      else
+      if (ia != useda && ib == usedb) {
+         /* b empty, use up a */
+         tmpa = VG_(indexXA)( a, ia );
+         thr  = tmpa->thr;
+         tyma = tmpa->tym;
+         tymb = 0;
+         ia++;
+      }
+      else {
+         /* both not empty; extract lowest-Thread*'d triple */
+         tmpa = VG_(indexXA)( a, ia );
+         tmpb = VG_(indexXA)( b, ib );
+         if (tmpa->thr < tmpb->thr) {
+            /* a has the lowest unconsidered Thread* */
+            thr  = tmpa->thr;
+            tyma = tmpa->tym;
+            tymb = 0;
+            ia++;
+         }
+         else
+         if (tmpa->thr > tmpb->thr) {
+            /* b has the lowest unconsidered Thread* */
+            thr  = tmpb->thr;
+            tyma = 0;
+            tymb = tmpb->tym;
+            ib++;
+         } else {
+            /* they both next mention the same Thread* */
+            tl_assert(tmpa->thr == tmpb->thr);
+            thr  = tmpa->thr; /* == tmpb->thr */
+            tyma = tmpa->tym;
+            tymb = tmpb->tym;
+            ia++;
+            ib++;
+         }
+      }
+
+      /* having laboriously determined (thr, tyma, tymb), do something
+         useful with it. */
+      if (tyma < tymb)
+         all_geq = False;
+      if (tyma > tymb)
+         all_leq = False;
+   }
+
+   if (all_leq && all_geq)
+      return True; /* PordEQ */
+   /* now we know they aren't equal, so either all_leq or all_geq or
+      both are false. */
+   if (all_leq)
+      return False; /* PordLT */
+   if (all_geq)
+      return True; /* PordGT */
+   /* hmm, neither all_geq or all_leq.  This means unordered. */
+   return False; /* PordUN */
+}
+
+
+/* Compute max((tick(thra,a),b) into a new XArray.  a and b are
+   unchanged.  If neither a nor b supply a value for 'thra',
+   assert. */
+static
+XArray* tickL_and_joinR_VTS ( Thread* thra, XArray* a, XArray* b )
+{
+   Word     ia, ib, useda, usedb, ticks_found;
+   UWord    tyma, tymb, tymMax;
+   Thread*  thr;
+   XArray*  res;
+   ScalarTS *tmpa, *tmpb;
+
+   tl_assert(a);
+   tl_assert(b);
+   tl_assert(thra);
+   useda = VG_(sizeXA)( a );
+   usedb = VG_(sizeXA)( b );
+
+   res = new_VTS();
+   ia = ib = ticks_found = 0;
+
+   while (1) {
+
+      /* This logic is to enumerate triples (thr, tyma, tymb) drawn
+         from a and b in order, where thr is the next Thread*
+         occurring in either a or b, and tyma/b are the relevant
+         scalar timestamps, taking into account implicit zeroes. */
+      tl_assert(ia >= 0 && ia <= useda);
+      tl_assert(ib >= 0 && ib <= usedb);
+      tmpa = tmpb = NULL;
+
+      if (ia == useda && ib == usedb) {
+         /* both empty - done */
+         break;
+      }
+      else
+      if (ia == useda && ib != usedb) {
+         /* a empty, use up b */
+         tmpb = VG_(indexXA)( b, ib );
+         thr  = tmpb->thr;
+         tyma = 0;
+         tymb = tmpb->tym;
+         ib++;
+      }
+      else
+      if (ia != useda && ib == usedb) {
+         /* b empty, use up a */
+         tmpa = VG_(indexXA)( a, ia );
+         thr  = tmpa->thr;
+         tyma = tmpa->tym;
+         tymb = 0;
+         ia++;
+      }
+      else {
+         /* both not empty; extract lowest-Thread*'d triple */
+         tmpa = VG_(indexXA)( a, ia );
+         tmpb = VG_(indexXA)( b, ib );
+         if (tmpa->thr < tmpb->thr) {
+            /* a has the lowest unconsidered Thread* */
+            thr  = tmpa->thr;
+            tyma = tmpa->tym;
+            tymb = 0;
+            ia++;
+         }
+         else
+         if (tmpa->thr > tmpb->thr) {
+            /* b has the lowest unconsidered Thread* */
+            thr  = tmpb->thr;
+            tyma = 0;
+            tymb = tmpb->tym;
+            ib++;
+         } else {
+            /* they both next mention the same Thread* */
+            tl_assert(tmpa->thr == tmpb->thr);
+            thr  = tmpa->thr; /* == tmpb->thr */
+            tyma = tmpa->tym;
+            tymb = tmpb->tym;
+            ia++;
+            ib++;
+         }
+      }
+
+      /* having laboriously determined (thr, tyma, tymb), do something
+         useful with it. */
+      if (thr == thra) {
+         if (tyma > 0) {
+            /* VTS 'a' actually supplied this value; it is not a
+               default zero.  Do the required 'tick' action. */
+            tyma++;
+            ticks_found++;
+         } else {
+            /* 'a' didn't supply this value, so 'b' must have. */
+            tl_assert(tymb > 0);
+         }
+      }
+      tymMax = tyma > tymb ? tyma : tymb;
+      if (tymMax > 0) {
+         ScalarTS st;
+         st.thr = thr;
+         st.tym = tymMax;
+         VG_(addToXA)( res, &st );
+      }
+
+   }
+
+   tl_assert(is_sane_VTS( res ));
+
+   if (thra != NULL) {
+      tl_assert(ticks_found == 1);
+   } else {
+      tl_assert(ticks_found == 0);
+   }
+
+   return res;
+}
+
+
+/* Do 'vts[me]++', so to speak.  If 'me' does not have an entry in
+   'vts', set it to 1 in the returned VTS. */
+
+static XArray* tick_VTS ( Thread* me, XArray* vts ) {
+   ScalarTS* here = NULL;
+   ScalarTS  tmp;
+   XArray*   res;
+   Word      i, n; 
+   tl_assert(me);
+   tl_assert(is_sane_VTS(vts));
+   if (0) VG_(printf)("tick vts thrno %ld szin %d\n",
+                      (Word)me->errmsg_index, (Int)VG_(sizeXA)(vts) );
+   res = new_VTS();
+   n = VG_(sizeXA)( vts );
+   for (i = 0; i < n; i++) {
+      here = VG_(indexXA)( vts, i );
+      if (me < here->thr) {
+         /* We just went past 'me', without seeing it. */
+         tmp.thr = me;
+         tmp.tym = 1;
+         VG_(addToXA)( res, &tmp );
+         tmp = *here;
+         VG_(addToXA)( res, &tmp );
+         i++;
+         break;
+      } 
+      else if (me == here->thr) {
+         tmp = *here;
+         tmp.tym++;
+         VG_(addToXA)( res, &tmp );
+         i++;
+         break;
+      }
+      else /* me > here->thr */ {
+         tmp = *here;
+         VG_(addToXA)( res, &tmp );
+      }
+   }
+   tl_assert(i >= 0 && i <= n);
+   if (i == n && here && here->thr < me) {
+      tmp.thr = me;
+      tmp.tym = 1;
+      VG_(addToXA)( res, &tmp );
+   } else {
+      for (/*keepgoing*/; i < n; i++) {
+         here = VG_(indexXA)( vts, i );
+         tmp = *here;
+         VG_(addToXA)( res, &tmp );
+      }
+   }
+   tl_assert(is_sane_VTS(res));
+   if (0) VG_(printf)("tick vts thrno %ld szou %d\n",
+                      (Word)me->errmsg_index, (Int)VG_(sizeXA)(res) );
+   return res;
+}
+
+static void show_VTS ( HChar* buf, Int nBuf, XArray* vts ) {
+   ScalarTS* st;
+   HChar     unit[64];
+   Word      i, n;
+   Int       avail = nBuf;
+   tl_assert(avail > 16);
+   buf[0] = '[';
+   buf[1] = 0;
+   n = VG_(sizeXA)( vts );
+   for (i = 0; i < n; i++) {
+      tl_assert(avail >= 10);
+      st = VG_(indexXA)( vts, i );
+      VG_(memset)(unit, 0, sizeof(unit));
+      VG_(sprintf)(unit, i < n-1 ? "%ld:%ld " : "%ld:%ld",
+                         (Word)st->thr->errmsg_index, st->tym);
+      if (avail < VG_(strlen)(unit) + 10/*let's say*/) {
+         VG_(strcat)(buf, " ...]");
+         return;
+      }
+      VG_(strcat)(buf, unit);
+      avail -= VG_(strlen)(unit);
+   }
+   VG_(strcat)(buf, "]");
+}
+
+
 /*------------ searching the happens-before graph ------------*/
 
 static UWord stats__hbefore_queries   = 0; // total # queries
@@ -1614,18 +1968,9 @@
 }
 
 __attribute__((noinline))
-static Bool happens_before_wrk ( SegmentID segid1, SegmentID segid2 )
+static Bool happens_before_wrk ( Segment* seg1, Segment* seg2 )
 {
-   Bool    reachable;
-   Segment *seg1, *seg2;
-   tl_assert(is_sane_SegmentID(segid1));
-   tl_assert(is_sane_SegmentID(segid2));
-   tl_assert(segid1 != segid2);
-   seg1 = map_segments_lookup(segid1);
-   seg2 = map_segments_lookup(segid2);
-   tl_assert(is_sane_Segment(seg1));
-   tl_assert(is_sane_Segment(seg2));
-   tl_assert(seg1 != seg2);
+   Bool reachable;
 
    { static Int nnn = 0;
      if (SHOW_EXPENSIVE_STUFF && (nnn++ % 1000) == 0)
@@ -1640,14 +1985,10 @@
    if (dfsver_stack == NULL) {
      dfsver_stack = VG_(newXA)( tc_zalloc, tc_free, sizeof(Segment*) );
      tl_assert(dfsver_stack);
-  }
+   }
 
    reachable = happens_before_do_dfs_from_to( seg2, seg1 );
 
-   if (0)
-   VG_(printf)("happens_before 0x%x 0x%x: %s\n",
-               (Int)segid1, (Int)segid2, reachable ? "Y" : "N");
-
    return reachable;
 }
 
@@ -1675,8 +2016,9 @@
 
 static Bool happens_before ( SegmentID segid1, SegmentID segid2 )
 {
-   Bool hb;
-   Int  i, j, iNSERT_POINT;
+   Bool    hbG, hbV;
+   Int     i, j, iNSERT_POINT;
+   Segment *seg1, *seg2;
    tl_assert(is_sane_SegmentID(segid1));
    tl_assert(is_sane_SegmentID(segid2));
    tl_assert(segid1 != segid2);
@@ -1701,7 +2043,34 @@
    }
    /* Not found.  Search the graph and add an entry to the cache. */
    stats__hbefore_gsearches++;
-   hb = happens_before_wrk( segid1, segid2 );
+
+   seg1 = map_segments_lookup(segid1);
+   seg2 = map_segments_lookup(segid2);
+   tl_assert(is_sane_Segment(seg1));
+   tl_assert(is_sane_Segment(seg2));
+   tl_assert(seg1 != seg2);
+   tl_assert(seg1->vts);
+   tl_assert(seg2->vts);
+
+   hbV = cmpGEQ_VTS( seg2->vts, seg1->vts );
+   if (0) {
+      /* Crosscheck the vector-timestamp comparison result against that
+         obtained from the explicit graph approach.  Can be very
+         slow. */
+      hbG = happens_before_wrk( seg1, seg2 );
+   } else {
+      /* Assume the vector-timestamp comparison result is correct, and
+         use it as-is. */
+      hbG = hbV;
+   }
+
+   if (hbV != hbG) {
+      VG_(printf)("seg1 %p  seg2 %p  hbV %d  hbG %d\n", 
+                  seg1,seg2,(Int)hbV,(Int)hbG);
+      segments__generate_vcg();
+   }
+   tl_assert(hbV == hbG);
+
    iNSERT_POINT = (1*HBEFORE__N_CACHE)/4 - 1;
    /* if (iNSERT_POINT > 4) iNSERT_POINT = 4; */
 
@@ -1710,11 +2079,11 @@
    }
    hbefore__cache[iNSERT_POINT].segid1 = segid1;
    hbefore__cache[iNSERT_POINT].segid2 = segid2;
-   hbefore__cache[iNSERT_POINT].result = hb;
+   hbefore__cache[iNSERT_POINT].result = hbG;
 
    if (0)
    VG_(printf)("hb %d %d\n", (Int)segid1-(1<<24), (Int)segid2-(1<<24));
-   return hb;
+   return hbG;
 }
 
 /*--------------- generating .vcg output ---------------*/
@@ -1727,9 +2096,10 @@
          Green  -- thread creation, link to parent
          Red    -- thread exit, link to exiting thread
          Yellow -- signal edge
-         Ping   -- semaphore-up edge
+         Pink   -- semaphore-up edge
    */
    Segment* seg;
+   HChar vtsstr[128];
    VG_(printf)(PFX "graph: { title: \"Segments\"\n");
    VG_(printf)(PFX "orientation: top_to_bottom\n");
    VG_(printf)(PFX "height: 900\n");
@@ -1740,14 +2110,18 @@
    for (seg = admin_segments; seg; seg=seg->admin) {
 
       VG_(printf)(PFX "node: { title: \"%p\" color: lightcyan "
-                  "textcolor: darkgreen label: \"Seg %x\\n", 
+                  "textcolor: darkgreen label: \"Seg %p\\n", 
                   seg, seg);
       if (seg->thr->errmsg_index == 1) {
-         VG_(printf)("ROOT_THREAD\" }\n");
+         VG_(printf)("ROOT_THREAD");
       } else {
-         VG_(printf)("Thr# %d\" }\n", seg->thr->errmsg_index);
+         VG_(printf)("Thr# %d", seg->thr->errmsg_index);
       }
 
+      show_VTS( vtsstr, sizeof(vtsstr)-1, seg->vts );
+      vtsstr[sizeof(vtsstr)-1] = 0;
+
+      VG_(printf)("\\n%s\" }\n", vtsstr);
       if (seg->prev)
          VG_(printf)(PFX "edge: { sourcename: \"%p\" targetname: \"%p\""
                      "color: black }\n", seg->prev, seg );
@@ -1757,7 +2131,7 @@
             case 'c': colour = "darkgreen";  break; /* creation */
             case 'j': colour = "red";        break; /* join (exit) */
             case 's': colour = "orange";     break; /* signal */
-            case 'S': colour = "pink";       break; /* signal */
+            case 'S': colour = "pink";       break; /* sem_post->wait */
             case 'u': colour = "cyan";       break; /* unlock */
             default: tl_assert(0);
          }
@@ -1947,7 +2321,8 @@
 /*--- Sanity checking the data structures                      ---*/
 /*----------------------------------------------------------------*/
 
-static Bool is_sane_CacheLine ( CacheLine* cl );
+static Bool is_sane_CacheLine ( CacheLine* cl ); /* fwds */
+static Bool cmpGEQ_VTS ( XArray* a, XArray* b ); /* fwds */
 
 /* REQUIRED INVARIANTS:
 
@@ -2158,6 +2533,13 @@
    for (seg = admin_segments; seg; seg = seg->admin) {
       if (!is_sane_Segment(seg)) BAD("2");
       if (!is_sane_Thread(seg->thr)) BAD("3");
+      if (!seg->vts) BAD("4");
+      if (seg->prev && seg->prev->vts
+          && !cmpGEQ_VTS(seg->vts, seg->prev->vts))
+         BAD("5");
+      if (seg->other && seg->other->vts
+          && !cmpGEQ_VTS(seg->vts, seg->other->vts))
+         BAD("6");
    }
    return;
   bad:
@@ -3481,8 +3863,8 @@
       case 0: case 4:
          tl_assert(descr & TREE_DESCR_64);
          tree[4] = tree[0];
-        descr &= ~TREE_DESCR_64;
-        descr |= (TREE_DESCR_32_1 | TREE_DESCR_32_0);
+         descr &= ~TREE_DESCR_64;
+         descr |= (TREE_DESCR_32_1 | TREE_DESCR_32_0);
          break;
       default:
          tl_assert(0);
@@ -3495,7 +3877,7 @@
    switch (toff) {
       case 0: case 2:
          if (!(descr & TREE_DESCR_32_0)) {
-          descr = pulldown_to_32(tree, 0, descr);
+            descr = pulldown_to_32(tree, 0, descr);
          }
          tl_assert(descr & TREE_DESCR_32_0);
          tree[2] = tree[0];
@@ -3504,7 +3886,7 @@
          break;
       case 4: case 6:
          if (!(descr & TREE_DESCR_32_1)) {
-          descr = pulldown_to_32(tree, 4, descr);
+            descr = pulldown_to_32(tree, 4, descr);
          }
          tl_assert(descr & TREE_DESCR_32_1);
          tree[6] = tree[4];
@@ -4889,6 +5271,8 @@
          /* Make the child's new segment depend on the parent */
          seg_c->other = map_segments_lookup( thr_p->csegid );
          seg_c->other_hint = 'c';
+         seg_c->vts = tick_VTS( thr_c, seg_c->other->vts );
+         tl_assert(seg_c->prev == NULL);
          /* and start a new segment for the parent. */
          { SegmentID new_segid = 0; /* bogus */
            Segment*  new_seg   = NULL;
@@ -4896,6 +5280,8 @@
                                                thr_p );
            tl_assert(is_sane_SegmentID(new_segid));
            tl_assert(is_sane_Segment(new_seg));
+           new_seg->vts = tick_VTS( thr_p, new_seg->prev->vts );
+           tl_assert(new_seg->other == NULL);
          }
       }
    }
@@ -4965,6 +5351,9 @@
       tl_assert(new_seg->other == NULL);
       new_seg->other = map_segments_lookup( thr_q->csegid );
       new_seg->other_hint = 'j';
+      tl_assert(new_seg->thr == thr_s);
+      new_seg->vts = tickL_and_joinR_VTS( thr_s, new_seg->prev->vts,
+                                                 new_seg->other->vts );
    }
 
    // FIXME: error-if: exiting thread holds any locks
@@ -5394,6 +5783,8 @@
       tl_assert( is_sane_Segment(new_seg) );
       tl_assert( new_seg->thr == thr );
       tl_assert( is_sane_Segment(new_seg->prev) );
+      tl_assert( new_seg->prev->vts );
+      new_seg->vts = tick_VTS( new_seg->thr, new_seg->prev->vts );
 
       /* ... and add the binding. */
       TC_(addToFM)( map_cond_to_Segment, (Word)cond,
@@ -5460,8 +5851,15 @@
                              NULL, (Word*)&signalling_seg, (Word)cond );
       if (found) {
          tl_assert(is_sane_Segment(signalling_seg));
+         tl_assert(new_seg->prev);
+         tl_assert(new_seg->prev->vts);
          new_seg->other      = signalling_seg;
          new_seg->other_hint = 's';
+         tl_assert(new_seg->other->vts);
+         new_seg->vts = tickL_and_joinR_VTS( 
+                           new_seg->thr, 
+                           new_seg->prev->vts,
+                           new_seg->other->vts );
       } else {
          /* Hmm.  How can a wait on 'cond' succeed if nobody signalled
             it?  If this happened it would surely be a bug in the
@@ -5721,6 +6119,8 @@
       tl_assert( is_sane_Segment(new_seg) );
       tl_assert( new_seg->thr == thr );
       tl_assert( is_sane_Segment(new_seg->prev) );
+      tl_assert( new_seg->prev->vts );
+      new_seg->vts = tick_VTS( new_seg->thr, new_seg->prev->vts );
 
       /* ... and add the binding. */
       push_Segment_for_sem( sem, new_seg->prev );
@@ -5764,8 +6164,15 @@
       posting_seg = mb_pop_Segment_for_sem( sem );
       if (posting_seg) {
          tl_assert(is_sane_Segment(posting_seg));
+         tl_assert(new_seg->prev);
+         tl_assert(new_seg->prev->vts);
          new_seg->other      = posting_seg;
          new_seg->other_hint = 'S';
+         tl_assert(new_seg->other->vts);
+         new_seg->vts = tickL_and_joinR_VTS( 
+                           new_seg->thr, 
+                           new_seg->prev->vts,
+                           new_seg->other->vts );
       } else {
          /* Hmm.  How can a wait on 'sem' succeed if nobody posted to
             it?  If this happened it would surely be a bug in the


-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
Valgrind-developers mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/valgrind-developers

Reply via email to