From 20031fb436cf204632124aaa66c73f2972d533ab Mon Sep 17 00:00:00 2001 From: ivmai Date: Thu, 10 Sep 2009 18:24:52 +0000 Subject: [PATCH] 2009-09-10 Ivan Maidanski (diff115) * finalize.c (GC_general_register_disappearing_link, GC_register_finalizer_inner): Remove unnecessary "ifdef THREADS" guard for LOCK/UNLOCK(). * finalize.c (GC_general_register_disappearing_link, GC_register_finalizer_inner): Get GC_oom_fn value before releasing the lock (to prevent data races). * gcj_mlc.c (GC_gcj_malloc, GC_debug_gcj_malloc, GC_gcj_malloc_ignore_off_page): Ditto. * mallocx.c (GC_generic_malloc_ignore_off_page): Ditto. * include/gc_inline.h (GC_FAST_MALLOC_GRANS): Use GC_get_oom_fn() instead of GC_oom_fn (to prevent data races). * malloc.c (GC_generic_malloc): Ditto. * mallocx.c (GC_memalign): Ditto. * pthread_support.c (pthread_create): Ditto. * gcj_mlc.c (maybe_finalize): Acquire the lock before setting last_finalized_no value to prevent data races. * include/gc.h (GC_gc_no, GC_get_gc_no, GC_oom_fn, GC_set_oom_fn, GC_set_find_leak, GC_set_finalize_on_demand, GC_set_java_finalization, GC_set_finalizer_notifier, GC_set_dont_expand, GC_set_full_freq, GC_set_non_gc_bytes, GC_set_no_dls, GC_set_free_space_divisor, GC_set_max_retries, GC_set_dont_precollect, GC_set_time_limit, GC_warn_proc): Refine the comment. * misc.c (GC_set_oom_fn): Ditto. * include/gc.h (GC_general_register_disappearing_link): Refine the comment (replace "soft" word with "weak"). * misc.c (GC_oom_fn, GC_get_gc_no, GC_get_parallel, GC_set_finalizer_notifier, GC_set_find_leak): Add the comment. * misc.c (GC_set_oom_fn, GC_get_oom_fn, GC_set_finalizer_notifier, GC_get_finalizer_notifier): Use LOCK/UNLOCK to prevent data races. --- ChangeLog | 34 +++++++++++++++++++ finalize.c | 55 ++++++++++--------------------- gcj_mlc.c | 17 ++++++---- include/gc.h | 95 +++++++++++++++++++++++++++++++++++++++++------------ include/gc_inline.h | 2 +- malloc.c | 2 +- mallocx.c | 10 ++++-- misc.c | 35 ++++++++++++++++++-- pthread_support.c | 3 +- 9 files changed, 179 insertions(+), 74 deletions(-) diff --git a/ChangeLog b/ChangeLog index 82e80aa..45d1b6e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,39 @@ 2009-09-10 Ivan Maidanski + (diff115) + + * finalize.c (GC_general_register_disappearing_link, + GC_register_finalizer_inner): Remove unnecessary "ifdef THREADS" + guard for LOCK/UNLOCK(). + * finalize.c (GC_general_register_disappearing_link, + GC_register_finalizer_inner): Get GC_oom_fn value before releasing + the lock (to prevent data races). + * gcj_mlc.c (GC_gcj_malloc, GC_debug_gcj_malloc, + GC_gcj_malloc_ignore_off_page): Ditto. + * mallocx.c (GC_generic_malloc_ignore_off_page): Ditto. + * include/gc_inline.h (GC_FAST_MALLOC_GRANS): Use GC_get_oom_fn() + instead of GC_oom_fn (to prevent data races). + * malloc.c (GC_generic_malloc): Ditto. + * mallocx.c (GC_memalign): Ditto. + * pthread_support.c (pthread_create): Ditto. + * gcj_mlc.c (maybe_finalize): Acquire the lock before setting + last_finalized_no value to prevent data races. + * include/gc.h (GC_gc_no, GC_get_gc_no, GC_oom_fn, GC_set_oom_fn, + GC_set_find_leak, GC_set_finalize_on_demand, + GC_set_java_finalization, GC_set_finalizer_notifier, + GC_set_dont_expand, GC_set_full_freq, GC_set_non_gc_bytes, + GC_set_no_dls, GC_set_free_space_divisor, GC_set_max_retries, + GC_set_dont_precollect, GC_set_time_limit, GC_warn_proc): Refine + the comment. + * misc.c (GC_set_oom_fn): Ditto. + * include/gc.h (GC_general_register_disappearing_link): Refine the + comment (replace "soft" word with "weak"). + * misc.c (GC_oom_fn, GC_get_gc_no, GC_get_parallel, + GC_set_finalizer_notifier, GC_set_find_leak): Add the comment. + * misc.c (GC_set_oom_fn, GC_get_oom_fn, GC_set_finalizer_notifier, + GC_get_finalizer_notifier): Use LOCK/UNLOCK to prevent data races. + +2009-09-10 Ivan Maidanski (diff114a, diff114b, diff114c) * dbg_mlc.c: Guard include with ifndef MSWINCE; include diff --git a/finalize.c b/finalize.c index 8e5736b..032ec04 100644 --- a/finalize.c +++ b/finalize.c @@ -154,9 +154,7 @@ GC_API int GC_CALL GC_general_register_disappearing_link(void * * link, if (((word)link & (ALIGNMENT-1)) || link == NULL) ABORT("Bad arg to GC_general_register_disappearing_link"); -# ifdef THREADS - LOCK(); -# endif + LOCK(); GC_ASSERT(obj != NULL && GC_base(obj) == obj); if (log_dl_table_size == -1 || GC_dl_entries > ((word)1 << log_dl_table_size)) { @@ -171,36 +169,29 @@ GC_API int GC_CALL GC_general_register_disappearing_link(void * * link, for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = dl_next(curr_dl)) { if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) { curr_dl -> dl_hidden_obj = HIDE_POINTER(obj); -# ifdef THREADS - UNLOCK(); -# endif + UNLOCK(); return(1); } } new_dl = (struct disappearing_link *) GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL); if (0 == new_dl) { -# ifdef THREADS - UNLOCK(); -# endif + GC_oom_func oom_fn = GC_oom_fn; + UNLOCK(); new_dl = (struct disappearing_link *) - GC_oom_fn(sizeof(struct disappearing_link)); + (*oom_fn)(sizeof(struct disappearing_link)); if (0 == new_dl) { return(2); } /* It's not likely we'll make it here, but ... */ -# ifdef THREADS - LOCK(); -# endif + LOCK(); } new_dl -> dl_hidden_obj = HIDE_POINTER(obj); new_dl -> dl_hidden_link = HIDE_POINTER(link); dl_set_next(new_dl, dl_head[index]); dl_head[index] = new_dl; GC_dl_entries++; -# ifdef THREADS - UNLOCK(); -# endif + UNLOCK(); return(0); } @@ -308,11 +299,10 @@ STATIC void GC_register_finalizer_inner(void * obj, size_t index; struct finalizable_object *new_fo; hdr *hhdr; + GC_oom_func oom_fn; DCL_LOCK_STATE; -# ifdef THREADS - LOCK(); -# endif + LOCK(); if (log_fo_table_size == -1 || GC_fo_entries > ((word)1 << log_fo_table_size)) { GC_grow_table((struct hash_chain_entry ***)(&fo_head), @@ -361,9 +351,7 @@ STATIC void GC_register_finalizer_inner(void * obj, fo_set_next(prev_fo, curr_fo); } } -# ifdef THREADS - UNLOCK(); -# endif + UNLOCK(); return; } prev_fo = curr_fo; @@ -372,34 +360,27 @@ STATIC void GC_register_finalizer_inner(void * obj, if (ofn) *ofn = 0; if (ocd) *ocd = 0; if (fn == 0) { -# ifdef THREADS - UNLOCK(); -# endif + UNLOCK(); return; } GET_HDR(base, hhdr); if (0 == hhdr) { /* We won't collect it, hence finalizer wouldn't be run. */ -# ifdef THREADS - UNLOCK(); -# endif + UNLOCK(); return; } new_fo = (struct finalizable_object *) GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL); if (EXPECT(0 == new_fo, FALSE)) { -# ifdef THREADS - UNLOCK(); -# endif + oom_fn = GC_oom_fn; + UNLOCK(); new_fo = (struct finalizable_object *) - GC_oom_fn(sizeof(struct finalizable_object)); + (*oom_fn)(sizeof(struct finalizable_object)); if (0 == new_fo) { return; } /* It's not likely we'll make it here, but ... */ -# ifdef THREADS - LOCK(); -# endif + LOCK(); } GC_ASSERT(GC_size(new_fo) >= sizeof(struct finalizable_object)); new_fo -> fo_hidden_base = (word)HIDE_POINTER(base); @@ -410,9 +391,7 @@ STATIC void GC_register_finalizer_inner(void * obj, fo_set_next(new_fo, fo_head[index]); GC_fo_entries++; fo_head[index] = new_fo; -# ifdef THREADS - UNLOCK(); -# endif + UNLOCK(); } GC_API void GC_CALL GC_register_finalizer(void * obj, diff --git a/gcj_mlc.c b/gcj_mlc.c index 6441ca2..5d772ff 100644 --- a/gcj_mlc.c +++ b/gcj_mlc.c @@ -126,8 +126,8 @@ static void maybe_finalize(void) if (!GC_is_initialized) return; UNLOCK(); GC_INVOKE_FINALIZERS(); - last_finalized_no = GC_gc_no; LOCK(); + last_finalized_no = GC_gc_no; } /* Allocate an object, clear it, and store the pointer to the */ @@ -154,8 +154,9 @@ static void maybe_finalize(void) maybe_finalize(); op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind); if (0 == op) { + GC_oom_func oom_fn = GC_oom_fn; UNLOCK(); - return(GC_oom_fn(lb)); + return((*oom_fn)(lb)); } } else { *opp = obj_link(op); @@ -169,8 +170,9 @@ static void maybe_finalize(void) maybe_finalize(); op = (ptr_t)GENERAL_MALLOC((word)lb, GC_gcj_kind); if (0 == op) { + GC_oom_func oom_fn = GC_oom_fn; UNLOCK(); - return(GC_oom_fn(lb)); + return((*oom_fn)(lb)); } *(void **)op = ptr_to_struct_containing_descr; UNLOCK(); @@ -193,12 +195,13 @@ GC_API void * GC_CALL GC_debug_gcj_malloc(size_t lb, maybe_finalize(); result = GC_generic_malloc_inner(lb + DEBUG_BYTES, GC_gcj_debug_kind); if (result == 0) { + GC_oom_func oom_fn = GC_oom_fn; UNLOCK(); GC_err_printf("GC_debug_gcj_malloc(%ld, %p) returning NIL (", (unsigned long)lb, ptr_to_struct_containing_descr); GC_err_puts(s); GC_err_printf(":%d)\n", i); - return(GC_oom_fn(lb)); + return((*oom_fn)(lb)); } *((void **)((ptr_t)result + sizeof(oh))) = ptr_to_struct_containing_descr; UNLOCK(); @@ -226,8 +229,9 @@ GC_API void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb, maybe_finalize(); op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind); if (0 == op) { + GC_oom_func oom_fn = GC_oom_fn; UNLOCK(); - return(GC_oom_fn(lb)); + return((*oom_fn)(lb)); } } else { *opp = obj_link(op); @@ -238,8 +242,9 @@ GC_API void * GC_CALL GC_gcj_malloc_ignore_off_page(size_t lb, maybe_finalize(); op = (ptr_t)GENERAL_MALLOC_IOP(lb, GC_gcj_kind); if (0 == op) { + GC_oom_func oom_fn = GC_oom_fn; UNLOCK(); - return(GC_oom_fn(lb)); + return((*oom_fn)(lb)); } } *(void **)op = ptr_to_struct_containing_descr; diff --git a/include/gc.h b/include/gc.h index 9110bf0..c649590 100644 --- a/include/gc.h +++ b/include/gc.h @@ -66,12 +66,14 @@ #endif /* Public read-only variables */ -/* Getter procedures are supplied in some cases and preferred for new */ -/* code. */ +/* The supplied getter functions are preferred for new code. */ GC_API GC_word GC_gc_no;/* Counter incremented per collection. */ /* Includes empty GCs at startup. */ GC_API GC_word GC_CALL GC_get_gc_no(void); + /* GC_get_gc_no() uses no synchronization, so */ + /* it requires GC_call_with_alloc_lock() to */ + /* avoid data races on multiprocessors. */ GC_API int GC_parallel; /* GC is parallelized for performance on */ /* multiprocessors. Currently set only */ @@ -86,16 +88,19 @@ GC_API int GC_CALL GC_get_parallel(void); /* Public R/W variables */ +/* The supplied setter and getter functions are preferred for new code. */ typedef void * (GC_CALLBACK * GC_oom_func)(size_t /* bytes_requested */); GC_API GC_oom_func GC_oom_fn; /* When there is insufficient memory to satisfy */ /* an allocation request, we return */ - /* (*GC_oom_fn)(). By default this just */ - /* returns 0. */ + /* (*GC_oom_fn)(size). By default this just */ + /* returns NULL. */ /* If it returns, it must return 0 or a valid */ /* pointer to a previously allocated heap */ - /* object. */ + /* object. GC_oom_fn must not be 0. */ + /* Both the supplied setter and the getter */ + /* acquire the GC lock (to avoid data races). */ GC_API void GC_CALL GC_set_oom_fn(GC_oom_func); GC_API GC_oom_func GC_CALL GC_get_oom_fn(void); @@ -104,6 +109,10 @@ GC_API int GC_find_leak; /* report inaccessible memory that was not */ /* deallocated with GC_free. Initial value */ /* is determined by FIND_LEAK macro. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_find_leak(int); GC_API int GC_CALL GC_get_find_leak(void); @@ -127,6 +136,10 @@ GC_API int GC_finalize_on_demand; /* call. The default is determined by whether */ /* the FINALIZE_ON_DEMAND macro is defined */ /* when the collector is built. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_finalize_on_demand(int); GC_API int GC_CALL GC_get_finalize_on_demand(void); @@ -138,6 +151,10 @@ GC_API int GC_java_finalization; /* determined by JAVA_FINALIZATION macro. */ /* Enables register_finalizer_unreachable to */ /* work correctly. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_java_finalization(int); GC_API int GC_CALL GC_get_java_finalization(void); @@ -149,7 +166,9 @@ GC_API GC_finalizer_notifier_proc GC_finalizer_notifier; /* GC_finalize_on_demand is set. */ /* Typically this will notify a finalization */ /* thread, which will call GC_invoke_finalizers */ - /* in response. */ + /* in response. May be 0 (means no notifier). */ + /* Both the supplied setter and the getter */ + /* acquire the GC lock (to avoid data races). */ GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc); GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void); @@ -165,6 +184,10 @@ GC_API int GC_dont_gc; /* != 0 ==> Dont collect. In versions 6.2a1+, */ GC_API int GC_dont_expand; /* Dont expand heap unless explicitly requested */ /* or forced to. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_dont_expand(int); GC_API int GC_CALL GC_get_dont_expand(void); @@ -188,6 +211,10 @@ GC_API int GC_full_freq; /* Number of partial collections between */ /* blocks. Values in the tens are now */ /* perfectly reasonable, unlike for */ /* earlier GC versions. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_full_freq(int); GC_API int GC_CALL GC_get_full_freq(void); @@ -196,6 +223,10 @@ GC_API GC_word GC_non_gc_bytes; /* Used only to control scheduling of collections. */ /* Updated by GC_malloc_uncollectable and GC_free. */ /* Wizards only. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_non_gc_bytes(GC_word); GC_API GC_word GC_CALL GC_get_non_gc_bytes(void); @@ -206,6 +237,10 @@ GC_API int GC_no_dls; /* In Microsoft Windows environments, this will */ /* usually also prevent registration of the */ /* main data segment as part of the root set. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_no_dls(int); GC_API int GC_CALL GC_get_no_dls(void); @@ -222,6 +257,10 @@ GC_API GC_word GC_free_space_divisor; /* but more collection time. Decreasing it */ /* will appreciably decrease collection time */ /* at the expense of space. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_free_space_divisor(GC_word); GC_API GC_word GC_CALL GC_get_free_space_divisor(void); @@ -229,6 +268,10 @@ GC_API GC_word GC_max_retries; /* The maximum number of GCs attempted before */ /* reporting out of memory after heap */ /* expansion fails. Initially 0. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_max_retries(GC_word); GC_API GC_word GC_CALL GC_get_max_retries(void); @@ -252,6 +295,10 @@ GC_API int GC_dont_precollect; /* Don't collect as part of */ /* before the first collection. */ /* Interferes with blacklisting. */ /* Wizards only. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_dont_precollect(int); GC_API int GC_CALL GC_get_dont_precollect(void); @@ -268,6 +315,10 @@ GC_API unsigned long GC_time_limit; /* Setting GC_time_limit to this value */ /* will disable the "pause time exceeded"*/ /* tests. */ + /* The setter and getter are unsynchronized, so */ + /* GC_call_with_alloc_lock() is required to */ + /* avoid data races (if the value is modified */ + /* after the GC is put to multi-threaded mode). */ GC_API void GC_CALL GC_set_time_limit(unsigned long); GC_API unsigned long GC_CALL GC_get_time_limit(void); @@ -808,20 +859,21 @@ GC_API int GC_CALL GC_general_register_disappearing_link (void * * link, /* can be used to implement weak pointers easily and */ /* safely. Typically link will point to a location */ /* holding a disguised pointer to obj. (A pointer */ - /* inside an "atomic" object is effectively */ - /* disguised.) In this way soft */ - /* pointers are broken before any object */ - /* reachable from them are finalized. Each link */ - /* May be registered only once, i.e. with one obj */ - /* value. This was added after a long email discussion */ - /* with John Ellis. */ - /* Obj must be a pointer to the first word of an object */ - /* we allocated. It is unsafe to explicitly deallocate */ - /* the object containing link. Explicitly deallocating */ - /* obj may or may not cause link to eventually be */ - /* cleared. */ - /* This can be used to implement certain types of */ - /* weak pointers. Note however that this generally */ + /* inside an "atomic" object is effectively disguised.) */ + /* In this way, weak pointers are broken before any */ + /* object reachable from them gets finalized. */ + /* Each link may be registered only with one obj value, */ + /* i.e. all objects but the last one (link registered */ + /* with) are ignored. This was added after a long */ + /* email discussion with John Ellis. */ + /* link must be non-NULL (and be properly aligned). */ + /* obj must be a pointer to the first word of an object */ + /* allocated by GC_malloc or friends. It is unsafe to */ + /* explicitly deallocate the object containing link. */ + /* Explicit deallocation of obj may or may not cause */ + /* link to eventually be cleared. */ + /* This function can be used to implement certain types */ + /* of weak pointers. Note, however, this generally */ /* requires that the allocation lock is held (see */ /* GC_call_with_alloc_lock() below) when the disguised */ /* pointer is accessed. Otherwise a strong pointer */ @@ -863,7 +915,8 @@ GC_API int GC_CALL GC_invoke_finalizers(void); #endif /* GC_set_warn_proc can be used to redirect or filter warning messages. */ -/* p may not be a NULL pointer. */ +/* p may not be a NULL pointer. Both the setter and the getter acquire */ +/* the GC lock (to avoid data races). */ typedef void (GC_CALLBACK * GC_warn_proc) (char *msg, GC_word arg); GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc p); /* GC_get_warn_proc returns the current warn_proc. */ diff --git a/include/gc_inline.h b/include/gc_inline.h index 5b5e51a..cf2e9f6 100644 --- a/include/gc_inline.h +++ b/include/gc_inline.h @@ -78,7 +78,7 @@ kind, my_fl); \ my_entry = *my_fl; \ if (my_entry == 0) { \ - result = GC_oom_fn((granules)*GC_GRANULE_BYTES); \ + result = (*GC_get_oom_fn())((granules)*GC_GRANULE_BYTES); \ goto out; \ } \ } \ diff --git a/malloc.c b/malloc.c index 3c3cca7..15adc5d 100644 --- a/malloc.c +++ b/malloc.c @@ -193,7 +193,7 @@ void * GC_generic_malloc(size_t lb, int k) } } if (0 == result) { - return((*GC_oom_fn)(lb)); + return((*GC_get_oom_fn())(lb)); } else { return(result); } diff --git a/mallocx.c b/mallocx.c index a86601d..ba14251 100644 --- a/mallocx.c +++ b/mallocx.c @@ -198,10 +198,12 @@ void * GC_generic_malloc_ignore_off_page(size_t lb, int k) } } GC_bytes_allocd += lb_rounded; - UNLOCK(); if (0 == result) { - return((*GC_oom_fn)(lb)); + GC_oom_func oom_fn = GC_oom_fn; + UNLOCK(); + return((*oom_fn)(lb)); } else { + UNLOCK(); if (init && !GC_debugging_started) { BZERO(result, n_blocks * HBLKSIZE); } @@ -500,7 +502,9 @@ GC_API void * GC_CALL GC_memalign(size_t align, size_t lb) if (align <= GRANULE_BYTES) return GC_malloc(lb); if (align >= HBLKSIZE/2 || lb >= HBLKSIZE/2) { - if (align > HBLKSIZE) return GC_oom_fn(LONG_MAX-1024) /* Fail */; + if (align > HBLKSIZE) { + return (*GC_get_oom_fn())(LONG_MAX-1024); /* Fail */ + } return GC_malloc(lb <= HBLKSIZE? HBLKSIZE : lb); /* Will be HBLKSIZE aligned. */ } diff --git a/misc.c b/misc.c index 25ee10c..4a25d9b 100644 --- a/misc.c +++ b/misc.c @@ -127,6 +127,7 @@ STATIC void * GC_CALLBACK GC_default_oom_fn(size_t bytes_requested) return(0); } +/* All accesses to it should be synchronized to avoid data races. */ GC_oom_func GC_oom_fn = GC_default_oom_fn; /* Set things up so that GC_size_map[i] >= granules(i), */ @@ -1286,6 +1287,11 @@ GC_API void GC_CALL GC_dump(void) #endif /* NO_DEBUGGING */ +/* Getter functions for the public Read-only variables. */ + +/* GC_get_gc_no() is unsynchronized and should be typically called */ +/* inside the context of GC_call_with_alloc_lock() to prevent data */ +/* races (on multiprocessors). */ GC_API GC_word GC_CALL GC_get_gc_no(void) { return GC_gc_no; @@ -1293,32 +1299,55 @@ GC_API GC_word GC_CALL GC_get_gc_no(void) GC_API int GC_CALL GC_get_parallel(void) { + /* GC_parallel is initialized at start-up. */ return GC_parallel; } -/* Setter and getter functions for the public R/W variables. */ +/* Setter and getter functions for the public R/W function variables. */ +/* These functions are synchronized (like GC_set_warn_proc() and */ +/* GC_get_warn_proc()). */ GC_API void GC_CALL GC_set_oom_fn(GC_oom_func fn) { GC_ASSERT(fn != 0); + LOCK(); GC_oom_fn = fn; + UNLOCK(); } GC_API GC_oom_func GC_CALL GC_get_oom_fn(void) { - return GC_oom_fn; + GC_oom_func fn; + LOCK(); + fn = GC_oom_fn; + UNLOCK(); + return fn; } GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc fn) { + /* fn may be 0 (means no finalizer notifier). */ + LOCK(); GC_finalizer_notifier = fn; + UNLOCK(); } GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void) { - return GC_finalizer_notifier; + GC_finalizer_notifier_proc fn; + LOCK(); + fn = GC_finalizer_notifier; + UNLOCK(); + return fn; } +/* Setter and getter functions for the public numeric R/W variables. */ +/* It is safe to call these functions even before GC_INIT(). */ +/* These functions are unsynchronized and should be typically called */ +/* inside the context of GC_call_with_alloc_lock() (if called after */ +/* GC_INIT()) to prevent data races (unless it is guaranteed the */ +/* collector is not multi-threaded at that execution point). */ + GC_API void GC_CALL GC_set_find_leak(int value) { /* value is of boolean type. */ diff --git a/pthread_support.c b/pthread_support.c index 93128df..cc5fd50 100644 --- a/pthread_support.c +++ b/pthread_support.c @@ -1188,7 +1188,8 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread, UNLOCK(); if (!parallel_initialized) GC_init_parallel(); if (0 == si && - (si = (struct start_info *)GC_oom_fn(sizeof(struct start_info))) == 0) + (si = (struct start_info *) + (*GC_get_oom_fn())(sizeof(struct start_info))) == 0) return(ENOMEM); sem_init(&(si -> registered), 0, 0); si -> start_routine = start_routine; -- 2.7.4