Author: Remi Meier <[email protected]>
Branch: finalizer-queues
Changeset: r2000:ceda93abb51f
Date: 2016-11-17 10:39 +0100
http://bitbucket.org/pypy/stmgc/changeset/ceda93abb51f/

Log:    re-introduce running finalizers within a regular transaction

diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -1206,6 +1206,8 @@
 
 static void _core_commit_transaction(bool external)
 {
+    exec_local_finalizers();
+
     assert(!_has_mutex());
     assert(STM_PSEGMENT->safe_point == SP_RUNNING);
     assert(STM_PSEGMENT->transaction_state != TS_NONE);
diff --git a/c8/stm/finalizer.c b/c8/stm/finalizer.c
--- a/c8/stm/finalizer.c
+++ b/c8/stm/finalizer.c
@@ -18,6 +18,7 @@
     f->probably_young_objects_with_finalizers = list_create();
     f->run_finalizers = list_create();
     f->running_next = NULL;
+    f->lock = 0;
 }
 
 static void setup_finalizer(void)
@@ -493,6 +494,68 @@
         getfield on *dying obj*).
 */
 
+static bool _trigger_finalizer_queues(struct finalizers_s *f)
+{
+    /* runs triggers of finalizer queues that have elements in the queue. May
+       run outside of a transaction, as triggers should be safe to call(?)
+
+       returns true if there are old-style finalizers to run */
+
+    bool trigger_oldstyle = false;
+    bool *to_trigger = calloc(g_finalizer_triggers.count, sizeof(bool));
+
+    while (__sync_lock_test_and_set(&f->lock, 1) != 0) {
+        /* somebody is adding more finalizers (_commit_finalizer()) */
+        stm_spin_loop();
+    }
+
+    int count = list_count(f->run_finalizers);
+    for (int i = 0; i < count; i += 2) {
+        int qindex = (int)list_item(f->run_finalizers, i + 1);
+        dprintf(("qindex=%d\n", qindex));
+        if (qindex == -1)
+            trigger_oldstyle = true;
+        else
+            to_trigger[qindex] = true;
+    }
+
+    __sync_lock_release(&f->lock);
+
+    // trigger now:
+    for (int i = 0; i < g_finalizer_triggers.count; i++) {
+        if (to_trigger[i]) {
+            dprintf(("invoke-finalizer-trigger(qindex=%d)\n", i));
+            // XXX: check that triggers *really* cannot touch GC-memory,
+            // otherwise, this needs to run in an (inevitable) transaction
+#ifndef NDEBUG
+            set_gs_register(NULL);
+#endif
+            g_finalizer_triggers.triggers[i]();
+        }
+    }
+
+    free(to_trigger);
+
+    return trigger_oldstyle;
+}
+
+static void _invoke_local_finalizers()
+{
+    /* called inside a transaction; invoke local triggers, process old-style
+     * local finalizers */
+    dprintf(("invoke_local_finalizers %lu\n", 
list_count(STM_PSEGMENT->finalizers->run_finalizers)));
+    if (list_is_empty(STM_PSEGMENT->finalizers->run_finalizers))
+        return;
+
+    if (!_trigger_finalizer_queues(STM_PSEGMENT->finalizers))
+        return; // no oldstyle to run
+
+    object_t *obj;
+    while ((obj = stm_next_to_finalize(-1)) != NULL) {
+        stmcb_finalizer(obj);
+    }
+}
+
 
 static void _invoke_general_finalizers(stm_thread_local_t *tl)
 {
@@ -503,38 +566,8 @@
     if (list_is_empty(g_finalizers.run_finalizers))
         return;
 
-    bool *to_trigger = calloc(g_finalizer_triggers.count + 1, sizeof(bool));
-
-    while (__sync_lock_test_and_set(&g_finalizers.lock, 1) != 0) {
-        /* somebody is adding more finalizers (_commit_finalizer()) */
-        stm_spin_loop();
-    }
-
-    int count = list_count(g_finalizers.run_finalizers);
-    for (int i = 0; i < count; i += 2) {
-        int qindex = (int)list_item(g_finalizers.run_finalizers, i + 1);
-        to_trigger[qindex + 1] = true; // also for -1!
-    }
-
-    __sync_lock_release(&g_finalizers.lock);
-
-    // trigger now:
-    for (int i = 1; i < g_finalizer_triggers.count; i++) {
-        if (to_trigger[i]) {
-            dprintf(("invoke-finalizer-trigger(qindex=%d)\n", i));
-            // XXX: check that triggers *really* cannot touch GC-memory,
-            // otherwise, this needs to run in an (inevitable) transaction
-            g_finalizer_triggers.triggers[i - 1]();
-        }
-    }
-
-    if (!to_trigger[0]) {
-        // 0 is the qindex for old-style finalizers,
-        // so nothing todo here.
-        free(to_trigger);
-        return;
-    }
-    free(to_trigger);
+    if (!_trigger_finalizer_queues(&g_finalizers))
+        return; // no oldstyle finalizers to run
 
     // run old-style finalizers:
     dprintf(("invoke-oldstyle-finalizers\n"));
@@ -553,6 +586,29 @@
 }
 
 object_t* stm_next_to_finalize(int queue_index) {
+    /* first check local run_finalizers queue, then global */
+    if (!list_is_empty(STM_PSEGMENT->finalizers->run_finalizers)) {
+        struct list_s *lst = STM_PSEGMENT->finalizers->run_finalizers;
+        int count = list_count(lst);
+        for (int i = 0; i < count; i += 2) {
+            int qindex = (int)list_item(lst, i + 1);
+            if (qindex == queue_index) {
+                /* no need to become inevitable for local ones */
+                /* Remove obj from list and return it. */
+                object_t *obj = (object_t*)list_item(lst, i);
+                if (i < count - 2) {
+                    memmove(&lst->items[i],
+                            &lst->items[i + 2],
+                            (count - 2) * sizeof(uintptr_t));
+                }
+                lst->count -= 2;
+                return obj;
+            }
+        }
+    }
+
+    /* no local finalizers found, continue in global list */
+
     while (__sync_lock_test_and_set(&g_finalizers.lock, 1) != 0) {
         /* somebody is adding more finalizers (_commit_finalizer()) */
         stm_spin_loop();
diff --git a/c8/stm/finalizer.h b/c8/stm/finalizer.h
--- a/c8/stm/finalizer.h
+++ b/c8/stm/finalizer.h
@@ -38,9 +38,16 @@
 
 
 static void _invoke_general_finalizers(stm_thread_local_t *tl);
+static void _invoke_local_finalizers(void);
 
 #define invoke_general_finalizers(tl)    do {   \
      _invoke_general_finalizers(tl);         \
 } while (0)
 
+
+#define exec_local_finalizers()  do {                   \
+    if (!list_is_empty(STM_PSEGMENT->finalizers->run_finalizers)) \
+        _invoke_local_finalizers();  \
+} while (0)
+
 #endif
