[pypy-commit] stmgc use-gcc: fix some issues with finalizers

Raemi noreply at buildbot.pypy.org
Thu Aug 27 10:01:36 CEST 2015


Author: Remi Meier <remi.meier at inf.ethz.ch>
Branch: use-gcc
Changeset: r1947:187d67c77fd4
Date: 2015-08-27 10:05 +0200
http://bitbucket.org/pypy/stmgc/changeset/187d67c77fd4/

Log:	fix some issues with finalizers

diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -1365,9 +1365,10 @@
         stm_rewind_jmp_forget(STM_SEGMENT->running_thread);
     }
 
+    commit_finalizers();
+
     /* XXX do we still need a s_mutex_lock() section here? */
     s_mutex_lock();
-    commit_finalizers();
 
     /* update 'overflow_number' if needed */
     if (STM_PSEGMENT->overflow_number_has_been_used) {
diff --git a/c8/stm/finalizer.c b/c8/stm/finalizer.c
--- a/c8/stm/finalizer.c
+++ b/c8/stm/finalizer.c
@@ -29,6 +29,9 @@
 static void _commit_finalizers(void)
 {
     /* move finalizer lists to g_finalizers for major collections */
+    while (__sync_lock_test_and_set(&g_finalizers.lock, 1) != 0) {
+        spin_loop();
+    }
 
     if (STM_PSEGMENT->finalizers->run_finalizers != NULL) {
         /* copy 'STM_PSEGMENT->finalizers->run_finalizers' into
@@ -60,6 +63,8 @@
 
     free(STM_PSEGMENT->finalizers);
     STM_PSEGMENT->finalizers = NULL;
+
+    __sync_lock_release(&g_finalizers.lock);
 }
 
 static void abort_finalizers(struct stm_priv_segment_info_s *pseg)
@@ -389,7 +394,7 @@
 static void deal_with_objects_with_finalizers(void)
 {
     /* for non-light finalizers */
-
+    assert(_has_mutex());
     /* there is one 'objects_with_finalizers' list per segment.
        Objects that die at a major collection running in the same
        transaction as they were created will be put in the
@@ -495,23 +500,29 @@
 static void _invoke_general_finalizers(stm_thread_local_t *tl)
 {
     /* called between transactions */
-    static int lock = 0;
-
-    if (__sync_lock_test_and_set(&lock, 1) != 0) {
-        /* can't acquire the lock: someone else is likely already
-           running this function, so don't wait. */
-        return;
-    }
-
     rewind_jmp_buf rjbuf;
     stm_rewind_jmp_enterframe(tl, &rjbuf);
     _stm_start_transaction(tl);
+    /* XXX: become inevitable, bc. otherwise, we would need to keep
+       around the original g_finalizers.run_finalizers to restore it
+       in case of an abort. */
+    _stm_become_inevitable("finalizer-Tx");
 
-    fprintf(stderr, "run_finalizers: %lu\n", list_count(g_finalizers.run_finalizers));
-    _execute_finalizers(&g_finalizers);
+    while (__sync_lock_test_and_set(&g_finalizers.lock, 1) != 0) {
+        /* somebody is adding more finalizers (_commit_finalizer()) */
+        spin_loop();
+    }
+    struct finalizers_s copy = g_finalizers;
+    assert(copy.running_next == NULL);
+    g_finalizers.run_finalizers = NULL;
+    /* others may add to g_finalizers again: */
+    __sync_lock_release(&g_finalizers.lock);
+
+    fprintf(stderr, "run_finalizers: %lu\n", list_count(copy.run_finalizers));
+    _execute_finalizers(&copy);
 
     _stm_commit_transaction();
     stm_rewind_jmp_leaveframe(tl, &rjbuf);
 
-    __sync_lock_release(&lock);
+    LIST_FREE(copy.run_finalizers);
 }
diff --git a/c8/stm/finalizer.h b/c8/stm/finalizer.h
--- a/c8/stm/finalizer.h
+++ b/c8/stm/finalizer.h
@@ -1,5 +1,7 @@
 
+/* see deal_with_objects_with_finalizers() for explanation of these fields */
 struct finalizers_s {
+    long lock;
     struct list_s *objects_with_finalizers;
     uintptr_t count_non_young;
     struct list_s *run_finalizers;
diff --git a/c8/test/test_finalizer.py b/c8/test/test_finalizer.py
--- a/c8/test/test_finalizer.py
+++ b/c8/test/test_finalizer.py
@@ -273,59 +273,3 @@
         self.expect_finalized([])
         stm_major_collect()
         self.expect_finalized([lp1])
-
-
-class TestMoreRegularFinalizers(BaseTest):
-
-    def test_inevitable_in_finalizer(self):
-        lpo = stm_allocate_old(16)
-
-        self._first_time = True
-        @ffi.callback("void(object_t *)")
-        def finalizer(obj):
-            print "finalizing!", obj
-            stm_set_char(lpo, 'a')
-
-            if self._first_time:
-                self._first_time = False
-                # we will switch to the other TX and
-                # make it inevitable, so that our TX
-                # will abort on commit (or validate)
-                self.switch(0, validate=False)
-                self.become_inevitable()
-                self.switch(1, validate=False)
-
-        lib.stmcb_finalizer = finalizer
-        self._finalizer_keepalive = finalizer
-
-        # start a transaction with a finalizing obj
-        self.switch(1)
-        self.start_transaction()
-        lpf = stm_allocate_with_finalizer(16)
-
-        self.push_root(lpf)
-        stm_minor_collect()
-
-
-        self.switch(0)
-        self.start_transaction()
-        stm_set_char(lpo, 'x')
-        self.switch(1)
-        lpf = self.pop_root()
-        # commit this TX, start a new one, let lpf
-        # die with a major-gc:
-        self.commit_transaction()
-        self.start_transaction()
-        stm_major_collect()
-        # commit and run finalizer in separate TX
-        # that will abort because of a conflict
-        self.commit_transaction()
-
-        self.switch(0, validate=False)
-        assert stm_get_char(lpo) == 'x'
-        # commit the now-inevitable TX and run
-        # the aborted finalizer again
-        self.commit_transaction()
-        self.start_transaction()
-        # should now see the value set by finalizer
-        assert stm_get_char(lpo) == 'a'


More information about the pypy-commit mailing list