[pypy-commit] stmgc default: stm_clear_on_abort(): move the thread-local variables into the

arigo noreply at buildbot.pypy.org
Sat Sep 7 18:12:27 CEST 2013


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r523:4c80cba2b8ce
Date: 2013-09-07 17:19 +0200
http://bitbucket.org/pypy/stmgc/changeset/4c80cba2b8ce/

Log:	stm_clear_on_abort(): move the thread-local variables into the
	tx_descriptor structure.

	Add stm_call_on_abort() for invoking callbacks (like free()) if the
	current transaction is aborted.

diff --git a/c4/et.c b/c4/et.c
--- a/c4/et.c
+++ b/c4/et.c
@@ -986,8 +986,12 @@
   spinlock_release(d->public_descriptor->collection_lock);
 
   /* clear memory registered by stm_clear_on_abort */
-  if (stm_to_clear_on_abort)
-    memset(stm_to_clear_on_abort, 0, stm_bytes_to_clear_on_abort);
+  if (d->mem_clear_on_abort)
+    memset(d->mem_clear_on_abort, 0, d->mem_bytes_to_clear_on_abort);
+
+  /* invoke the callbacks registered by stm_call_on_abort */
+  stm_invoke_callbacks_on_abort(d);
+  stm_clear_callbacks_on_abort(d);
 
   dprintf(("\n"
           "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n"
@@ -1482,6 +1486,10 @@
   d->num_commits++;
   d->active = 0;
   stm_stop_sharedlock();
+
+  /* clear the list of callbacks that would have been called
+     on abort */
+  stm_clear_callbacks_on_abort(d);
 }
 
 /************************************************************/
diff --git a/c4/et.h b/c4/et.h
--- a/c4/et.h
+++ b/c4/et.h
@@ -183,6 +183,9 @@
   struct tx_descriptor *tx_prev, *tx_next;
   int tcolor;
   pthread_t pthreadid;
+  void *mem_clear_on_abort;
+  size_t mem_bytes_to_clear_on_abort;
+  struct G2L callbacks_on_abort;
 };
 
 extern __thread struct tx_descriptor *thread_descriptor;
diff --git a/c4/extra.c b/c4/extra.c
--- a/c4/extra.c
+++ b/c4/extra.c
@@ -14,13 +14,46 @@
 }
 
 
-__thread void *stm_to_clear_on_abort = NULL;
-__thread size_t stm_bytes_to_clear_on_abort;
-
 void stm_clear_on_abort(void *start, size_t bytes)
 {
-    stm_to_clear_on_abort = start;
-    stm_bytes_to_clear_on_abort = bytes;
+    struct tx_descriptor *d = thread_descriptor;
+    assert(d != NULL);
+    d->mem_clear_on_abort = start;
+    d->mem_bytes_to_clear_on_abort = bytes;
+}
+
+void stm_call_on_abort(void *key, void callback(void *))
+{
+    struct tx_descriptor *d = thread_descriptor;
+    if (callback == NULL) {
+        /* ignore the return value: unregistered keys can be
+           "deleted" again */
+        g2l_delete_item(&d->callbacks_on_abort, (gcptr)key);
+    }
+    else {
+        /* double-registering the same key will crash */
+        g2l_insert(&d->callbacks_on_abort, (gcptr)key, (gcptr)callback);
+    }
+}
+
+void stm_clear_callbacks_on_abort(struct tx_descriptor *d)
+{
+    if (g2l_any_entry(&d->callbacks_on_abort))
+        g2l_clear(&d->callbacks_on_abort);
+}
+
+void stm_invoke_callbacks_on_abort(struct tx_descriptor *d)
+{
+    wlog_t *item;
+    G2L_LOOP_FORWARD(d->callbacks_on_abort, item) {
+        void *key = (void *)item->addr;
+        void (*callback)(void *) = (void(*)(void *))item->val;
+        assert(key != NULL);
+        assert(callback != NULL);
+
+        callback(key);
+
+    } G2L_LOOP_END;
 }
 
 
diff --git a/c4/extra.h b/c4/extra.h
--- a/c4/extra.h
+++ b/c4/extra.h
@@ -17,5 +17,7 @@
 size_t stm_decode_abort_info(struct tx_descriptor *d, long long elapsed_time,
                              int abort_reason, struct tx_abort_info *output);
 void stm_visit_abort_info(struct tx_descriptor *d, void (*visit)(gcptr *));
+void stm_clear_callbacks_on_abort(struct tx_descriptor *d);
+void stm_invoke_callbacks_on_abort(struct tx_descriptor *d);
 
 #endif
diff --git a/c4/gcpage.c b/c4/gcpage.c
--- a/c4/gcpage.c
+++ b/c4/gcpage.c
@@ -207,7 +207,8 @@
         //stm_dbgmem_not_used(obj, size_class * WORD, 0);
     }
     else {
-        g2l_delete_item(&gcp->nonsmall_objects, obj);
+        int deleted = g2l_delete_item(&gcp->nonsmall_objects, obj);
+        assert(deleted);
         stm_free(obj);
     }
 }
