Author: Armin Rigo <ar...@tunes.org> Branch: stmgc-c7 Changeset: r73988:b2f9c698970e Date: 2014-10-17 12:37 +0200 http://bitbucket.org/pypy/pypy/changeset/b2f9c698970e/
Log: import stmgc/3a8ef5f741ab diff --git a/rpython/translator/stm/src_stm/revision b/rpython/translator/stm/src_stm/revision --- a/rpython/translator/stm/src_stm/revision +++ b/rpython/translator/stm/src_stm/revision @@ -1,1 +1,1 @@ -32dbfbd04b6f +3a8ef5f741ab diff --git a/rpython/translator/stm/src_stm/stm/core.c b/rpython/translator/stm/src_stm/stm/core.c --- a/rpython/translator/stm/src_stm/stm/core.c +++ b/rpython/translator/stm/src_stm/stm/core.c @@ -375,6 +375,7 @@ assert(tree_is_cleared(STM_PSEGMENT->callbacks_on_commit_and_abort[1])); assert(STM_PSEGMENT->objects_pointing_to_nursery == NULL); assert(STM_PSEGMENT->large_overflow_objects == NULL); + assert(STM_PSEGMENT->finalizers == NULL); #ifndef NDEBUG /* this should not be used when objects_pointing_to_nursery == NULL */ STM_PSEGMENT->modified_old_objects_markers_num_old = 99999999999999999L; @@ -808,6 +809,9 @@ void stm_commit_transaction(void) { + restart_all: + exec_local_finalizers(); + assert(!_has_mutex()); assert(STM_PSEGMENT->safe_point == SP_RUNNING); assert(STM_PSEGMENT->running_pthread == pthread_self()); @@ -825,6 +829,11 @@ Important: we should not call cond_wait() in the meantime. */ synchronize_all_threads(STOP_OTHERS_UNTIL_MUTEX_UNLOCK); + if (any_local_finalizers()) { + s_mutex_unlock(); + goto restart_all; + } + /* detect conflicts */ if (detect_write_read_conflicts()) goto restart; @@ -846,6 +855,8 @@ push_modified_to_other_segments(); _verify_cards_cleared_in_all_lists(get_priv_segment(STM_SEGMENT->segment_num)); + commit_finalizers(); + /* update 'overflow_number' if needed */ if (STM_PSEGMENT->overflow_number_has_been_used) { highest_overflow_number += GCFLAG_OVERFLOW_NUMBER_bit0; @@ -866,10 +877,13 @@ } /* done */ + stm_thread_local_t *tl = STM_SEGMENT->running_thread; _finish_transaction(STM_TRANSACTION_COMMIT); /* cannot access STM_SEGMENT or STM_PSEGMENT from here ! */ s_mutex_unlock(); + + invoke_general_finalizers(tl); } void stm_abort_transaction(void) @@ -1047,6 +1061,8 @@ /* invoke the callbacks */ invoke_and_clear_user_callbacks(1); /* for abort */ + abort_finalizers(); + if (is_abort(STM_SEGMENT->nursery_end)) { /* done aborting */ STM_SEGMENT->nursery_end = pause_signalled ? NSE_SIGPAUSE diff --git a/rpython/translator/stm/src_stm/stm/core.h b/rpython/translator/stm/src_stm/stm/core.h --- a/rpython/translator/stm/src_stm/stm/core.h +++ b/rpython/translator/stm/src_stm/stm/core.h @@ -199,6 +199,13 @@ /* marker where this thread became inevitable */ stm_loc_marker_t marker_inev; + + /* 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; }; enum /* safe_point */ { diff --git a/rpython/translator/stm/src_stm/stm/finalizer.c b/rpython/translator/stm/src_stm/stm/finalizer.c new file mode 100644 --- /dev/null +++ b/rpython/translator/stm/src_stm/stm/finalizer.c @@ -0,0 +1,405 @@ +/* Imported by rpython/translator/stm/import_stmgc.py */ + + +/* callbacks */ +void (*stmcb_light_finalizer)(object_t *); +void (*stmcb_finalizer)(object_t *); + + +static void init_finalizers(struct finalizers_s *f) +{ + f->objects_with_finalizers = list_create(); + f->count_non_young = 0; + f->run_finalizers = NULL; + f->running_next = NULL; +} + +static void setup_finalizer(void) +{ + init_finalizers(&g_finalizers); +} + +static void teardown_finalizer(void) +{ + if (g_finalizers.run_finalizers != NULL) + list_free(g_finalizers.run_finalizers); + list_free(g_finalizers.objects_with_finalizers); + memset(&g_finalizers, 0, sizeof(g_finalizers)); +} + +static void _commit_finalizers(void) +{ + if (STM_PSEGMENT->finalizers->run_finalizers != NULL) { + /* copy 'STM_PSEGMENT->finalizers->run_finalizers' into + 'g_finalizers.run_finalizers', dropping any initial NULLs + (finalizers already called) */ + struct list_s *src = STM_PSEGMENT->finalizers->run_finalizers; + uintptr_t frm = 0; + if (STM_PSEGMENT->finalizers->running_next != NULL) { + frm = *STM_PSEGMENT->finalizers->running_next; + assert(frm <= list_count(src)); + *STM_PSEGMENT->finalizers->running_next = (uintptr_t)-1; + } + if (frm < list_count(src)) { + g_finalizers.run_finalizers = list_extend( + g_finalizers.run_finalizers, + src, frm); + } + list_free(src); + } + + /* copy the whole 'STM_PSEGMENT->finalizers->objects_with_finalizers' + into 'g_finalizers.objects_with_finalizers' */ + g_finalizers.objects_with_finalizers = list_extend( + g_finalizers.objects_with_finalizers, + STM_PSEGMENT->finalizers->objects_with_finalizers, 0); + list_free(STM_PSEGMENT->finalizers->objects_with_finalizers); + + free(STM_PSEGMENT->finalizers); + STM_PSEGMENT->finalizers = NULL; +} + +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; + } + list_free(STM_PSEGMENT->finalizers->run_finalizers); + } + list_free(STM_PSEGMENT->finalizers->objects_with_finalizers); + free(STM_PSEGMENT->finalizers); + STM_PSEGMENT->finalizers = NULL; +} + + +void stm_enable_light_finalizer(object_t *obj) +{ + if (_is_young(obj)) + LIST_APPEND(STM_PSEGMENT->young_objects_with_light_finalizers, obj); + else + LIST_APPEND(STM_PSEGMENT->old_objects_with_light_finalizers, obj); +} + +object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up) +{ + object_t *obj = _stm_allocate_external(size_rounded_up); + + if (STM_PSEGMENT->finalizers == NULL) { + struct finalizers_s *f = malloc(sizeof(struct finalizers_s)); + if (f == NULL) + stm_fatalerror("out of memory in create_finalizers"); /* XXX */ + init_finalizers(f); + STM_PSEGMENT->finalizers = f; + } + LIST_APPEND(STM_PSEGMENT->finalizers->objects_with_finalizers, obj); + return obj; +} + + +/************************************************************/ +/* Light finalizers +*/ + +static void deal_with_young_objects_with_finalizers(void) +{ + /* for light finalizers */ + 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); + assert(_is_young(obj)); + + object_t *TLPREFIX *pforwarded_array = (object_t *TLPREFIX *)obj; + if (pforwarded_array[0] != GCWORD_MOVED) { + /* not moved: the object dies */ + stmcb_light_finalizer(obj); + } + else { + obj = pforwarded_array[1]; /* moved location */ + assert(!_is_young(obj)); + LIST_APPEND(STM_PSEGMENT->old_objects_with_light_finalizers, obj); + } + } + 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); + + 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)); +} + + +/************************************************************/ +/* Algorithm for regular (non-light) finalizers. + Follows closely pypy/doc/discussion/finalizer-order.rst + 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 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 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 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)]++; + + /* trace */ + tmpstack = finalizer_trace(base, obj, tmpstack); + } + + if (list_is_empty(tmpstack)) + break; + + 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; + + struct list_s *marked = list_create(); + + struct list_s *lst = f->objects_with_finalizers; + long i, count = list_count(lst); + lst->count = 0; + 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); + + 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; + + 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); + + 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; +} + +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); + + 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); + + 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); +} + +static void _execute_finalizers(struct finalizers_s *f) +{ + if (f->run_finalizers == NULL) + return; /* nothing to do */ + + restart: + if (f->running_next != NULL) + return; /* in a nested invocation of execute_finalizers() */ + + uintptr_t next = 0, total = list_count(f->run_finalizers); + f->running_next = &next; + + while (next < total) { + object_t *obj = (object_t *)list_item(f->run_finalizers, next); + list_set_item(f->run_finalizers, next, 0); + next++; + + stmcb_finalizer(obj); + } + if (next == (uintptr_t)-1) { + /* transaction committed: the whole 'f' was freed */ + return; + } + f->running_next = NULL; + + if (f->run_finalizers->count > total) { + memmove(f->run_finalizers->items, + f->run_finalizers->items + total, + (f->run_finalizers->count - total) * sizeof(uintptr_t)); + goto restart; + } + + LIST_FREE(f->run_finalizers); +} + +static void _invoke_general_finalizers(stm_thread_local_t *tl) +{ + /* called between transactions */ + static int lock = 0; + + if (__sync_lock_test_and_set(&lock, 1) != 0) { + /* can't acquire the lock: someone else is likely already + running this function, so don't wait. */ + return; + } + + rewind_jmp_buf rjbuf; + stm_rewind_jmp_enterframe(tl, &rjbuf); + stm_start_transaction(tl); + + _execute_finalizers(&g_finalizers); + + stm_commit_transaction(); + stm_rewind_jmp_leaveframe(tl, &rjbuf); + + __sync_lock_release(&lock); +} diff --git a/rpython/translator/stm/src_stm/stm/finalizer.h b/rpython/translator/stm/src_stm/stm/finalizer.h new file mode 100644 --- /dev/null +++ b/rpython/translator/stm/src_stm/stm/finalizer.h @@ -0,0 +1,48 @@ +/* Imported by rpython/translator/stm/import_stmgc.py */ + +struct finalizers_s { + struct list_s *objects_with_finalizers; + uintptr_t count_non_young; + struct list_s *run_finalizers; + uintptr_t *running_next; +}; + +static void deal_with_young_objects_with_finalizers(void); +static void deal_with_old_objects_with_finalizers(void); +static void deal_with_objects_with_finalizers(void); + +static void setup_finalizer(void); +static void teardown_finalizer(void); + +static void _commit_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; + +static void _invoke_general_finalizers(stm_thread_local_t *tl); + +#define invoke_general_finalizers(tl) do { \ + if (g_finalizers.run_finalizers != NULL) \ + _invoke_general_finalizers(tl); \ +} while (0) + +static void _execute_finalizers(struct finalizers_s *f); + +#define any_local_finalizers() (STM_PSEGMENT->finalizers != NULL && \ + STM_PSEGMENT->finalizers->run_finalizers != NULL) +#define exec_local_finalizers() do { \ + if (any_local_finalizers()) \ + _execute_finalizers(STM_PSEGMENT->finalizers); \ +} while (0) diff --git a/rpython/translator/stm/src_stm/stm/gcpage.c b/rpython/translator/stm/src_stm/stm/gcpage.c --- a/rpython/translator/stm/src_stm/stm/gcpage.c +++ b/rpython/translator/stm/src_stm/stm/gcpage.c @@ -154,6 +154,7 @@ } s_mutex_unlock(); + exec_local_finalizers(); } @@ -162,7 +163,11 @@ static struct list_s *mark_objects_to_trace; -#define WL_VISITED 255 +#define WL_FINALIZ_ORDER_1 253 +#define WL_FINALIZ_ORDER_2 254 +#define WL_FINALIZ_ORDER_3 WL_VISITED + +#define WL_VISITED 255 static inline uintptr_t mark_loc(object_t *obj) @@ -627,8 +632,14 @@ mark_visit_from_roots(); LIST_FREE(mark_objects_to_trace); - /* weakrefs: */ + /* finalizer support: will mark as WL_VISITED all objects with a + finalizer and all objects reachable from there, and also moves + some objects from 'objects_with_finalizers' to 'run_finalizers'. */ + deal_with_objects_with_finalizers(); + + /* weakrefs and old light finalizers */ stm_visit_old_weakrefs(); + deal_with_old_objects_with_finalizers(); /* cleanup */ clean_up_segment_lists(); diff --git a/rpython/translator/stm/src_stm/stm/list.c b/rpython/translator/stm/src_stm/stm/list.c --- a/rpython/translator/stm/src_stm/stm/list.c +++ b/rpython/translator/stm/src_stm/stm/list.c @@ -31,6 +31,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/rpython/translator/stm/src_stm/stm/list.h b/rpython/translator/stm/src_stm/stm/list.h --- a/rpython/translator/stm/src_stm/stm/list.h +++ b/rpython/translator/stm/src_stm/stm/list.h @@ -84,6 +84,9 @@ 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/rpython/translator/stm/src_stm/stm/nursery.c b/rpython/translator/stm/src_stm/stm/nursery.c --- a/rpython/translator/stm/src_stm/stm/nursery.c +++ b/rpython/translator/stm/src_stm/stm/nursery.c @@ -436,6 +436,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) { #pragma push_macro("STM_PSEGMENT") @@ -555,11 +571,15 @@ collect_roots_in_nursery(); + if (STM_PSEGMENT->finalizers != NULL) + collect_objs_still_young_but_with_finalizers(); + collect_oldrefs_to_nursery(); assert(list_is_empty(STM_PSEGMENT->old_objects_with_cards)); /* now all surviving nursery objects have been moved out */ stm_move_young_weakrefs(); + deal_with_young_objects_with_finalizers(); throw_away_nursery(get_priv_segment(STM_SEGMENT->segment_num)); diff --git a/rpython/translator/stm/src_stm/stm/setup.c b/rpython/translator/stm/src_stm/stm/setup.c --- a/rpython/translator/stm/src_stm/stm/setup.c +++ b/rpython/translator/stm/src_stm/stm/setup.c @@ -114,7 +114,7 @@ /* Initialize STM_PSEGMENT */ struct stm_priv_segment_info_s *pr = get_priv_segment(i); - assert(1 <= i && i < 255); /* 255 is WL_VISITED in gcpage.c */ + assert(1 <= i && i < 253); /* 253 is WL_FINALIZ_ORDER_1 in gcpage.c */ pr->write_lock_num = i; pr->pub.segment_num = i; pr->pub.segment_base = segment_base; @@ -129,6 +129,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->overflow_number = GCFLAG_OVERFLOW_NUMBER_bit0 * i; highest_overflow_number = pr->overflow_number; pr->pub.transaction_read_version = 0xff; @@ -148,6 +150,7 @@ setup_gcpage(); setup_pages(); setup_forksupport(); + setup_finalizer(); } void stm_teardown(void) @@ -170,12 +173,15 @@ 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); stm_object_pages = NULL; close_fd_mmap(stm_object_pages_fd); + teardown_finalizer(); teardown_core(); teardown_sync(); teardown_gcpage(); diff --git a/rpython/translator/stm/src_stm/stm/sync.c b/rpython/translator/stm/src_stm/stm/sync.c --- a/rpython/translator/stm/src_stm/stm/sync.c +++ b/rpython/translator/stm/src_stm/stm/sync.c @@ -229,6 +229,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(); } #if STM_TESTS diff --git a/rpython/translator/stm/src_stm/stmgc.c b/rpython/translator/stm/src_stm/stmgc.c --- a/rpython/translator/stm/src_stm/stmgc.c +++ b/rpython/translator/stm/src_stm/stmgc.c @@ -17,6 +17,7 @@ #include "stm/weakref.h" #include "stm/marker.h" #include "stm/prof.h" +#include "stm/finalizer.h" #include "stm/misc.c" #include "stm/list.c" @@ -38,3 +39,4 @@ #include "stm/marker.c" #include "stm/prof.c" #include "stm/rewind_setjmp.c" +#include "stm/finalizer.c" diff --git a/rpython/translator/stm/src_stm/stmgc.h b/rpython/translator/stm/src_stm/stmgc.h --- a/rpython/translator/stm/src_stm/stmgc.h +++ b/rpython/translator/stm/src_stm/stmgc.h @@ -506,6 +506,29 @@ } while (0) +/* Support for light finalizers. This is a simple version of + finalizers that guarantees not to do anything fancy, like not + resurrecting objects. */ +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. */ +void (*stmcb_finalizer)(object_t *); +object_t *stm_allocate_with_finalizer(ssize_t size_rounded_up); + /* ==================== END ==================== */ #endif _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit