[pypy-commit] stmgc default: Add a return value to stm_call_on_xxx() to know if a call with NULL

arigo noreply at buildbot.pypy.org
Tue Aug 19 19:05:24 CEST 2014


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r1320:bea13491352f
Date: 2014-08-19 18:52 +0200
http://bitbucket.org/pypy/stmgc/changeset/bea13491352f/

Log:	Add a return value to stm_call_on_xxx() to know if a call with NULL
	really cancelled something or not.

diff --git a/c7/stm/extra.c b/c7/stm/extra.c
--- a/c7/stm/extra.c
+++ b/c7/stm/extra.c
@@ -3,50 +3,51 @@
 #endif
 
 
-static bool register_callbacks(stm_thread_local_t *tl,
+static long register_callbacks(stm_thread_local_t *tl,
                                void *key, void callback(void *), long index)
 {
     if (!_stm_in_transaction(tl)) {
         /* check that the current thread-local is really running a
            transaction, and do nothing otherwise. */
-        return false;
+        return -1;
     }
 
     if (STM_PSEGMENT->transaction_state == TS_INEVITABLE) {
         /* ignore callbacks if we're in an inevitable transaction
            (which cannot abort) */
-        return false;
+        return -1;
     }
 
     struct tree_s *callbacks;
     callbacks = STM_PSEGMENT->callbacks_on_commit_and_abort[index];
 
     if (callback == NULL) {
-        /* ignore the return value: unregistered keys can be
-           "deleted" again */
-        tree_delete_item(callbacks, (uintptr_t)key);
+        /* double-unregistering works, but return 0 */
+        return tree_delete_item(callbacks, (uintptr_t)key);
     }
     else {
         /* double-registering the same key will crash */
         tree_insert(callbacks, (uintptr_t)key, (uintptr_t)callback);
+        return 1;
     }
-    return true;
 }
 
-void stm_call_on_commit(stm_thread_local_t *tl,
+long stm_call_on_commit(stm_thread_local_t *tl,
                        void *key, void callback(void *))
 {
-    if (!register_callbacks(tl, key, callback, 0)) {
+    long result = register_callbacks(tl, key, callback, 0);
+    if (result < 0 && callback != NULL) {
         /* no regular transaction running, invoke the callback
            immediately */
         callback(key);
     }
+    return result;
 }
 
-void stm_call_on_abort(stm_thread_local_t *tl,
+long stm_call_on_abort(stm_thread_local_t *tl,
                        void *key, void callback(void *))
 {
-    register_callbacks(tl, key, callback, 1);
+    return register_callbacks(tl, key, callback, 1);
 }
 
 static void invoke_and_clear_user_callbacks(long index)
diff --git a/c7/stmgc.h b/c7/stmgc.h
--- a/c7/stmgc.h
+++ b/c7/stmgc.h
@@ -412,15 +412,16 @@
 /* If the current transaction aborts later, invoke 'callback(key)'.  If
    the current transaction commits, then the callback is forgotten.  You
    can only register one callback per key.  You can call
-   'stm_call_on_abort(key, NULL)' to cancel an existing callback.
+   'stm_call_on_abort(key, NULL)' to cancel an existing callback
+   (returns 0 if there was no existing callback to cancel).
    Note: 'key' must be aligned to a multiple of 8 bytes. */
-void stm_call_on_abort(stm_thread_local_t *, void *key, void callback(void *));
+long stm_call_on_abort(stm_thread_local_t *, void *key, void callback(void *));
 
 /* If the current transaction commits later, invoke 'callback(key)'.  If
    the current transaction aborts, then the callback is forgotten.  Same
    restrictions as stm_call_on_abort().  If the transaction is or becomes
    inevitable, 'callback(key)' is called immediately. */
-void stm_call_on_commit(stm_thread_local_t *, void *key, void callback(void *));
+long stm_call_on_commit(stm_thread_local_t *, void *key, void callback(void *));
 
 
 /* Similar to stm_become_inevitable(), but additionally suspend all
diff --git a/c7/test/support.py b/c7/test/support.py
--- a/c7/test/support.py
+++ b/c7/test/support.py
@@ -109,9 +109,9 @@
 long stm_id(object_t *obj);
 void stm_set_prebuilt_identityhash(object_t *obj, uint64_t hash);
 
-int stm_can_move(object_t *);
-void stm_call_on_abort(stm_thread_local_t *, void *key, void callback(void *));
-void stm_call_on_commit(stm_thread_local_t *, void *key, void callback(void *));
+long stm_can_move(object_t *);
+long stm_call_on_abort(stm_thread_local_t *, void *key, void callback(void *));
+long stm_call_on_commit(stm_thread_local_t *, void *key, void callback(void *));
 
 #define STM_TIME_OUTSIDE_TRANSACTION ...
 #define STM_TIME_RUN_CURRENT ...
diff --git a/c7/test/test_extra.py b/c7/test/test_extra.py
--- a/c7/test/test_extra.py
+++ b/c7/test/test_extra.py
@@ -32,6 +32,7 @@
         p1 = ffi_new_aligned("hello")
         p2 = ffi_new_aligned("removed")
         p3 = ffi_new_aligned("world")
+        p4 = ffi_new_aligned("00")
         #
         @ffi.callback("void(void *)")
         def clear_me(p):
@@ -39,17 +40,26 @@
             p[0] = chr(ord(p[0]) + 1)
         #
         self.start_transaction()
-        lib.stm_call_on_abort(self.get_stm_thread_local(), p0, clear_me)
+        x = lib.stm_call_on_abort(self.get_stm_thread_local(), p0, clear_me)
+        assert x != 0
         # the registered callbacks are removed on
         # successful commit
         self.commit_transaction()
         assert ffi.string(p0) == "aaa"
         #
         self.start_transaction()
-        lib.stm_call_on_abort(self.get_stm_thread_local(), p1, clear_me)
-        lib.stm_call_on_abort(self.get_stm_thread_local(), p2, clear_me)
-        lib.stm_call_on_abort(self.get_stm_thread_local(), p3, clear_me)
-        lib.stm_call_on_abort(self.get_stm_thread_local(), p2, ffi.NULL)
+        x = lib.stm_call_on_abort(self.get_stm_thread_local(), p1, clear_me)
+        assert x != 0
+        x = lib.stm_call_on_abort(self.get_stm_thread_local(), p2, clear_me)
+        assert x != 0
+        x = lib.stm_call_on_abort(self.get_stm_thread_local(), p3, clear_me)
+        assert x != 0
+        x = lib.stm_call_on_abort(self.get_stm_thread_local(), p2, ffi.NULL)
+        assert x != 0
+        x = lib.stm_call_on_abort(self.get_stm_thread_local(), p2, ffi.NULL)
+        assert x == 0
+        x = lib.stm_call_on_abort(self.get_stm_thread_local(), p4, ffi.NULL)
+        assert x == 0
         assert ffi.string(p0) == "aaa"
         assert ffi.string(p1) == "hello"
         assert ffi.string(p2) == "removed"
@@ -68,6 +78,7 @@
         assert ffi.string(p1) == "iello"
         assert ffi.string(p2) == "removed"
         assert ffi.string(p3) == "xorld"
+        assert ffi.string(p4) == "00"
 
     def test_ignores_if_outside_transaction(self):
         @ffi.callback("void(void *)")
@@ -76,7 +87,8 @@
         #
         seen = []
         p0 = ffi_new_aligned("aaa")
-        lib.stm_call_on_abort(self.get_stm_thread_local(), p0, dont_see_me)
+        x = lib.stm_call_on_abort(self.get_stm_thread_local(), p0, dont_see_me)
+        assert x != 0
         self.start_transaction()
         self.abort_transaction()
         assert seen == []
@@ -86,6 +98,7 @@
         p1 = ffi_new_aligned("hello")
         p2 = ffi_new_aligned("removed")
         p3 = ffi_new_aligned("world")
+        p4 = ffi_new_aligned("00")
         #
         @ffi.callback("void(void *)")
         def clear_me(p):
@@ -93,16 +106,25 @@
             p[0] = chr(ord(p[0]) + 1)
         #
         self.start_transaction()
-        lib.stm_call_on_commit(self.get_stm_thread_local(), p0, clear_me)
+        x = lib.stm_call_on_commit(self.get_stm_thread_local(), p0, clear_me)
+        assert x != 0
         # the registered callbacks are not called on abort
         self.abort_transaction()
         assert ffi.string(p0) == "aaa"
         #
         self.start_transaction()
-        lib.stm_call_on_commit(self.get_stm_thread_local(), p1, clear_me)
-        lib.stm_call_on_commit(self.get_stm_thread_local(), p2, clear_me)
-        lib.stm_call_on_commit(self.get_stm_thread_local(), p3, clear_me)
-        lib.stm_call_on_commit(self.get_stm_thread_local(), p2, ffi.NULL)
+        x = lib.stm_call_on_commit(self.get_stm_thread_local(), p1, clear_me)
+        assert x != 0
+        x = lib.stm_call_on_commit(self.get_stm_thread_local(), p2, clear_me)
+        assert x != 0
+        x = lib.stm_call_on_commit(self.get_stm_thread_local(), p3, clear_me)
+        assert x != 0
+        x = lib.stm_call_on_commit(self.get_stm_thread_local(), p2, ffi.NULL)
+        assert x != 0
+        x = lib.stm_call_on_commit(self.get_stm_thread_local(), p2, ffi.NULL)
+        assert x == 0
+        x = lib.stm_call_on_commit(self.get_stm_thread_local(), p4, ffi.NULL)
+        assert x == 0
         assert ffi.string(p0) == "aaa"
         assert ffi.string(p1) == "hello"
         assert ffi.string(p2) == "removed"
@@ -113,6 +135,7 @@
         assert ffi.string(p1) == "iello"
         assert ffi.string(p2) == "removed"
         assert ffi.string(p3) == "xorld"
+        assert ffi.string(p4) == "00"
 
     def test_call_on_commit_immediately_if_inevitable(self):
         p0 = ffi_new_aligned("aaa")


More information about the pypy-commit mailing list