Author: Armin Rigo <ar...@tunes.org> 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 pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit