[pypy-commit] extradoc extradoc: Finish the first version of inevitable transactions

arigo noreply at buildbot.pypy.org
Sun Aug 26 09:26:38 CEST 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: extradoc
Changeset: r4725:c90748a61893
Date: 2012-08-26 09:25 +0200
http://bitbucket.org/pypy/extradoc/changeset/c90748a61893/

Log:	Finish the first version of inevitable transactions

diff --git a/talk/stm2012/stmimpl.rst b/talk/stm2012/stmimpl.rst
--- a/talk/stm2012/stmimpl.rst
+++ b/talk/stm2012/stmimpl.rst
@@ -392,7 +392,7 @@
 modified since ``start_time``::
 
     def ValidateDuringTransaction():
-        start_time = global_cur_time    # copy from the global time
+        start_time = GetGlobalCurTime() # copy from the global time
         for R in list_of_read_objects:
             if not (R->h_revision & 1): # "is a pointer", i.e.
                 AbortTransaction()      #   "has a more recent revision"
@@ -500,11 +500,13 @@
 In pseudo-code::
 
     def CommitTransaction():
+        # (see below for the full version with inevitable transactions)
         AcquireLocks()
         cur_time = global_cur_time
         while not CMPXCHG(&global_cur_time, cur_time, cur_time + 1):
             cur_time = global_cur_time    # try again
-        ValidateDuringCommit()
+        if cur_time != start_time:
+            ValidateDuringCommit()   # only call it if needed
         UpdateChainHeads(cur_time)
 
 Note the general style of usage of CMPXCHG: we first read normally the
@@ -557,10 +559,13 @@
 done by writing back the original timestamps in the ``h_revision``
 fields::
 
-    def AbortTransaction():
+    def CancelLocks():
         for (R, L, v) in gcroots:
             if v != 0:
                 R->h_revision = v
+
+    def AbortTransaction():
+        CancelLocks()
         # call longjmp(), which is the function from C
         # going back to the transaction start
         longjmp()
@@ -622,6 +627,7 @@
 (attempt to) make the current transaction inevitable::
 
     def BecomeInevitable():
+        inevitable_mutex.acquire()
         cur_time = global_cur_time
         while not CMPXCHG(&global_cur_time, cur_time, INEVITABLE):
             cur_time = global_cur_time    # try again
@@ -634,6 +640,46 @@
         for R in list_of_read_objects:
             if not (R->h_revision & 1):
                 global_cur_time = t     # must restore the value
+                inevitable_mutex.release()
                 AbortTransaction()
 
-...
+We use a normal OS mutex to allow other threads to really sleep instead
+of spin-looping until the inevitable transaction finishes.  So the
+function ``GetGlobalCurTime`` is defined to return ``global_cur_time``
+after waiting for other inevitable transaction to finish::
+
+    def GetGlobalCurTime():
+        assert not is_inevitable    # must not be myself inevitable
+        t = global_cur_time
+        if t == INEVITABLE:         # there is another inevitable tr.?
+            inevitable_mutex.acquire()   # wait
+            inevitable_mutex.release()
+            return GetGlobalCurTime()    # retry
+        return t
+
+Then we extend ``CommitTransaction`` for inevitable support::
+
+    def CommitTransaction():
+        AcquireLocks()
+        if is_inevitable:
+            cur_time = start_time
+            if not CMPXCHG(&global_cur_time, INEVITABLE, cur_time + 1):
+                unreachable: no other thread changed global_cur_time
+            inevitable_mutex.release()
+        else:
+            cur_time = GetGlobalCurTimeInCommit()
+            while not CMPXCHG(&global_cur_time, cur_time, cur_time + 1):
+                cur_time = GetGlobalCurTimeInCommit()  # try again
+            if cur_time != start_time:
+                ValidateDuringCommit()   # only call it if needed
+        UpdateChainHeads(cur_time)
+
+    def GetGlobalCurTimeInCommit():
+        t = global_cur_time
+        if t == INEVITABLE:
+            CancelLocks()
+            inevitable_mutex.acquire()   # wait until released
+            inevitable_mutex.release()
+            AcquireLocks()
+            return GetGlobalCurTimeInCommit()
+        return t


More information about the pypy-commit mailing list