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