[pypy-commit] pypy stm-thread-2: Attempt again to fix stm_PtrEq().

arigo noreply at buildbot.pypy.org
Mon Feb 25 19:00:45 CET 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: stm-thread-2
Changeset: r61766:3172187f8470
Date: 2013-02-25 18:58 +0100
http://bitbucket.org/pypy/pypy/changeset/3172187f8470/

Log:	Attempt again to fix stm_PtrEq().

diff --git a/rpython/translator/stm/src_stm/et.c b/rpython/translator/stm/src_stm/et.c
--- a/rpython/translator/stm/src_stm/et.c
+++ b/rpython/translator/stm/src_stm/et.c
@@ -748,65 +748,66 @@
 
 inline static _Bool _PtrEq_Globals(gcptr G1, gcptr G2)
 {
-  /* This is a bit lengthy, but (probably) efficient: the idea is to
-     check if G1 and G2 are pointers in the same chained list of globals
-     or not.  Assumes no partial sharing in the chained lists.  Works by
-     trying to search forward with S1, starting from G1, if it reaches
-     G2; and conversely with S2, starting from G2, if it reaches G1. */
-  gcptr S1 = G1, S2 = G2;
+  /* This is a mess, because G1 and G2 can be different pointers to "the
+     same" object, and it's hard to determine that.  Description of the
+     idealized problem: we have chained lists following the 'h_revision'
+     field from G1 and from G2, and we must return True if the chained
+     lists end in the same object G and False if they don't.
+
+     It's possible that G1 != G2 but G1->h_revision == G2->h_revision.
+     This occurs because of random updates done by PossiblyUpdateChain().
+
+     But the real mess comes from other threads doing concurrent
+     updates.  They can be either done by PossiblyUpdateChain() from
+     other threads, changing 'h_revision' without warning to point to
+     what used to be 'h_revision-> ... -> h_revision'.  Alternatively,
+     they can be adding new objects to the so-far root of the tree:
+     consider the G that used to be the end of both chained lists.  Its
+     'h_revision' used to be not-a-pointer.  But it can suddenly
+     suddenly turns into a LOCK value, and then later to a pointer to
+     some new object, making the chained list longer.  Worse, once the
+     list is longer, a PossiblyUpdateChain() might make shortcuts in
+     it...
+
+     So it means even the following algorithm is flawed: "follow
+     h_revisions from G1 until we reach G; then follow h_revisions from
+     G2, and return True/False if we reach/do not reach the same G".
+
+     For now we go with: try to move forward G1 and G2 alternatively,
+     until we failed three times to move forward one of these.  Let's
+     say the last three steps were "G1 is already at the end", "G2 is
+     already at the end", "G1 is already at the end".  Then we can
+     return (G1 == G2).  This is because we know that G1 was at the end
+     of the chained list for the whole time during which we checked G2.
+
+     WARNING: THIS ONLY WORKS ON THE X86 MEMORY MODEL, AND NOT ON WEAKER
+     MODELS!
+  */
+  int blocked_steps = 0;
   volatile revision_t *vp;
   revision_t v;
+  gcptr G3;
 
   while (1)
     {
-      if (S2 == G1)
-        return 1;
-
-      /* move forward S1 */
-      vp = (volatile revision_t *)&S1->h_revision;
+      /* try to move G1 forward */
+      vp = (volatile revision_t *)&G1->h_revision;
       v = *vp;
-      if (v & 1)  // "is not a pointer", i.e.
-        goto s1_end;   // "doesn't have a more recent revision"
-      S1 = (gcptr)v;
-
-      if (S1 == G2)
-        return 1;
-
-      /* move forward S2 */
-      vp = (volatile revision_t *)&S2->h_revision;
-      v = *vp;
-      if (v & 1)  // "is not a pointer", i.e.
-        goto s2_end;   // "doesn't have a more recent revision"
-      S2 = (gcptr)v;
+      if (v & 1)
+        {
+          blocked_steps++;
+          if (blocked_steps == 3)
+            break;
+        }
+      else
+        {
+          G1 = (gcptr)v;    /* success */
+          blocked_steps = 0;
+        }
+      /* swap the roles of G1 and G2, then loop */
+      G3 = G1; G1 = G2; G2 = G3;
     }
-
- s1_end:
-  while (1)
-    {
-      /* move forward S2 */
-      vp = (volatile revision_t *)&S2->h_revision;
-      v = *vp;
-      if (v & 1)  // "is not a pointer", i.e.
-        return 0;      // "doesn't have a more recent revision"
-      S2 = (gcptr)v;
-
-      if (S2 == G1)
-        return 1;
-    }
-
- s2_end:
-  while (1)
-    {
-      /* move forward S1 */
-      vp = (volatile revision_t *)&S1->h_revision;
-      v = *vp;
-      if (v & 1)  // "is not a pointer", i.e.
-        return 0;      // "doesn't have a more recent revision"
-      S1 = (gcptr)v;
-
-      if (S1 == G2)
-        return 1;
-    }
+  return G1 == G2;
 }
 
 _Bool stm_PtrEq(gcptr P1, gcptr P2)


More information about the pypy-commit mailing list