[pypy-commit] stmgc default: c8: pass some first finalizer tests
Raemi
noreply at buildbot.pypy.org
Tue Feb 24 23:50:36 CET 2015
Author: Remi Meier <remi.meier at gmail.com>
Branch:
Changeset: r1659:7aceea4cc94e
Date: 2015-02-24 17:12 +0100
http://bitbucket.org/pypy/stmgc/changeset/7aceea4cc94e/
Log: c8: pass some first finalizer tests
diff --git a/c8/stm/core.c b/c8/stm/core.c
--- a/c8/stm/core.c
+++ b/c8/stm/core.c
@@ -773,6 +773,8 @@
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->finalizers == NULL);
check_nursery_at_transaction_start();
@@ -871,6 +873,8 @@
void stm_commit_transaction(void)
{
+ exec_local_finalizers();
+
assert(!_has_mutex());
assert(STM_PSEGMENT->safe_point == SP_RUNNING);
assert(STM_PSEGMENT->running_pthread == pthread_self());
@@ -884,7 +888,6 @@
_validate_and_add_to_commit_log();
-
/* XXX do we still need a s_mutex_lock() section here? */
s_mutex_lock();
@@ -893,6 +896,8 @@
stm_rewind_jmp_forget(STM_SEGMENT->running_thread);
+ commit_finalizers();
+
invoke_and_clear_user_callbacks(0); /* for commit */
if (globally_unique_transaction && was_inev) {
@@ -900,10 +905,15 @@
}
/* done */
+ stm_thread_local_t *tl = STM_SEGMENT->running_thread;
_finish_transaction();
/* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */
s_mutex_unlock();
+
+ /* between transactions, call finalizers. this will execute
+ a transaction itself */
+ invoke_general_finalizers(tl);
}
static void reset_modified_from_backup_copies(int segment_num)
@@ -959,6 +969,8 @@
(int)pseg->transaction_state);
}
+ abort_finalizers(pseg);
+
long bytes_in_nursery = throw_away_nursery(pseg);
acquire_modification_lock(segment_num);
diff --git a/c8/stm/core.h b/c8/stm/core.h
--- a/c8/stm/core.h
+++ b/c8/stm/core.h
@@ -110,6 +110,14 @@
pthread_t running_pthread;
#endif
+ /* light finalizers */
+ struct list_s *young_objects_with_light_finalizers;
+ struct list_s *old_objects_with_light_finalizers;
+
+ /* regular finalizers (objs from the current transaction only) */
+ struct finalizers_s *finalizers;
+
+
/* This is for smallmalloc.c */
struct small_malloc_data_s small_malloc_data;
diff --git a/c8/stm/finalizer.c b/c8/stm/finalizer.c
--- a/c8/stm/finalizer.c
+++ b/c8/stm/finalizer.c
@@ -28,6 +28,8 @@
static void _commit_finalizers(void)
{
+ /* move finalizer lists to g_finalizers for major collections */
+
if (STM_PSEGMENT->finalizers->run_finalizers != NULL) {
/* copy 'STM_PSEGMENT->finalizers->run_finalizers' into
'g_finalizers.run_finalizers', dropping any initial NULLs
@@ -96,14 +98,14 @@
list_clear(lst);
}
- /* also deals with overflow objects: they are at the tail of
+ /* also deals with newly created 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 = pseg->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(pseg, obj))
+ if (!(obj->stm_flags & GCFLAG_WB_EXECUTED))
break;
lst->count = count;
if (must_fix_gs) {
@@ -153,7 +155,8 @@
static void deal_with_young_objects_with_finalizers(void)
{
- /* for light finalizers */
+ /* for light finalizers: executes finalizers for objs that don't survive
+ this minor gc */
struct list_s *lst = STM_PSEGMENT->young_objects_with_light_finalizers;
long i, count = list_count(lst);
for (i = 0; i < count; i++) {
@@ -174,48 +177,48 @@
list_clear(lst);
}
-static void deal_with_old_objects_with_finalizers(void)
-{
- /* for light finalizers */
- int old_gs_register = STM_SEGMENT->segment_num;
- int current_gs_register = old_gs_register;
- long j;
- for (j = 1; j <= NB_SEGMENTS; j++) {
- struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
+/* static void deal_with_old_objects_with_finalizers(void) */
+/* { */
+/* /\* for light finalizers *\/ */
+/* int old_gs_register = STM_SEGMENT->segment_num; */
+/* int current_gs_register = old_gs_register; */
+/* long j; */
+/* for (j = 1; j <= NB_SEGMENTS; j++) { */
+/* struct stm_priv_segment_info_s *pseg = get_priv_segment(j); */
- struct list_s *lst = pseg->old_objects_with_light_finalizers;
- long i, count = list_count(lst);
- lst->count = 0;
- for (i = 0; i < count; 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
- segment as where it was originally registered. For
- objects that existed since a long time, it doesn't
- change anything: any thread should see the same old
- content (because if it wasn't the case, the object
- would be in a 'modified_old_objects' list
- somewhere, and so it wouldn't be dead). But it's
- important if the object was created by the same
- transaction: then only that segment sees valid
- content.
- */
- if (j != current_gs_register) {
- set_gs_register(get_segment_base(j));
- current_gs_register = j;
- }
- stmcb_light_finalizer(obj);
- }
- else {
- /* object survives */
- list_set_item(lst, lst->count++, (uintptr_t)obj);
- }
- }
- }
- if (old_gs_register != current_gs_register)
- set_gs_register(get_segment_base(old_gs_register));
-}
+/* struct list_s *lst = pseg->old_objects_with_light_finalizers; */
+/* long i, count = list_count(lst); */
+/* lst->count = 0; */
+/* for (i = 0; i < count; 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 */
+/* segment as where it was originally registered. For */
+/* objects that existed since a long time, it doesn't */
+/* change anything: any thread should see the same old */
+/* content (because if it wasn't the case, the object */
+/* would be in a 'modified_old_objects' list */
+/* somewhere, and so it wouldn't be dead). But it's */
+/* important if the object was created by the same */
+/* transaction: then only that segment sees valid */
+/* content. */
+/* *\/ */
+/* if (j != current_gs_register) { */
+/* set_gs_register(get_segment_base(j)); */
+/* current_gs_register = j; */
+/* } */
+/* stmcb_light_finalizer(obj); */
+/* } */
+/* else { */
+/* /\* object survives *\/ */
+/* list_set_item(lst, lst->count++, (uintptr_t)obj); */
+/* } */
+/* } */
+/* } */
+/* if (old_gs_register != current_gs_register) */
+/* set_gs_register(get_segment_base(old_gs_register)); */
+/* } */
/************************************************************/
@@ -224,195 +227,195 @@
as well as rpython/memory/gc/minimark.py.
*/
-static inline int _finalization_state(object_t *obj)
-{
- /* Returns the state, "0", 1, 2 or 3, as per finalizer-order.rst.
- One difference is that the official state 0 is returned here
- as a number that is <= 0. */
- uintptr_t lock_idx = mark_loc(obj);
- return write_locks[lock_idx] - (WL_FINALIZ_ORDER_1 - 1);
-}
+/* static inline int _finalization_state(object_t *obj) */
+/* { */
+/* /\* Returns the state, "0", 1, 2 or 3, as per finalizer-order.rst. */
+/* One difference is that the official state 0 is returned here */
+/* as a number that is <= 0. *\/ */
+/* uintptr_t lock_idx = mark_loc(obj); */
+/* return write_locks[lock_idx] - (WL_FINALIZ_ORDER_1 - 1); */
+/* } */
-static void _bump_finalization_state_from_0_to_1(object_t *obj)
-{
- uintptr_t lock_idx = mark_loc(obj);
- assert(write_locks[lock_idx] < WL_FINALIZ_ORDER_1);
- write_locks[lock_idx] = WL_FINALIZ_ORDER_1;
-}
+/* static void _bump_finalization_state_from_0_to_1(object_t *obj) */
+/* { */
+/* uintptr_t lock_idx = mark_loc(obj); */
+/* assert(write_locks[lock_idx] < WL_FINALIZ_ORDER_1); */
+/* write_locks[lock_idx] = WL_FINALIZ_ORDER_1; */
+/* } */
-static struct list_s *_finalizer_tmpstack;
-static struct list_s *_finalizer_emptystack;
-static struct list_s *_finalizer_pending;
+/* static struct list_s *_finalizer_tmpstack; */
+/* static struct list_s *_finalizer_emptystack; */
+/* static struct list_s *_finalizer_pending; */
-static inline void _append_to_finalizer_tmpstack(object_t **pobj)
-{
- object_t *obj = *pobj;
- if (obj != NULL)
- LIST_APPEND(_finalizer_tmpstack, obj);
-}
+/* static inline void _append_to_finalizer_tmpstack(object_t **pobj) */
+/* { */
+/* object_t *obj = *pobj; */
+/* if (obj != NULL) */
+/* LIST_APPEND(_finalizer_tmpstack, obj); */
+/* } */
-static inline struct list_s *finalizer_trace(char *base, object_t *obj,
- struct list_s *lst)
-{
- struct object_s *realobj = (struct object_s *)REAL_ADDRESS(base, obj);
- _finalizer_tmpstack = lst;
- stmcb_trace(realobj, &_append_to_finalizer_tmpstack);
- return _finalizer_tmpstack;
-}
+/* static inline struct list_s *finalizer_trace(char *base, object_t *obj, */
+/* struct list_s *lst) */
+/* { */
+/* struct object_s *realobj = (struct object_s *)REAL_ADDRESS(base, obj); */
+/* _finalizer_tmpstack = lst; */
+/* stmcb_trace(realobj, &_append_to_finalizer_tmpstack); */
+/* return _finalizer_tmpstack; */
+/* } */
-static void _recursively_bump_finalization_state(char *base, object_t *obj,
- int to_state)
-{
- struct list_s *tmpstack = _finalizer_emptystack;
- assert(list_is_empty(tmpstack));
+/* static void _recursively_bump_finalization_state(char *base, object_t *obj, */
+/* int to_state) */
+/* { */
+/* struct list_s *tmpstack = _finalizer_emptystack; */
+/* assert(list_is_empty(tmpstack)); */
- while (1) {
- if (_finalization_state(obj) == to_state - 1) {
- /* bump to the next state */
- write_locks[mark_loc(obj)]++;
+/* while (1) { */
+/* if (_finalization_state(obj) == to_state - 1) { */
+/* /\* bump to the next state *\/ */
+/* write_locks[mark_loc(obj)]++; */
- /* trace */
- tmpstack = finalizer_trace(base, obj, tmpstack);
- }
+/* /\* trace *\/ */
+/* tmpstack = finalizer_trace(base, obj, tmpstack); */
+/* } */
- if (list_is_empty(tmpstack))
- break;
+/* if (list_is_empty(tmpstack)) */
+/* break; */
- obj = (object_t *)list_pop_item(tmpstack);
- }
- _finalizer_emptystack = tmpstack;
-}
+/* obj = (object_t *)list_pop_item(tmpstack); */
+/* } */
+/* _finalizer_emptystack = tmpstack; */
+/* } */
-static struct list_s *mark_finalize_step1(char *base, struct finalizers_s *f)
-{
- if (f == NULL)
- return NULL;
+/* static struct list_s *mark_finalize_step1(char *base, struct finalizers_s *f) */
+/* { */
+/* if (f == NULL) */
+/* return NULL; */
- struct list_s *marked = list_create();
+/* struct list_s *marked = list_create(); */
- struct list_s *lst = f->objects_with_finalizers;
- long i, count = list_count(lst);
- lst->count = 0;
- f->count_non_young = 0;
+/* struct list_s *lst = f->objects_with_finalizers; */
+/* long i, count = list_count(lst); */
+/* lst->count = 0; */
+/* f->count_non_young = 0; */
- for (i = 0; i < count; i++) {
- object_t *x = (object_t *)list_item(lst, i);
+/* for (i = 0; i < count; i++) { */
+/* object_t *x = (object_t *)list_item(lst, i); */
- assert(_finalization_state(x) != 1);
- if (_finalization_state(x) >= 2) {
- list_set_item(lst, lst->count++, (uintptr_t)x);
- continue;
- }
- LIST_APPEND(marked, x);
+/* assert(_finalization_state(x) != 1); */
+/* if (_finalization_state(x) >= 2) { */
+/* list_set_item(lst, lst->count++, (uintptr_t)x); */
+/* continue; */
+/* } */
+/* LIST_APPEND(marked, x); */
- struct list_s *pending = _finalizer_pending;
- LIST_APPEND(pending, x);
- while (!list_is_empty(pending)) {
- object_t *y = (object_t *)list_pop_item(pending);
- int state = _finalization_state(y);
- if (state <= 0) {
- _bump_finalization_state_from_0_to_1(y);
- pending = finalizer_trace(base, y, pending);
- }
- else if (state == 2) {
- _recursively_bump_finalization_state(base, y, 3);
- }
- }
- _finalizer_pending = pending;
- assert(_finalization_state(x) == 1);
- _recursively_bump_finalization_state(base, x, 2);
- }
- return marked;
-}
+/* struct list_s *pending = _finalizer_pending; */
+/* LIST_APPEND(pending, x); */
+/* while (!list_is_empty(pending)) { */
+/* object_t *y = (object_t *)list_pop_item(pending); */
+/* int state = _finalization_state(y); */
+/* if (state <= 0) { */
+/* _bump_finalization_state_from_0_to_1(y); */
+/* pending = finalizer_trace(base, y, pending); */
+/* } */
+/* else if (state == 2) { */
+/* _recursively_bump_finalization_state(base, y, 3); */
+/* } */
+/* } */
+/* _finalizer_pending = pending; */
+/* assert(_finalization_state(x) == 1); */
+/* _recursively_bump_finalization_state(base, x, 2); */
+/* } */
+/* return marked; */
+/* } */
-static void mark_finalize_step2(char *base, struct finalizers_s *f,
- struct list_s *marked)
-{
- if (f == NULL)
- return;
+/* static void mark_finalize_step2(char *base, struct finalizers_s *f, */
+/* struct list_s *marked) */
+/* { */
+/* if (f == NULL) */
+/* return; */
- struct list_s *run_finalizers = f->run_finalizers;
+/* struct list_s *run_finalizers = f->run_finalizers; */
- long i, count = list_count(marked);
- for (i = 0; i < count; i++) {
- object_t *x = (object_t *)list_item(marked, i);
+/* long i, count = list_count(marked); */
+/* for (i = 0; i < count; i++) { */
+/* object_t *x = (object_t *)list_item(marked, i); */
- int state = _finalization_state(x);
- assert(state >= 2);
- if (state == 2) {
- if (run_finalizers == NULL)
- run_finalizers = list_create();
- LIST_APPEND(run_finalizers, x);
- _recursively_bump_finalization_state(base, x, 3);
- }
- else {
- struct list_s *lst = f->objects_with_finalizers;
- list_set_item(lst, lst->count++, (uintptr_t)x);
- }
- }
- list_free(marked);
+/* int state = _finalization_state(x); */
+/* assert(state >= 2); */
+/* if (state == 2) { */
+/* if (run_finalizers == NULL) */
+/* run_finalizers = list_create(); */
+/* LIST_APPEND(run_finalizers, x); */
+/* _recursively_bump_finalization_state(base, x, 3); */
+/* } */
+/* else { */
+/* struct list_s *lst = f->objects_with_finalizers; */
+/* list_set_item(lst, lst->count++, (uintptr_t)x); */
+/* } */
+/* } */
+/* list_free(marked); */
- f->run_finalizers = run_finalizers;
-}
+/* f->run_finalizers = run_finalizers; */
+/* } */
-static void deal_with_objects_with_finalizers(void)
-{
- /* for non-light finalizers */
+/* static void deal_with_objects_with_finalizers(void) */
+/* { */
+/* /\* for non-light finalizers *\/ */
- /* there is one 'objects_with_finalizers' list per segment.
- Objects that die at a major collection running in the same
- transaction as they were created will be put in the
- 'run_finalizers' list of that segment. Objects that survive at
- least one commit move to the global g_objects_with_finalizers,
- and when they die they go to g_run_finalizers. The former kind
- of dying object must have its finalizer called in the correct
- thread; the latter kind can be called in any thread, through
- any segment, because they all should see the same old content
- anyway. (If the content was different between segments at this
- point, the object would be in a 'modified_old_objects' list
- somewhere, and so it wouldn't be dead).
- */
- struct list_s *marked_seg[NB_SEGMENTS + 1];
- LIST_CREATE(_finalizer_emptystack);
- LIST_CREATE(_finalizer_pending);
+/* /\* there is one 'objects_with_finalizers' list per segment. */
+/* Objects that die at a major collection running in the same */
+/* transaction as they were created will be put in the */
+/* 'run_finalizers' list of that segment. Objects that survive at */
+/* least one commit move to the global g_objects_with_finalizers, */
+/* and when they die they go to g_run_finalizers. The former kind */
+/* of dying object must have its finalizer called in the correct */
+/* thread; the latter kind can be called in any thread, through */
+/* any segment, because they all should see the same old content */
+/* anyway. (If the content was different between segments at this */
+/* point, the object would be in a 'modified_old_objects' list */
+/* somewhere, and so it wouldn't be dead). */
+/* *\/ */
+/* struct list_s *marked_seg[NB_SEGMENTS + 1]; */
+/* LIST_CREATE(_finalizer_emptystack); */
+/* LIST_CREATE(_finalizer_pending); */
- long j;
- for (j = 1; j <= NB_SEGMENTS; j++) {
- struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
- marked_seg[j] = mark_finalize_step1(pseg->pub.segment_base,
- pseg->finalizers);
- }
- marked_seg[0] = mark_finalize_step1(stm_object_pages, &g_finalizers);
+/* long j; */
+/* for (j = 1; j <= NB_SEGMENTS; j++) { */
+/* struct stm_priv_segment_info_s *pseg = get_priv_segment(j); */
+/* marked_seg[j] = mark_finalize_step1(pseg->pub.segment_base, */
+/* pseg->finalizers); */
+/* } */
+/* marked_seg[0] = mark_finalize_step1(stm_object_pages, &g_finalizers); */
- LIST_FREE(_finalizer_pending);
+/* LIST_FREE(_finalizer_pending); */
- for (j = 1; j <= NB_SEGMENTS; j++) {
- struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
- mark_finalize_step2(pseg->pub.segment_base, pseg->finalizers,
- marked_seg[j]);
- }
- mark_finalize_step2(stm_object_pages, &g_finalizers, marked_seg[0]);
+/* for (j = 1; j <= NB_SEGMENTS; j++) { */
+/* struct stm_priv_segment_info_s *pseg = get_priv_segment(j); */
+/* mark_finalize_step2(pseg->pub.segment_base, pseg->finalizers, */
+/* marked_seg[j]); */
+/* } */
+/* mark_finalize_step2(stm_object_pages, &g_finalizers, marked_seg[0]); */
- LIST_FREE(_finalizer_emptystack);
-}
+/* LIST_FREE(_finalizer_emptystack); */
+/* } */
-static void mark_visit_from_finalizer1(char *base, struct finalizers_s *f)
-{
- if (f != NULL && f->run_finalizers != NULL) {
- LIST_FOREACH_R(f->run_finalizers, object_t * /*item*/,
- mark_visit_object(item, base));
- }
-}
+/* static void mark_visit_from_finalizer1(char *base, struct finalizers_s *f) */
+/* { */
+/* if (f != NULL && f->run_finalizers != NULL) { */
+/* LIST_FOREACH_R(f->run_finalizers, object_t * /\*item*\/, */
+/* mark_visit_object(item, base)); */
+/* } */
+/* } */
-static void mark_visit_from_finalizer_pending(void)
-{
- long j;
- for (j = 1; j <= NB_SEGMENTS; j++) {
- struct stm_priv_segment_info_s *pseg = get_priv_segment(j);
- mark_visit_from_finalizer1(pseg->pub.segment_base, pseg->finalizers);
- }
- mark_visit_from_finalizer1(stm_object_pages, &g_finalizers);
-}
+/* static void mark_visit_from_finalizer_pending(void) */
+/* { */
+/* long j; */
+/* for (j = 1; j <= NB_SEGMENTS; j++) { */
+/* struct stm_priv_segment_info_s *pseg = get_priv_segment(j); */
+/* mark_visit_from_finalizer1(pseg->pub.segment_base, pseg->finalizers); */
+/* } */
+/* mark_visit_from_finalizer1(stm_object_pages, &g_finalizers); */
+/* } */
static void _execute_finalizers(struct finalizers_s *f)
{
diff --git a/c8/stm/list.c b/c8/stm/list.c
--- a/c8/stm/list.c
+++ b/c8/stm/list.c
@@ -30,6 +30,21 @@
return lst;
}
+static struct list_s *list_extend(struct list_s *lst, struct list_s *lst2,
+ uintptr_t slicestart)
+{
+ if (lst2->count <= slicestart)
+ return lst;
+ uintptr_t baseindex = lst->count;
+ lst->count = baseindex + lst2->count - slicestart;
+ uintptr_t lastindex = lst->count - 1;
+ if (lastindex > lst->last_allocated)
+ lst = _list_grow(lst, lastindex);
+ memcpy(lst->items + baseindex, lst2->items + slicestart,
+ (lst2->count - slicestart) * sizeof(uintptr_t));
+ return lst;
+}
+
/************************************************************/
diff --git a/c8/stm/list.h b/c8/stm/list.h
--- a/c8/stm/list.h
+++ b/c8/stm/list.h
@@ -96,6 +96,10 @@
return &lst->items[index];
}
+static struct list_s *list_extend(struct list_s *lst, struct list_s *lst2,
+ uintptr_t slicestart);
+
+
#define LIST_FOREACH_R(lst, TYPE, CODE) \
do { \
struct list_s *_lst = (lst); \
diff --git a/c8/stm/nursery.c b/c8/stm/nursery.c
--- a/c8/stm/nursery.c
+++ b/c8/stm/nursery.c
@@ -37,6 +37,10 @@
tree_contains(STM_PSEGMENT->young_outside_nursery, (uintptr_t)obj));
}
+static inline bool _is_from_same_transaction(object_t *obj) {
+ return _is_young(obj) || (obj->stm_flags & GCFLAG_WB_EXECUTED);
+}
+
long stm_can_move(object_t *obj)
{
/* 'long' return value to avoid using 'bool' in the public interface */
@@ -226,6 +230,22 @@
}
}
+static void collect_objs_still_young_but_with_finalizers(void)
+{
+ struct list_s *lst = STM_PSEGMENT->finalizers->objects_with_finalizers;
+ uintptr_t i, total = list_count(lst);
+
+ for (i = STM_PSEGMENT->finalizers->count_non_young; i < total; i++) {
+
+ object_t *o = (object_t *)list_item(lst, i);
+ minor_trace_if_young(&o);
+
+ /* was not actually movable */
+ assert(o == (object_t *)list_item(lst, i));
+ }
+ STM_PSEGMENT->finalizers->count_non_young = total;
+}
+
static size_t throw_away_nursery(struct stm_priv_segment_info_s *pseg)
{
@@ -296,12 +316,16 @@
collect_roots_in_nursery();
+ if (STM_PSEGMENT->finalizers != NULL)
+ collect_objs_still_young_but_with_finalizers();
+
collect_oldrefs_to_nursery();
/* now all surviving nursery objects have been moved out */
acquire_privatization_lock(STM_SEGMENT->segment_num);
stm_move_young_weakrefs();
release_privatization_lock(STM_SEGMENT->segment_num);
+ deal_with_young_objects_with_finalizers();
assert(list_is_empty(STM_PSEGMENT->objects_pointing_to_nursery));
diff --git a/c8/stm/setup.c b/c8/stm/setup.c
--- a/c8/stm/setup.c
+++ b/c8/stm/setup.c
@@ -108,6 +108,8 @@
pr->nursery_objects_shadows = tree_create();
pr->callbacks_on_commit_and_abort[0] = tree_create();
pr->callbacks_on_commit_and_abort[1] = tree_create();
+ pr->young_objects_with_light_finalizers = list_create();
+ pr->old_objects_with_light_finalizers = list_create();
pr->last_commit_log_entry = &commit_log_root;
pr->pub.transaction_read_version = 0xff;
@@ -127,6 +129,7 @@
setup_gcpage();
setup_pages();
setup_forksupport();
+ setup_finalizer();
set_gs_register(get_segment_base(0));
}
@@ -153,6 +156,8 @@
tree_free(pr->nursery_objects_shadows);
tree_free(pr->callbacks_on_commit_and_abort[0]);
tree_free(pr->callbacks_on_commit_and_abort[1]);
+ list_free(pr->young_objects_with_light_finalizers);
+ list_free(pr->old_objects_with_light_finalizers);
}
munmap(stm_object_pages, TOTAL_MEMORY);
@@ -160,6 +165,7 @@
commit_log_root.next = NULL; /* xxx:free them */
commit_log_root.segment_num = -1;
+ teardown_finalizer();
teardown_sync();
teardown_gcpage();
teardown_smallmalloc();
diff --git a/c8/stm/sync.c b/c8/stm/sync.c
--- a/c8/stm/sync.c
+++ b/c8/stm/sync.c
@@ -193,6 +193,7 @@
assert(_stm_in_transaction(tl));
set_gs_register(get_segment_base(tl->associated_segment_num));
assert(STM_SEGMENT->running_thread == tl);
+ exec_local_finalizers();
}
void _stm_test_switch_segment(int segnum)
diff --git a/c8/stmgc.h b/c8/stmgc.h
--- a/c8/stmgc.h
+++ b/c8/stmgc.h
@@ -270,6 +270,31 @@
void stm_validate(void);
+
+/* Support for light finalizers. This is a simple version of
+ finalizers that guarantees not to do anything fancy, like not
+ resurrecting objects. */
+extern void (*stmcb_light_finalizer)(object_t *);
+void stm_enable_light_finalizer(object_t *);
+
+/* Support for regular finalizers. Unreachable objects with
+ finalizers are kept alive, as well as everything they point to, and
+ stmcb_finalizer() is called after the major GC. If there are
+ several objects with finalizers that reference each other in a
+ well-defined order (i.e. there are no cycles), then they are
+ finalized in order from outermost to innermost (i.e. starting with
+ the ones that are unreachable even from others).
+
+ For objects that have been created by the current transaction, if a
+ major GC runs while that transaction is alive and finds the object
+ unreachable, the finalizer is called immediately in the same
+ transaction. For older objects, the finalizer is called from a
+ random thread between regular transactions, in a new custom
+ transaction. */
+extern void (*stmcb_finalizer)(object_t *);
+object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up);
+
+
/* dummies for now: */
__attribute__((always_inline))
static inline void stm_write_card(object_t *obj, uintptr_t index)
diff --git a/c8/test/support.py b/c8/test/support.py
--- a/c8/test/support.py
+++ b/c8/test/support.py
@@ -40,6 +40,7 @@
/*void stm_write(object_t *obj); use _checked_stm_write() instead */
object_t *stm_allocate(ssize_t size_rounded_up);
object_t *stm_allocate_weakref(ssize_t size_rounded_up);
+object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up);
void stm_setup(void);
void stm_teardown(void);
@@ -77,6 +78,7 @@
bool _check_become_inevitable(stm_thread_local_t *tl);
bool _check_become_globally_unique_transaction(stm_thread_local_t *tl);
int stm_is_inevitable(void);
+long current_segment_num(void);
void _set_type_id(object_t *obj, uint32_t h);
uint32_t _get_type_id(object_t *obj);
@@ -128,6 +130,12 @@
bool (*_stm_smallmalloc_keep)(char *data);
void _stm_smallmalloc_sweep_test(void);
+
+void (*stmcb_light_finalizer)(object_t *);
+void stm_enable_light_finalizer(object_t *);
+
+void (*stmcb_finalizer)(object_t *);
+
""")
@@ -322,6 +330,10 @@
}
}
+long current_segment_num(void)
+{
+ return STM_SEGMENT->segment_num;
+}
''', sources=source_files,
define_macros=[('STM_TESTS', '1'),
('STM_NO_AUTOMATIC_SETJMP', '1'),
@@ -332,7 +344,7 @@
],
undef_macros=['NDEBUG'],
include_dirs=[parent_dir],
- extra_compile_args=['-g', '-O0', '-Wall', '-Werror', '-ferror-limit=5'],
+ extra_compile_args=['-g', '-O0', '-Wall', '-ferror-limit=5'],
extra_link_args=['-g', '-lrt'],
force_generic_engine=True)
@@ -386,15 +398,27 @@
lib._set_weakref(o, point_to_obj)
return o
-def stm_get_weakref(o):
- return lib._get_weakref(o)
-
def stm_allocate_refs(n):
o = lib.stm_allocate(HDR + n * WORD)
tid = 421420 + n
lib._set_type_id(o, tid)
return o
+def stm_allocate_with_finalizer(size):
+ o = lib.stm_allocate_with_finalizer(size)
+ tid = 42 + size
+ lib._set_type_id(o, tid)
+ return o
+
+def stm_allocate_with_finalizer_refs(n):
+ o = lib.stm_allocate_with_finalizer(HDR + n * WORD)
+ tid = 421420 + n
+ lib._set_type_id(o, tid)
+ return o
+
+def stm_get_weakref(o):
+ return lib._get_weakref(o)
+
def stm_set_ref(obj, idx, ref, use_cards=False):
if use_cards:
stm_write_card(obj, idx)
diff --git a/c8/test/test_list.py b/c8/test/test_list.py
--- a/c8/test/test_list.py
+++ b/c8/test/test_list.py
@@ -6,6 +6,12 @@
ffi = cffi.FFI()
ffi.cdef("""
struct list_s *list_create(void);
+void list_free(struct list_s *lst);
+struct list_s *list_append(struct list_s *lst, uintptr_t item);
+uintptr_t list_count(struct list_s *lst);
+uintptr_t list_item(struct list_s *lst, uintptr_t index);
+struct list_s *list_extend(struct list_s *lst, struct list_s *lst2,
+ uintptr_t slicestart);
struct tree_s *tree_create(void);
void tree_free(struct tree_s *tree);
@@ -127,3 +133,16 @@
def test_hash_permutation():
hashes = [((n ^ (n << 4)) & 0xFF0) for n in range(256)]
assert set(hashes) == set(range(0, 4096, 16))
+
+def test_list_extend():
+ a = lib.list_create()
+ b = lib.list_create()
+ for i in range(100, 120):
+ b = lib.list_append(b, i)
+ a = lib.list_extend(a, b, 3)
+ a = lib.list_extend(a, b, 13)
+ assert lib.list_count(a) == 17 + 7
+ for i, expected in enumerate(range(103, 120) + range(113, 120)):
+ assert lib.list_item(a, i) == expected
+ lib.list_free(b)
+ lib.list_free(a)
More information about the pypy-commit
mailing list