summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZach Saw <zach.saw@gmail.com>2012-11-19 12:34:10 +1100
committerZach Saw <zach.saw@gmail.com>2012-11-19 12:34:10 +1100
commitff44c6ae6730e054c028cc8c958d6ca961d4ebfa (patch)
treef561c245e40d90b529a9d108836accc289946177
parentdf392f378463ae22e7b0f9da253dd13aa3840d9f (diff)
downloadbdwgc-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.c93
-rw-r--r--include/gc.h24
2 files changed, 101 insertions, 16 deletions
diff --git a/finalize.c b/finalize.c
index 257fb619..6d5f26e2 100644
--- a/finalize.c
+++ b/finalize.c
@@ -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);