@@ -234,7 +235,8 @@
     assert(obj->h_tid & GCFLAG_PUBLIC);
 
     stmgcpage_acquire_global_lock();
-    g2l_delete_item(&registered_stubs, obj);
+    int deleted = g2l_delete_item(&registered_stubs, obj);
+    assert(deleted);
     stmgcpage_release_global_lock();
     dprintf(("unregistered %p\n", obj));
 }
diff --git a/c4/lists.c b/c4/lists.c
--- a/c4/lists.c
+++ b/c4/lists.c
@@ -132,15 +132,15 @@
   *(char **)p = (char *)wlog;
 }
 
-void g2l_delete_item(struct G2L *g2l, gcptr addr)
+int g2l_delete_item(struct G2L *g2l, gcptr addr)
 {
     wlog_t *entry;
     G2L_FIND(*g2l, addr, entry, goto missing);
     entry->addr = NULL;
-    return;
+    return 1;
 
  missing:
-    stm_fatalerror("g2l_delete_item: item %p not in dict", addr);
+    return 0;
 }
 
 /************************************************************/
diff --git a/c4/lists.h b/c4/lists.h
--- a/c4/lists.h
+++ b/c4/lists.h
@@ -113,7 +113,7 @@
 wlog_t *_g2l_find(char *entry, gcptr addr);
 void _g2l_compress(struct G2L *g2l);
 void g2l_insert(struct G2L *g2l, gcptr addr, gcptr val);
-void g2l_delete_item(struct G2L *g2l, gcptr addr);
+int g2l_delete_item(struct G2L *g2l, gcptr addr);
 
 static inline int g2l_contains(struct G2L *g2l, gcptr addr)
 {
diff --git a/c4/stmgc.h b/c4/stmgc.h
--- a/c4/stmgc.h
+++ b/c4/stmgc.h
@@ -175,10 +175,14 @@
 
 /* Clear some memory when aborting a transaction in the current
    thread. This is a provisional API. The information is stored
-   thread-locally and belongs to the current thread. */
+   in the current tx_descriptor. */
 void stm_clear_on_abort(void *start, size_t bytes);
-extern __thread void *stm_to_clear_on_abort;
-extern __thread size_t stm_bytes_to_clear_on_abort;
+
+/* 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. */
+void stm_call_on_abort(void *key, void callback(void *));
 
 /* only user currently is stm_allocate_public_integer_address() */
 void stm_register_integer_address(intptr_t);
diff --git a/c4/test/support.py b/c4/test/support.py
--- a/c4/test/support.py
+++ b/c4/test/support.py
@@ -128,6 +128,7 @@
     void stm_initialize_tests(int max_aborts);
 
     void stm_clear_on_abort(void *start, size_t bytes);
+    void stm_call_on_abort(void *key, void callback(void *));
 
     /* some constants normally private that are useful in the tests */
     #define WORD                     ...
diff --git a/c4/test/test_extra.py b/c4/test/test_extra.py
--- a/c4/test/test_extra.py
+++ b/c4/test/test_extra.py
@@ -269,3 +269,42 @@
             assert p[2] == 'l'
             assert p[3] == 'l'
             assert p[4] == 'o'
+
+def test_call_on_abort():
+    p0 = ffi.new("char[]", "aaa")
+    p1 = ffi.new("char[]", "hello")
+    p2 = ffi.new("char[]", "removed")
+    p3 = ffi.new("char[]", "world")
+    #
+    @ffi.callback("void(void *)")
+    def clear_me(p):
+        p = ffi.cast("char *", p)
+        p[0] = chr(ord(p[0]) + 1)
+    #
+    lib.stm_call_on_abort(p0, clear_me)
+    # the registered callbacks are removed on
+    # successful commit
+    lib.stm_commit_transaction()
+    lib.stm_begin_inevitable_transaction()
+    #
+    @perform_transaction
+    def run(retry_counter):
+        if retry_counter == 0:
+            lib.stm_call_on_abort(p1, clear_me)
+            lib.stm_call_on_abort(p2, clear_me)
+            lib.stm_call_on_abort(p3, clear_me)
+            lib.stm_call_on_abort(p2, ffi.NULL)
+        #
+        assert ffi.string(p0) == "aaa"
+        assert ffi.string(p2) == "removed"
+        if retry_counter == 0:
+            assert ffi.string(p1) == "hello"
+            assert ffi.string(p3) == "world"
+            abort_and_retry()
+        else:
+            assert ffi.string(p1) == "iello"
+            assert ffi.string(p3) == "xorld"
+            if retry_counter == 1:
+                # the registered callbacks are removed
+                # on abort
+                abort_and_retry()


More information about the pypy-commit mailing list