Author: Remi Meier <[email protected]>
Branch: finalizer-queues
Changeset: r2001:26622312cfa8
Date: 2016-11-17 11:37 +0100
http://bitbucket.org/pypy/stmgc/changeset/26622312cfa8/

Log:    write some tests for finalizer queues

diff --git a/c8/stm/finalizer.c b/c8/stm/finalizer.c
--- a/c8/stm/finalizer.c
+++ b/c8/stm/finalizer.c
@@ -528,9 +528,13 @@
             // XXX: check that triggers *really* cannot touch GC-memory,
             // otherwise, this needs to run in an (inevitable) transaction
 #ifndef NDEBUG
+            char *old_gs_register = STM_SEGMENT->segment_base;
             set_gs_register(NULL);
 #endif
             g_finalizer_triggers.triggers[i]();
+#ifndef NDEBUG
+            set_gs_register(old_gs_register);
+#endif
         }
     }
 
@@ -586,6 +590,8 @@
 }
 
 object_t* stm_next_to_finalize(int queue_index) {
+    assert(STM_PSEGMENT->transaction_state != TS_NONE);
+
     /* 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;
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
@@ -11,6 +11,7 @@
         def trigger():
             # triggers not needed for destructors
             assert False
+        self._trigger_keepalive = trigger
         triggers = ffi.new("stm_finalizer_trigger_fn*", trigger)
         lib.stm_setup_finalizer_queues(1, triggers)
         triggers = None
@@ -147,6 +148,190 @@
         self.expect_finalized([lp1], from_tlnum=0)
 
 
+class TestRegularFinalizerQueues(BaseTest):
+    expect_content_character = None
+    run_major_collect_in_finalizer = False
+
+    def setup_method(self, meth):
+        BaseTest.setup_method(self, meth)
+        #
+        @ffi.callback("stm_finalizer_trigger_fn")
+        def trigger0():
+            self.queues_triggered.append(0)
+        @ffi.callback("stm_finalizer_trigger_fn")
+        def trigger1():
+            self.queues_triggered.append(1)
+        self._trigger_keepalive = [trigger0, trigger1]
+        triggers = ffi.new("stm_finalizer_trigger_fn[]", 
self._trigger_keepalive)
+        lib.stm_setup_finalizer_queues(2, triggers)
+        #
+        self.queues_triggered = []
+
+    def get_queues_triggered(self):
+        res = set(self.queues_triggered)
+        self.queues_triggered = []
+        return res
+
+    def get_to_finalize(self, qindex):
+        obj = lib.stm_next_to_finalize(qindex)
+        res = []
+        while obj:
+            res.append(obj)
+            obj = lib.stm_next_to_finalize(qindex)
+        return res
+
+
+
+    def test_no_finalizer(self):
+        self.start_transaction()
+        lp1 = stm_allocate(48)
+        stm_major_collect()
+        assert not self.get_queues_triggered()
+
+    def test_no_finalizer_in_minor_collection(self):
+        self.start_transaction()
+        lp1 = stm_allocate(48)
+        lib.stm_enable_finalizer(0, lp1)
+        stm_minor_collect()
+        assert not self.get_queues_triggered()
+
+    def test_finalizer_in_major_collection(self):
+        self.start_transaction()
+        for repeat in range(4):
+            lp1 = stm_allocate(48)
+            lp2 = stm_allocate(48)
+            lp3 = stm_allocate(48)
+            if repeat % 2 == 0: # register on young
+                lib.stm_enable_finalizer(0, lp1)
+                lib.stm_enable_finalizer(1, lp2)
+                lib.stm_enable_finalizer(1, lp3)
+            assert not self.get_queues_triggered()
+            self.push_roots([lp1, lp2, lp3])
+            stm_minor_collect()
+            lp1, lp2, lp3 = self.pop_roots()
+            if repeat % 2 == 1: # register on old
+                lib.stm_enable_finalizer(0, lp1)
+                lib.stm_enable_finalizer(1, lp2)
+                lib.stm_enable_finalizer(1, lp3)
+            print repeat, lp1, lp2, lp3
+            stm_major_collect()
+            assert {0, 1} == self.get_queues_triggered()
+            assert [lp1] == self.get_to_finalize(0)
+            assert [lp2, lp3] == self.get_to_finalize(1)
+
+    def test_finalizer_from_other_thread(self):
+        self.start_transaction()
+        lp1 = stm_allocate(48)
+        lib.stm_enable_finalizer(0, lp1)
+        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)
+        self.start_transaction()
+        stm_major_collect()
+        assert not self.get_queues_triggered()
+        #
+        self.switch(0)
+        assert {0} == self.get_queues_triggered()
+        assert [lp1] == self.get_to_finalize(0)
+
+    def test_finalizer_ordering(self):
+        self.start_transaction()
+        lp1 = stm_allocate_refs(1)
+        lp2 = stm_allocate_refs(1)
+        lp3 = stm_allocate_refs(1)
+        lib.stm_enable_finalizer(1, lp1)
+        lib.stm_enable_finalizer(1, lp2)
+        lib.stm_enable_finalizer(1, lp3)
+
+        print lp1, lp2, lp3
+        stm_set_ref(lp3, 0, lp1)
+        stm_set_ref(lp1, 0, lp2)
+
+        self.push_roots([lp1, lp2, lp3])
+        stm_minor_collect()
+        lp1, lp2, lp3 = self.pop_roots()
+
+        stm_major_collect()
+        assert {1} == self.get_queues_triggered()
+        assert [lp3] == self.get_to_finalize(1)
+
+    def test_finalizer_extra_transaction(self):
+        self.start_transaction()
+        lp1 = stm_allocate(32)
+        lib.stm_enable_finalizer(0, lp1)
+        self.push_root(lp1)
+        self.commit_transaction()
+
+        self.start_transaction()
+        lp1b = self.pop_root()
+        # assert lp1b == lp1 <- lp1 can be in nursery now
+        assert not self.get_queues_triggered()
+        self.commit_transaction() # finalizer-obj moved to global queue
+        assert not self.get_queues_triggered()
+
+        self.start_transaction()
+        stm_major_collect()
+        assert not self.get_queues_triggered()
+        self.commit_transaction() # invoke finalizers
+        self.start_transaction()
+        assert {0} == self.get_queues_triggered()
+        assert [lp1b] == self.get_to_finalize(0)
+
+    def test_run_cb_for_all_threads(self):
+        self.start_transaction()
+        lp1 = stm_allocate(48)
+        lib.stm_enable_finalizer(0, lp1)
+        print lp1
+        #
+        self.switch(1)
+        self.start_transaction()
+        lp2 = stm_allocate(56)
+        lib.stm_enable_finalizer(1, lp2)
+        print lp2
+
+        assert not self.get_queues_triggered()
+        stm_major_collect()
+        assert len(self.get_to_finalize(1)) == 1
+        self.switch(0)
+        assert self.get_queues_triggered() == {0, 1}
+        assert len(self.get_to_finalize(0)) == 1
+
+    def test_run_major_collect_in_finalizer(self):
+        self.run_major_collect_in_finalizer = True
+        self.start_transaction()
+        lp1 = stm_allocate(32)
+        lp2 = stm_allocate(32)
+        lp3 = stm_allocate(32)
+        lib.stm_enable_finalizer(0, lp1)
+        lib.stm_enable_finalizer(0, lp2)
+        lib.stm_enable_finalizer(0, lp3)
+        print lp1, lp2, lp3
+        stm_major_collect()
+
+    def test_new_objects_w_finalizers(self):
+        self.switch(2)
+        self.start_transaction()
+        lp1 = stm_allocate_refs(3)
+        lp2 = stm_allocate_refs(3)
+        lib.stm_enable_finalizer(0, lp1)
+        lib.stm_enable_finalizer(0, lp2)
+        stm_set_ref(lp1, 0, lp2)
+
+        self.push_root(lp1)
+        stm_minor_collect()
+        lp1 = self.pop_root()
+        lp2 = stm_get_ref(lp1, 0)
+        # lp1, lp2 have WB_EXECUTED objs
+
+        assert not self.get_queues_triggered()
+        stm_major_collect()
+        assert [lp1] == self.get_to_finalize(0)
+
 
 class TestOldStyleRegularFinalizer(BaseTest):
     expect_content_character = None
@@ -159,6 +344,7 @@
         def trigger():
             # triggers not needed for oldstyle-finalizer tests
             assert False
+        self._trigger_keepalive = trigger
         triggers = ffi.new("stm_finalizer_trigger_fn*", trigger)
         lib.stm_setup_finalizer_queues(1, triggers)
         #
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to