Author: Armin Rigo <[email protected]>
Branch: hashtable
Changeset: r1486:9b55442913fa
Date: 2014-10-31 12:07 +0100
http://bitbucket.org/pypy/stmgc/changeset/9b55442913fa/
Log: Light finalizer: fix what occurs in case of aborts after setting a
light finalizer. Previously crashed; now calls the light finalizer.
diff --git a/c7/stm/core.c b/c7/stm/core.c
--- a/c7/stm/core.c
+++ b/c7/stm/core.c
@@ -372,6 +372,7 @@
assert(tree_is_cleared(STM_PSEGMENT->nursery_objects_shadows));
assert(tree_is_cleared(STM_PSEGMENT->callbacks_on_commit_and_abort[0]));
assert(tree_is_cleared(STM_PSEGMENT->callbacks_on_commit_and_abort[1]));
+ assert(list_is_empty(STM_PSEGMENT->young_objects_with_light_finalizers));
assert(STM_PSEGMENT->objects_pointing_to_nursery == NULL);
assert(STM_PSEGMENT->large_overflow_objects == NULL);
assert(STM_PSEGMENT->finalizers == NULL);
diff --git a/c7/stm/finalizer.c b/c7/stm/finalizer.c
--- a/c7/stm/finalizer.c
+++ b/c7/stm/finalizer.c
@@ -58,28 +58,59 @@
STM_PSEGMENT->finalizers = NULL;
}
-static void _abort_finalizers(void)
+static void abort_finalizers(void)
{
/* like _commit_finalizers(), but forget everything from the
current transaction */
- if (STM_PSEGMENT->finalizers->run_finalizers != NULL) {
- if (STM_PSEGMENT->finalizers->running_next != NULL) {
- *STM_PSEGMENT->finalizers->running_next = (uintptr_t)-1;
+ if (STM_PSEGMENT->finalizers != NULL) {
+ if (STM_PSEGMENT->finalizers->run_finalizers != NULL) {
+ if (STM_PSEGMENT->finalizers->running_next != NULL) {
+ *STM_PSEGMENT->finalizers->running_next = (uintptr_t)-1;
+ }
+ list_free(STM_PSEGMENT->finalizers->run_finalizers);
}
- list_free(STM_PSEGMENT->finalizers->run_finalizers);
+ list_free(STM_PSEGMENT->finalizers->objects_with_finalizers);
+ free(STM_PSEGMENT->finalizers);
+ STM_PSEGMENT->finalizers = NULL;
}
- list_free(STM_PSEGMENT->finalizers->objects_with_finalizers);
- free(STM_PSEGMENT->finalizers);
- STM_PSEGMENT->finalizers = NULL;
+
+ /* also call the light finalizers for objects that are about to
+ be forgotten from the current transaction */
+ struct list_s *lst = STM_PSEGMENT->young_objects_with_light_finalizers;
+ long i, count = list_count(lst);
+ if (lst > 0) {
+ for (i = 0; i < count; i++) {
+ object_t *obj = (object_t *)list_item(lst, i);
+ assert(_is_young(obj));
+ stmcb_light_finalizer(obj);
+ }
+ list_clear(lst);
+ }
+
+ /* also deals with overflow objects: they are at the tail of
+ old_objects_with_light_finalizers (this list is kept in order
+ and we cannot add any already-committed object) */
+ lst = STM_PSEGMENT->old_objects_with_light_finalizers;
+ count = list_count(lst);
+ while (count > 0) {
+ object_t *obj = (object_t *)list_item(lst, --count);
+ if (!IS_OVERFLOW_OBJ(STM_PSEGMENT, obj))
+ break;
+ lst->count = count;
+ stmcb_light_finalizer(obj);
+ }
}
void stm_enable_light_finalizer(object_t *obj)
{
- if (_is_young(obj))
+ if (_is_young(obj)) {
LIST_APPEND(STM_PSEGMENT->young_objects_with_light_finalizers, obj);
- else
+ }
+ else {
+ assert(_is_from_same_transaction(obj));
LIST_APPEND(STM_PSEGMENT->old_objects_with_light_finalizers, obj);
+ }
}
object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up)
@@ -108,7 +139,7 @@
struct list_s *lst = STM_PSEGMENT->young_objects_with_light_finalizers;
long i, count = list_count(lst);
for (i = 0; i < count; i++) {
- object_t* obj = (object_t *)list_item(lst, i);
+ object_t *obj = (object_t *)list_item(lst, i);
assert(_is_young(obj));
object_t *TLPREFIX *pforwarded_array = (object_t *TLPREFIX *)obj;
@@ -138,7 +169,7 @@
long i, count = list_count(lst);
lst->count = 0;
for (i = 0; i < count; i++) {
- object_t* obj = (object_t *)list_item(lst, i);
+ object_t *obj = (object_t *)list_item(lst, i);
if (!mark_visited_test(obj)) {
/* not marked: object dies */
/* we're calling the light finalizer in the same
diff --git a/c7/stm/finalizer.h b/c7/stm/finalizer.h
--- a/c7/stm/finalizer.h
+++ b/c7/stm/finalizer.h
@@ -14,18 +14,13 @@
static void teardown_finalizer(void);
static void _commit_finalizers(void);
-static void _abort_finalizers(void);
+static void abort_finalizers(void);
#define commit_finalizers() do { \
if (STM_PSEGMENT->finalizers != NULL) \
_commit_finalizers(); \
} while (0)
-#define abort_finalizers() do { \
- if (STM_PSEGMENT->finalizers != NULL) \
- _abort_finalizers(); \
-} while (0)
-
/* regular finalizers (objs from already-committed transactions) */
static struct finalizers_s g_finalizers;
diff --git a/c7/test/test_finalizer.py b/c7/test/test_finalizer.py
--- a/c7/test/test_finalizer.py
+++ b/c7/test/test_finalizer.py
@@ -49,6 +49,15 @@
self.commit_transaction()
self.expect_finalized([])
+ def test_young_light_finalizer_aborts(self):
+ self.start_transaction()
+ lp1 = stm_allocate(48)
+ lib.stm_enable_light_finalizer(lp1)
+ self.expect_finalized([])
+ self.abort_transaction()
+ self.start_transaction()
+ self.expect_finalized([lp1], from_tlnum=0)
+
def test_old_light_finalizer(self):
self.start_transaction()
lp1 = stm_allocate(48)
@@ -99,6 +108,30 @@
stm_major_collect()
self.expect_finalized([lp1], from_tlnum=1)
+ def test_old_light_finalizer_aborts(self):
+ self.start_transaction()
+ lp1 = stm_allocate(48)
+ lib.stm_enable_light_finalizer(lp1)
+ self.push_root(lp1)
+ self.commit_transaction()
+ #
+ self.start_transaction()
+ self.expect_finalized([])
+ self.abort_transaction()
+ self.expect_finalized([])
+
+ def test_overflow_light_finalizer_aborts(self):
+ self.start_transaction()
+ lp1 = stm_allocate(48)
+ lib.stm_enable_light_finalizer(lp1)
+ self.push_root(lp1)
+ stm_minor_collect()
+ lp1 = self.pop_root()
+ self.push_root(lp1)
+ self.expect_finalized([])
+ self.abort_transaction()
+ self.expect_finalized([lp1], from_tlnum=0)
+
class TestRegularFinalizer(BaseTest):
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit