diff options
author | Zach Saw <zach.saw@gmail.com> | 2012-11-19 12:34:10 +1100 |
---|---|---|
committer | Zach Saw <zach.saw@gmail.com> | 2012-11-19 12:34:10 +1100 |
commit | ff44c6ae6730e054c028cc8c958d6ca961d4ebfa (patch) | |
tree | f561c245e40d90b529a9d108836accc289946177 | |
parent | df392f378463ae22e7b0f9da253dd13aa3840d9f (diff) | |
download | bdwgc-ff44c6ae6730e054c028cc8c958d6ca961d4ebfa.tar.gz |
dded long weakref support.
* include/gc.h: Added 3 GC_API functions for long weakref support:
GC_register_long_link, GC_unregister_long_link and GC_move_long_link.
* include/gc.h: Added corresponding GC_REGISTER_LONG_LINK macros.
* finalize.c: Add implementation of the above functions,
GC_ll_hashtbl for long links and GC_old_ll_entries.
* finalize.c (GC_push_finalizer_structures): GC_push_all long link
hash table entries as well.
* finalize.c (GC_dump_finalization): Refactored dump
disappearing link code out to GC_dump_finalization_links accepting
an argument of pointer to struct dl_hashtbl_s.
* finalize.c (GC_print_finalization_stats): Added long link stats
print out.
* finalize.c (GC_finalize): Added saving current GC_ll_hashtbl
entry count to GC_old_ll_entries,
GC_make_disappearing_links_disappear and
GC_remove_dangling_disappearing_links for long links.
-rw-r--r-- | finalize.c | 93 | ||||
-rw-r--r-- | include/gc.h | 24 |
2 files changed, 101 insertions, 16 deletions
@@ -48,7 +48,8 @@ STATIC struct dl_hashtbl_s { struct disappearing_link **head; signed_word log_size; word entries; -} GC_dl_hashtbl = { /* head */ NULL, /* log_size */ -1, /* entries */ 0}; +} GC_dl_hashtbl = { /* head */ NULL, /* log_size */ -1, /* entries */ 0}, + GC_ll_hashtbl = { /* head */ NULL, /* log_size */ -1, /* entries */ 0}; STATIC struct finalizable_object { struct hash_chain_entry prolog; @@ -72,11 +73,14 @@ static signed_word log_fo_table_size = -1; GC_INNER void GC_push_finalizer_structures(void) { GC_ASSERT((word)&GC_dl_hashtbl.head % sizeof(word) == 0); + GC_ASSERT((word)&GC_ll_hashtbl.head % sizeof(word) == 0); GC_ASSERT((word)&GC_fo_head % sizeof(word) == 0); GC_ASSERT((word)&GC_finalize_now % sizeof(word) == 0); GC_push_all((ptr_t)(&GC_dl_hashtbl.head), (ptr_t)(&GC_dl_hashtbl.head) + sizeof(word)); + GC_push_all((ptr_t)(&GC_ll_hashtbl.head), + (ptr_t)(&GC_ll_hashtbl.head) + sizeof(word)); GC_push_all((ptr_t)(&GC_fo_head), (ptr_t)(&GC_fo_head) + sizeof(word)); GC_push_all((ptr_t)(&GC_finalize_now), (ptr_t)(&GC_finalize_now) + sizeof(word)); @@ -206,6 +210,13 @@ GC_API int GC_CALL GC_general_register_disappearing_link(void * * link, return GC_register_disappearing_link_inner(&GC_dl_hashtbl, link, obj); } +GC_API int GC_CALL GC_register_long_link(void * * link, const void * obj) +{ + if (((word)link & (ALIGNMENT-1)) != 0 || NULL == link) + ABORT("Bad arg to GC_register_long_link"); + return GC_register_disappearing_link_inner(&GC_ll_hashtbl, link, obj); +} + #ifdef DBG_HDRS_ALL # define FREE_DL_ENTRY(curr_dl) dl_set_next(curr_dl, NULL) #else @@ -253,6 +264,21 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link) return 1; } +GC_API int GC_CALL GC_unregister_long_link(void * * link) +{ + struct disappearing_link *curr_dl; + DCL_LOCK_STATE; + + if (((word)link & (ALIGNMENT-1)) != 0) return(0); /* Nothing to do. */ + + LOCK(); + curr_dl = GC_unregister_disappearing_link_inner(&GC_ll_hashtbl, link); + UNLOCK(); + if (NULL == curr_dl) return 0; + FREE_DL_ENTRY(curr_dl); + return 1; +} + #ifndef GC_MOVE_DISAPPEARING_LINK_NOT_NEEDED /* Moves a link. Assume the lock is held. */ GC_INLINE int GC_move_disappearing_link_inner( @@ -321,6 +347,22 @@ GC_API int GC_CALL GC_unregister_disappearing_link(void * * link) UNLOCK(); return result; } + + GC_API int GC_CALL GC_move_long_link(void **link, void **new_link) + { + int result; + DCL_LOCK_STATE; + + if (((word)new_link & (ALIGNMENT-1)) != 0 || new_link == NULL) + ABORT("Bad new_link arg to GC_move_disappearing_link"); + if (((word)link & (ALIGNMENT-1)) != 0) + return GC_NOT_FOUND; /* Nothing to do. */ + + LOCK(); + result = GC_move_disappearing_link_inner(&GC_ll_hashtbl, link, new_link); + UNLOCK(); + return result; + } #endif /* !GC_MOVE_DISAPPEARING_LINK_NOT_NEEDED */ /* Possible finalization_marker procedures. Note that mark stack */ @@ -538,25 +580,35 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj, } #ifndef NO_DEBUGGING - void GC_dump_finalization(void) + GC_INLINE void GC_dump_finalization_links(struct dl_hashtbl_s* dl_hashtbl) { struct disappearing_link * curr_dl; - struct finalizable_object * curr_fo; ptr_t real_ptr, real_link; - int dl_size = GC_dl_hashtbl.log_size == -1 ? 0 : - 1 << GC_dl_hashtbl.log_size; - int fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size; - int i; + size_t dl_size = dl_hashtbl -> log_size == -1 ? 0 : + 1 << dl_hashtbl -> log_size; + size_t i; - GC_printf("Disappearing links:\n"); for (i = 0; i < dl_size; i++) { - for (curr_dl = GC_dl_hashtbl.head[i]; curr_dl != 0; + for (curr_dl = dl_hashtbl -> head[i]; curr_dl != 0; curr_dl = dl_next(curr_dl)) { real_ptr = GC_REVEAL_POINTER(curr_dl -> dl_hidden_obj); real_link = GC_REVEAL_POINTER(curr_dl -> dl_hidden_link); GC_printf("Object: %p, Link:%p\n", real_ptr, real_link); } } + } + + void GC_dump_finalization(void) + { + struct finalizable_object * curr_fo; + size_t fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size; + ptr_t real_ptr; + size_t i; + + GC_printf("Disappearing short links:\n"); + GC_dump_finalization_links(&GC_dl_hashtbl); + GC_printf("Disappearing long links:\n"); + GC_dump_finalization_links(&GC_ll_hashtbl); GC_printf("Finalizers:\n"); for (i = 0; i < fo_size; i++) { for (curr_fo = GC_fo_head[i]; curr_fo != 0; @@ -569,7 +621,8 @@ GC_API void GC_CALL GC_register_finalizer_unreachable(void * obj, #endif /* !NO_DEBUGGING */ #ifndef SMALL_CONFIG - STATIC word GC_old_dl_entries = 0; /* for stats printing */ + /* for stats printing */ + STATIC word GC_old_dl_entries = 0, GC_old_ll_entries = 0; #endif #ifndef THREADS @@ -674,8 +727,9 @@ GC_INNER void GC_finalize(void) size_t fo_size = log_fo_table_size == -1 ? 0 : 1 << log_fo_table_size; # ifndef SMALL_CONFIG - /* Save current GC_dl_entries value for stats printing */ + /* Save current GC_[dl/ll]_entries value for stats printing */ GC_old_dl_entries = GC_dl_hashtbl.entries; + GC_old_ll_entries = GC_ll_hashtbl.entries; # endif GC_make_disappearing_links_disappear(&GC_dl_hashtbl); @@ -787,7 +841,10 @@ GC_INNER void GC_finalize(void) } } + GC_make_disappearing_links_disappear(&GC_ll_hashtbl); + GC_remove_dangling_disappearing_links(&GC_dl_hashtbl); + GC_remove_dangling_disappearing_links(&GC_ll_hashtbl); if (GC_fail_count) { /* Don't prevent running finalizers if there has been an allocation */ @@ -1013,13 +1070,17 @@ GC_INNER void GC_notify_or_invoke_finalizers(void) unsigned long ready = 0; GC_log_printf( - "%lu finalization table entries; %lu disappearing links alive\n", - (unsigned long)GC_fo_entries, (unsigned long)GC_dl_hashtbl.entries); + "%lu finalization table entries; " + "%lu short/%lu long disappearing links alive\n", + (unsigned long)GC_fo_entries, + (unsigned long)GC_dl_hashtbl.entries, + (unsigned long)GC_ll_hashtbl.entries); for (; 0 != fo; fo = fo_next(fo)) ++ready; - GC_log_printf("%lu objects are eligible for immediate finalization; " - "%ld links cleared\n", + GC_log_printf("%lu objects are ready for finalization; " + "%ld short/%ld long links cleared\n", ready, - (long)GC_old_dl_entries - (long)GC_dl_hashtbl.entries); + (long)GC_old_dl_entries - (long)GC_dl_hashtbl.entries, + (long)GC_old_ll_entries - (long)GC_ll_hashtbl.entries); } #endif /* !SMALL_CONFIG */ diff --git a/include/gc.h b/include/gc.h index 4f32b485..c6e79193 100644 --- a/include/gc.h +++ b/include/gc.h @@ -825,6 +825,8 @@ GC_API /* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2) void * GC_CALL # define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \ GC_general_register_disappearing_link(link, \ GC_base((/* no const */ void *)(obj))) +# define GC_REGISTER_LONG_LINK(link, obj) \ + GC_register_long_link(link, GC_base((/* no const */ void *)(obj))) # define GC_REGISTER_DISPLACEMENT(n) GC_debug_register_displacement(n) #else # define GC_MALLOC_ATOMIC(sz) GC_malloc_atomic(sz) @@ -850,6 +852,8 @@ GC_API /* 'realloc' attr */ GC_ATTR_ALLOC_SIZE(2) void * GC_CALL # define GC_END_STUBBORN_CHANGE(p) GC_end_stubborn_change(p) # define GC_GENERAL_REGISTER_DISAPPEARING_LINK(link, obj) \ GC_general_register_disappearing_link(link, obj) +# define GC_REGISTER_LONG_LINK(link, obj) \ + GC_register_long_link(link, obj) # define GC_REGISTER_DISPLACEMENT(n) GC_register_displacement(n) #endif /* !GC_DEBUG */ @@ -1055,6 +1059,17 @@ GC_API int GC_CALL GC_general_register_disappearing_link(void ** /* link */, /* GC_NO_MEMORY if registration failed for lack of */ /* memory (and GC_oom_fn did not handle the problem). */ +GC_API int GC_CALL GC_register_long_link(void ** /* link */, + const void * /* obj */) + GC_ATTR_NONNULL(1) GC_ATTR_NONNULL(2); + /* Similar to the above but *link only gets cleared */ + /* obj becomes truly inaccessible. An object becomes */ + /* truly inaccessible when it can no longer be */ + /* resurrected from a finalizer (e.g. by assigning */ + /* itself to a pointer traceable from root). This can */ + /* be used to implement long weak pointers easily and */ + /* safely. */ + GC_API int GC_CALL GC_move_disappearing_link(void ** /* link */, void ** /* new_link */) GC_ATTR_NONNULL(2); @@ -1070,11 +1085,20 @@ GC_API int GC_CALL GC_move_disappearing_link(void ** /* link */, /* returned if new_link is equal to link), GC_NOT_FOUND */ /* if no link is registered at the original location. */ +GC_API int GC_CALL GC_move_long_link(void ** /* link */, + void ** /* new_link */) + GC_ATTR_NONNULL(2); + /* Similar to the above but for a link previously */ + /* registered via GC_register_long_link. */ + GC_API int GC_CALL GC_unregister_disappearing_link(void ** /* link */); /* Undoes a registration by either of the above two */ /* routines. Returns 0 if link was not actually */ /* registered (otherwise returns 1). */ +GC_API int GC_CALL GC_unregister_long_link(void ** /* link */); + /* Similar to the above but for the long_link routines. */ + /* Returns !=0 if GC_invoke_finalizers has something to do. */ GC_API int GC_CALL GC_should_invoke_finalizers(void); |