2009-09-10 Ivan Maidanski <ivmai@mail.ru>
authorivmai <ivmai>
Thu, 10 Sep 2009 18:24:52 +0000 (18:24 +0000)
committerIvan Maidanski <ivmai@mail.ru>
Tue, 26 Jul 2011 17:06:46 +0000 (21:06 +0400)
(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
finalize.c
gcj_mlc.c
include/gc.h
include/gc_inline.h
malloc.c
mallocx.c
misc.c
pthread_support.c

index 82e80aa..45d1b6e 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,39 @@
 
 2009-09-10  Ivan Maidanski <ivmai@mail.ru>
+       (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 <ivmai@mail.ru>
        (diff114a, diff114b, diff114c)
 
        * dbg_mlc.c: Guard include <errno.h> with ifndef MSWINCE; include
index 8e5736b..032ec04 100644 (file)
@@ -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,
index 6441ca2..5d772ff 100644 (file)
--- 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;
index 9110bf0..c649590 100644 (file)
 #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.                     */
index 5b5e51a..cf2e9f6 100644 (file)
@@ -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; \
                } \
            } \
index 3c3cca7..15adc5d 100644 (file)
--- 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);
     }
index a86601d..ba14251 100644 (file)
--- 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 (file)
--- 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. */
index 93128df..cc5fd50 100644 (file)
@@ -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;