diff --git a/c8/stm/gcpage.c b/c8/stm/gcpage.c
--- a/c8/stm/gcpage.c
+++ b/c8/stm/gcpage.c
@@ -213,6 +213,7 @@
     }
 
     s_mutex_unlock();
+    exec_local_finalizers();
 }
 
 
diff --git a/c8/stm/sync.c b/c8/stm/sync.c
--- a/c8/stm/sync.c
+++ b/c8/stm/sync.c
@@ -311,6 +311,7 @@
     assert(_stm_in_transaction(tl));
     ensure_gs_register(tl->last_associated_segment_num);
     assert(STM_SEGMENT->running_thread == tl);
+    exec_local_finalizers();
 }
 
 void _stm_test_switch_segment(int segnum)
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
@@ -179,6 +179,8 @@
         if isinstance(objs, int):
             assert len(self.finalizers_called) == objs
         else:
+            print objs
+            print self.finalizers_called
             assert self.finalizers_called == objs
         self.finalizers_called = []
 
@@ -186,14 +188,12 @@
         self.start_transaction()
         lp1 = stm_allocate(48)
         stm_major_collect()
-        self.commit_transaction()
         self.expect_finalized([])
 
     def test_no_finalizer_in_minor_collection(self):
         self.start_transaction()
         lp1 = stm_allocate_with_finalizer(48)
         stm_minor_collect()
-        self.commit_transaction()
         self.expect_finalized([])
 
     def test_finalizer_in_major_collection(self):
@@ -204,21 +204,20 @@
             lp3 = stm_allocate_with_finalizer(48)
             self.expect_finalized([])
             self.push_roots([lp1, lp2, lp3])
-            self.commit_transaction()  # move finalizer-objs to global queue
-            self.start_transaction()
+            stm_minor_collect()
             lp1, lp2, lp3 = self.pop_roots()
             print repeat, lp1, lp2, lp3
             stm_major_collect()
-            self.commit_transaction()  # invoke finalizers
             self.expect_finalized([lp1, lp2, lp3])
-            self.start_transaction()
-        self.commit_transaction()
 
     def test_finalizer_from_other_thread(self):
         self.start_transaction()
         lp1 = stm_allocate_with_finalizer(48)
         stm_set_char(lp1, 'H')
         self.expect_content_character = 'H'
+        self.push_root(lp1)
+        stm_minor_collect()
+        lp1 = self.pop_root()
         print lp1
         #
         self.switch(1)
@@ -227,7 +226,6 @@
         self.expect_finalized([])      # marked as dead, but wrong thread
         #
         self.switch(0)
-        py.test.xfail("we don't finalize in the same transaction anymore.")
         self.expect_finalized([lp1])   # now it has been finalized
 
     def test_finalizer_ordering(self):
@@ -240,12 +238,10 @@
         stm_set_ref(lp1, 0, lp2)
 
         self.push_roots([lp1, lp2, lp3])
-        self.commit_transaction()  # move finalizer-objs to global queue
-        self.start_transaction()
+        stm_minor_collect()
         lp1, lp2, lp3 = self.pop_roots()
 
         stm_major_collect()
-        self.commit_transaction() # invoke finalizers
         self.expect_finalized([lp3])
 
     def test_finalizer_extra_transaction(self):
@@ -280,11 +276,8 @@
 
         self.expect_finalized([])
         stm_major_collect()
-        self.commit_transaction()
-        self.expect_finalized(1)
         self.switch(0)
-        self.commit_transaction()
-        self.expect_finalized(1)
+        self.expect_finalized(2)
 
     def test_run_major_collect_in_finalizer(self):
         self.run_major_collect_in_finalizer = True
@@ -294,7 +287,6 @@
         lp3 = stm_allocate_with_finalizer(32)
         print lp1, lp2, lp3
         stm_major_collect()
-        self.commit_transaction()
 
     def test_new_objects_w_finalizers(self):
         self.switch(2)
@@ -311,5 +303,4 @@
 
         self.expect_finalized([])
         stm_major_collect()
-        self.commit_transaction()
         self.expect_finalized([lp1])
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to