LCOV - code coverage report
Current view: top level - mm/boehm-gc - misc.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 138 475 29.1 %
Date: 2015-06-10 18:10:59 Functions: 11 75 14.7 %

          Line data    Source code
       1             : /*
       2             :  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
       3             :  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
       4             :  * Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
       5             :  *
       6             :  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
       7             :  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
       8             :  *
       9             :  * Permission is hereby granted to use or copy this program
      10             :  * for any purpose,  provided the above notices are retained on all copies.
      11             :  * Permission to modify the code and to distribute modified code is granted,
      12             :  * provided the above notices are retained, and a notice that the code was
      13             :  * modified is included with the above copyright notice.
      14             :  */
      15             : 
      16             : #include "private/gc_pmark.h"
      17             : 
      18             : #include <stdio.h>
      19             : #include <limits.h>
      20             : #include <stdarg.h>
      21             : 
      22             : #ifndef MSWINCE
      23             : # include <signal.h>
      24             : #endif
      25             : 
      26             : #ifdef GC_SOLARIS_THREADS
      27             : # include <sys/syscall.h>
      28             : #endif
      29             : #if defined(MSWIN32) || defined(MSWINCE) \
      30             :     || (defined(CYGWIN32) && defined(GC_READ_ENV_FILE))
      31             : # ifndef WIN32_LEAN_AND_MEAN
      32             : #   define WIN32_LEAN_AND_MEAN 1
      33             : # endif
      34             : # define NOSERVICE
      35             : # include <windows.h>
      36             : #endif
      37             : 
      38             : #if defined(UNIX_LIKE) || defined(CYGWIN32)
      39             : # include <fcntl.h>
      40             : # include <sys/types.h>
      41             : # include <sys/stat.h>
      42             : #endif
      43             : 
      44             : #ifdef NONSTOP
      45             : # include <floss.h>
      46             : #endif
      47             : 
      48             : #ifdef THREADS
      49             : # ifdef PCR
      50             : #   include "il/PCR_IL.h"
      51             :     GC_INNER PCR_Th_ML GC_allocate_ml;
      52             : # elif defined(SN_TARGET_PS3)
      53             : #   include <pthread.h>
      54             :     GC_INNER pthread_mutex_t GC_allocate_ml;
      55             : # endif
      56             :   /* For other platforms with threads, the lock and possibly            */
      57             :   /* GC_lock_holder variables are defined in the thread support code.   */
      58             : #endif /* THREADS */
      59             : 
      60             : #ifdef DYNAMIC_LOADING
      61             :   /* We need to register the main data segment.  Returns  TRUE unless   */
      62             :   /* this is done implicitly as part of dynamic library registration.   */
      63             : # define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data()
      64             : #else
      65             :   /* Don't unnecessarily call GC_register_main_static_data() in case    */
      66             :   /* dyn_load.c isn't linked in.                                        */
      67             : # define GC_REGISTER_MAIN_STATIC_DATA() TRUE
      68             : #endif
      69             : 
      70             : #ifdef NEED_CANCEL_DISABLE_COUNT
      71             :   __thread unsigned char GC_cancel_disable_count = 0;
      72             : #endif
      73             : 
      74             : GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */;
      75             : 
      76             : GC_INNER GC_bool GC_debugging_started = FALSE;
      77             :         /* defined here so we don't have to load debug_malloc.o */
      78             : 
      79             : ptr_t GC_stackbottom = 0;
      80             : 
      81             : #ifdef IA64
      82             :   ptr_t GC_register_stackbottom = 0;
      83             : #endif
      84             : 
      85             : GC_bool GC_dont_gc = 0;
      86             : 
      87             : GC_bool GC_dont_precollect = 0;
      88             : 
      89             : GC_bool GC_quiet = 0; /* used also in pcr_interface.c */
      90             : 
      91             : #ifndef SMALL_CONFIG
      92             :   GC_bool GC_print_stats = 0;
      93             : #endif
      94             : 
      95             : #ifdef GC_PRINT_BACK_HEIGHT
      96             :   GC_INNER GC_bool GC_print_back_height = TRUE;
      97             : #else
      98             :   GC_INNER GC_bool GC_print_back_height = FALSE;
      99             : #endif
     100             : 
     101             : #ifndef NO_DEBUGGING
     102             :   GC_INNER GC_bool GC_dump_regularly = FALSE;
     103             :                                 /* Generate regular debugging dumps. */
     104             : #endif
     105             : 
     106             : #ifdef KEEP_BACK_PTRS
     107             :   GC_INNER long GC_backtraces = 0;
     108             :                 /* Number of random backtraces to generate for each GC. */
     109             : #endif
     110             : 
     111             : #ifdef FIND_LEAK
     112             :   int GC_find_leak = 1;
     113             : #else
     114             :   int GC_find_leak = 0;
     115             : #endif
     116             : 
     117             : #ifndef SHORT_DBG_HDRS
     118             : # ifdef GC_FINDLEAK_DELAY_FREE
     119             :     GC_INNER GC_bool GC_findleak_delay_free = TRUE;
     120             : # else
     121             :     GC_INNER GC_bool GC_findleak_delay_free = FALSE;
     122             : # endif
     123             : #endif /* !SHORT_DBG_HDRS */
     124             : 
     125             : #ifdef ALL_INTERIOR_POINTERS
     126             :   int GC_all_interior_pointers = 1;
     127             : #else
     128             :   int GC_all_interior_pointers = 0;
     129             : #endif
     130             : 
     131             : #ifdef GC_FORCE_UNMAP_ON_GCOLLECT
     132             :   /* Has no effect unless USE_MUNMAP.                           */
     133             :   /* Has no effect on implicitly-initiated garbage collections. */
     134             :   GC_INNER GC_bool GC_force_unmap_on_gcollect = TRUE;
     135             : #else
     136             :   GC_INNER GC_bool GC_force_unmap_on_gcollect = FALSE;
     137             : #endif
     138             : 
     139             : #ifndef GC_LARGE_ALLOC_WARN_INTERVAL
     140             : # define GC_LARGE_ALLOC_WARN_INTERVAL 5
     141             : #endif
     142             : GC_INNER long GC_large_alloc_warn_interval = GC_LARGE_ALLOC_WARN_INTERVAL;
     143             :                         /* Interval between unsuppressed warnings.      */
     144             : 
     145             : /*ARGSUSED*/
     146           0 : STATIC void * GC_CALLBACK GC_default_oom_fn(size_t bytes_requested)
     147             : {
     148           0 :     return(0);
     149             : }
     150             : 
     151             : /* All accesses to it should be synchronized to avoid data races.       */
     152             : GC_oom_func GC_oom_fn = GC_default_oom_fn;
     153             : 
     154             : #ifdef CAN_HANDLE_FORK
     155             : # ifdef HANDLE_FORK
     156             :     GC_INNER GC_bool GC_handle_fork = TRUE;
     157             :                         /* The value is examined by GC_thr_init.        */
     158             : # else
     159             :     GC_INNER GC_bool GC_handle_fork = FALSE;
     160             : # endif
     161             : #endif /* CAN_HANDLE_FORK */
     162             : 
     163             : /* Overrides the default handle-fork mode.  Non-zero value means GC     */
     164             : /* should install proper pthread_atfork handlers (or abort if not       */
     165             : /* supported).  Has effect only if called before GC_INIT.               */
     166             : /*ARGSUSED*/
     167           0 : GC_API void GC_CALL GC_set_handle_fork(int value)
     168             : {
     169             : # ifdef CAN_HANDLE_FORK
     170           0 :     if (!GC_is_initialized)
     171           0 :       GC_handle_fork = (GC_bool)value;
     172             : # elif defined(THREADS) || (defined(DARWIN) && defined(MPROTECT_VDB))
     173             :     if (!GC_is_initialized && value)
     174             :       ABORT("fork() handling disabled");
     175             : # else
     176             :     /* No at-fork handler is needed in the single-threaded mode.        */
     177             : # endif
     178           0 : }
     179             : 
     180             : /* Set things up so that GC_size_map[i] >= granules(i),                 */
     181             : /* but not too much bigger                                              */
     182             : /* and so that size_map contains relatively few distinct entries        */
     183             : /* This was originally stolen from Russ Atkinson's Cedar                */
     184             : /* quantization algorithm (but we precompute it).                       */
     185         163 : STATIC void GC_init_size_map(void)
     186             : {
     187             :     int i;
     188             : 
     189             :     /* Map size 0 to something bigger.                  */
     190             :     /* This avoids problems at lower levels.            */
     191         163 :       GC_size_map[0] = 1;
     192       62755 :     for (i = 1; i <= GRANULES_TO_BYTES(TINY_FREELISTS-1) - EXTRA_BYTES; i++) {
     193       62592 :         GC_size_map[i] = ROUNDED_UP_GRANULES(i);
     194             : #       ifndef _MSC_VER
     195             :           GC_ASSERT(GC_size_map[i] < TINY_FREELISTS);
     196             :           /* Seems to tickle bug in VC++ 2008 for AMD64 */
     197             : #       endif
     198             :     }
     199             :     /* We leave the rest of the array to be filled in on demand. */
     200         163 : }
     201             : 
     202             : /* Fill in additional entries in GC_size_map, including the ith one */
     203             : /* We assume the ith entry is currently 0.                              */
     204             : /* Note that a filled in section of the array ending at n always    */
     205             : /* has length at least n/4.                                             */
     206         720 : GC_INNER void GC_extend_size_map(size_t i)
     207             : {
     208         720 :     size_t orig_granule_sz = ROUNDED_UP_GRANULES(i);
     209         720 :     size_t granule_sz = orig_granule_sz;
     210         720 :     size_t byte_sz = GRANULES_TO_BYTES(granule_sz);
     211             :                         /* The size we try to preserve.         */
     212             :                         /* Close to i, unless this would        */
     213             :                         /* introduce too many distinct sizes.   */
     214         720 :     size_t smaller_than_i = byte_sz - (byte_sz >> 3);
     215         720 :     size_t much_smaller_than_i = byte_sz - (byte_sz >> 2);
     216             :     size_t low_limit;   /* The lowest indexed entry we  */
     217             :                         /* initialize.                  */
     218             :     size_t j;
     219             : 
     220         720 :     if (GC_size_map[smaller_than_i] == 0) {
     221         451 :         low_limit = much_smaller_than_i;
     222         451 :         while (GC_size_map[low_limit] != 0) low_limit++;
     223             :     } else {
     224         269 :         low_limit = smaller_than_i + 1;
     225         269 :         while (GC_size_map[low_limit] != 0) low_limit++;
     226         269 :         granule_sz = ROUNDED_UP_GRANULES(low_limit);
     227         269 :         granule_sz += granule_sz >> 3;
     228         269 :         if (granule_sz < orig_granule_sz) granule_sz = orig_granule_sz;
     229             :     }
     230             :     /* For these larger sizes, we use an even number of granules.       */
     231             :     /* This makes it easier to, for example, construct a 16byte-aligned */
     232             :     /* allocator even if GRANULE_BYTES is 8.                            */
     233         720 :         granule_sz += 1;
     234         720 :         granule_sz &= ~1;
     235         720 :     if (granule_sz > MAXOBJGRANULES) {
     236           0 :         granule_sz = MAXOBJGRANULES;
     237             :     }
     238             :     /* If we can fit the same number of larger objects in a block,      */
     239             :     /* do so.                                                   */
     240             :     {
     241         720 :         size_t number_of_objs = HBLK_GRANULES/granule_sz;
     242         720 :         granule_sz = HBLK_GRANULES/number_of_objs;
     243         720 :         granule_sz &= ~1;
     244             :     }
     245         720 :     byte_sz = GRANULES_TO_BYTES(granule_sz);
     246             :     /* We may need one extra byte;                      */
     247             :     /* don't always fill in GC_size_map[byte_sz]        */
     248         720 :     byte_sz -= EXTRA_BYTES;
     249             : 
     250         720 :     for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = granule_sz;
     251         720 : }
     252             : 
     253             : 
     254             : /*
     255             :  * The following is a gross hack to deal with a problem that can occur
     256             :  * on machines that are sloppy about stack frame sizes, notably SPARC.
     257             :  * Bogus pointers may be written to the stack and not cleared for
     258             :  * a LONG time, because they always fall into holes in stack frames
     259             :  * that are not written.  We partially address this by clearing
     260             :  * sections of the stack whenever we get control.
     261             :  */
     262             : # ifdef THREADS
     263             : #   define BIG_CLEAR_SIZE 2048  /* Clear this much now and then.        */
     264             : #   define SMALL_CLEAR_SIZE 256 /* Clear this much every time.          */
     265             : # else
     266             :   STATIC word GC_stack_last_cleared = 0; /* GC_no when we last did this */
     267             :   STATIC ptr_t GC_min_sp = NULL;
     268             :                         /* Coolest stack pointer value from which       */
     269             :                         /* we've already cleared the stack.             */
     270             :   STATIC ptr_t GC_high_water = NULL;
     271             :                         /* "hottest" stack pointer value we have seen   */
     272             :                         /* recently.  Degrades over time.               */
     273             :   STATIC word GC_bytes_allocd_at_reset = 0;
     274             : #   define DEGRADE_RATE 50
     275             : # endif
     276             : 
     277             : # define CLEAR_SIZE 213  /* Granularity for GC_clear_stack_inner */
     278             : 
     279             : #if defined(ASM_CLEAR_CODE)
     280             :   void *GC_clear_stack_inner(void *, ptr_t);
     281             : #else
     282             :   /* Clear the stack up to about limit.  Return arg.  This function is  */
     283             :   /* not static because it could also be errorneously defined in .S     */
     284             :   /* file, so this error would be caught by the linker.                 */
     285             :   /*ARGSUSED*/
     286       40480 :   void * GC_clear_stack_inner(void *arg, ptr_t limit)
     287             :   {
     288             :     volatile word dummy[CLEAR_SIZE];
     289             : 
     290       40480 :     BZERO((/* no volatile */ void *)dummy, sizeof(dummy));
     291       40480 :     if ((word)GC_approx_sp() COOLER_THAN (word)limit) {
     292       36432 :         (void) GC_clear_stack_inner(arg, limit);
     293             :     }
     294             :     /* Make sure the recursive call is not a tail call, and the bzero   */
     295             :     /* call is not recognized as dead code.                             */
     296       40480 :     GC_noop1((word)dummy);
     297       40480 :     return(arg);
     298             :   }
     299             : #endif
     300             : 
     301             : /* Clear some of the inaccessible part of the stack.  Returns its       */
     302             : /* argument, so it can be used in a tail call position, hence clearing  */
     303             : /* another frame.                                                       */
     304       54023 : GC_API void * GC_CALL GC_clear_stack(void *arg)
     305             : {
     306       54023 :     ptr_t sp = GC_approx_sp();  /* Hotter than actual sp */
     307             : #   ifdef THREADS
     308             :         word dummy[SMALL_CLEAR_SIZE];
     309             :         static unsigned random_no = 0;
     310             :                                  /* Should be more random than it is ... */
     311             :                                  /* Used to occasionally clear a bigger  */
     312             :                                  /* chunk.                               */
     313             : #   endif
     314             :     ptr_t limit;
     315             : 
     316             : #   define SLOP 400
     317             :         /* Extra bytes we clear every time.  This clears our own        */
     318             :         /* activation record, and should cause more frequent            */
     319             :         /* clearing near the cold end of the stack, a good thing.       */
     320             : #   define GC_SLOP 4000
     321             :         /* We make GC_high_water this much hotter than we really saw    */
     322             :         /* saw it, to cover for GC noise etc. above our current frame.  */
     323             : #   define CLEAR_THRESHOLD 100000
     324             :         /* We restart the clearing process after this many bytes of     */
     325             :         /* allocation.  Otherwise very heavily recursive programs       */
     326             :         /* with sparse stacks may result in heaps that grow almost      */
     327             :         /* without bounds.  As the heap gets larger, collection         */
     328             :         /* frequency decreases, thus clearing frequency would decrease, */
     329             :         /* thus more junk remains accessible, thus the heap gets        */
     330             :         /* larger ...                                                   */
     331             : # ifdef THREADS
     332       54023 :     if (++random_no % 13 == 0) {
     333        4048 :         limit = sp;
     334        4048 :         MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
     335        4048 :         limit = (ptr_t)((word)limit & ~0xf);
     336             :                         /* Make it sufficiently aligned for assembly    */
     337             :                         /* implementations of GC_clear_stack_inner.     */
     338        4048 :         return GC_clear_stack_inner(arg, limit);
     339             :     } else {
     340       49975 :         BZERO(dummy, SMALL_CLEAR_SIZE*sizeof(word));
     341       49975 :         return arg;
     342             :     }
     343             : # else
     344             :     if (GC_gc_no > GC_stack_last_cleared) {
     345             :         /* Start things over, so we clear the entire stack again */
     346             :         if (GC_stack_last_cleared == 0) GC_high_water = (ptr_t)GC_stackbottom;
     347             :         GC_min_sp = GC_high_water;
     348             :         GC_stack_last_cleared = GC_gc_no;
     349             :         GC_bytes_allocd_at_reset = GC_bytes_allocd;
     350             :     }
     351             :     /* Adjust GC_high_water */
     352             :         MAKE_COOLER(GC_high_water, WORDS_TO_BYTES(DEGRADE_RATE) + GC_SLOP);
     353             :         if (sp HOTTER_THAN GC_high_water) {
     354             :             GC_high_water = sp;
     355             :         }
     356             :         MAKE_HOTTER(GC_high_water, GC_SLOP);
     357             :     limit = GC_min_sp;
     358             :     MAKE_HOTTER(limit, SLOP);
     359             :     if (sp COOLER_THAN limit) {
     360             :         limit = (ptr_t)((word)limit & ~0xf);
     361             :                         /* Make it sufficiently aligned for assembly    */
     362             :                         /* implementations of GC_clear_stack_inner.     */
     363             :         GC_min_sp = sp;
     364             :         return(GC_clear_stack_inner(arg, limit));
     365             :     } else if (GC_bytes_allocd - GC_bytes_allocd_at_reset > CLEAR_THRESHOLD) {
     366             :         /* Restart clearing process, but limit how much clearing we do. */
     367             :         GC_min_sp = sp;
     368             :         MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
     369             :         if (GC_min_sp HOTTER_THAN GC_high_water) GC_min_sp = GC_high_water;
     370             :         GC_bytes_allocd_at_reset = GC_bytes_allocd;
     371             :     }
     372             :     return(arg);
     373             : # endif
     374             : }
     375             : 
     376             : 
     377             : /* Return a pointer to the base address of p, given a pointer to a      */
     378             : /* an address within an object.  Return 0 o.w.                          */
     379        1094 : GC_API void * GC_CALL GC_base(void * p)
     380             : {
     381             :     ptr_t r;
     382             :     struct hblk *h;
     383             :     bottom_index *bi;
     384             :     hdr *candidate_hdr;
     385             :     ptr_t limit;
     386             : 
     387        1094 :     r = p;
     388        1094 :     if (!GC_is_initialized) return 0;
     389        1094 :     h = HBLKPTR(r);
     390        1094 :     GET_BI(r, bi);
     391        1094 :     candidate_hdr = HDR_FROM_BI(bi, r);
     392        1094 :     if (candidate_hdr == 0) return(0);
     393             :     /* If it's a pointer to the middle of a large object, move it       */
     394             :     /* to the beginning.                                                */
     395         253 :         while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
     396         129 :            h = FORWARDED_ADDR(h,candidate_hdr);
     397         129 :            r = (ptr_t)h;
     398         129 :            candidate_hdr = HDR(h);
     399             :         }
     400          62 :     if (HBLK_IS_FREE(candidate_hdr)) return(0);
     401             :     /* Make sure r points to the beginning of the object */
     402          62 :         r = (ptr_t)((word)r & ~(WORDS_TO_BYTES(1) - 1));
     403             :         {
     404          62 :             size_t offset = HBLKDISPL(r);
     405          62 :             word sz = candidate_hdr -> hb_sz;
     406          62 :             size_t obj_displ = offset % sz;
     407             : 
     408          62 :             r -= obj_displ;
     409          62 :             limit = r + sz;
     410          62 :             if (limit > (ptr_t)(h + 1) && sz <= HBLKSIZE) {
     411           0 :                 return(0);
     412             :             }
     413          62 :             if ((ptr_t)p >= limit) return(0);
     414             :         }
     415          61 :     return((void *)r);
     416             : }
     417             : 
     418             : 
     419             : /* Return the size of an object, given a pointer to its base.           */
     420             : /* (For small objects this also happens to work from interior pointers, */
     421             : /* but that shouldn't be relied upon.)                                  */
     422           0 : GC_API size_t GC_CALL GC_size(const void * p)
     423             : {
     424           0 :     hdr * hhdr = HDR(p);
     425             : 
     426           0 :     return hhdr -> hb_sz;
     427             : }
     428             : 
     429             : 
     430             : /* These getters remain unsynchronized for compatibility (since some    */
     431             : /* clients could call some of them from a GC callback holding the       */
     432             : /* allocator lock).                                                     */
     433         163 : GC_API size_t GC_CALL GC_get_heap_size(void)
     434             : {
     435             :     /* ignore the memory space returned to OS (i.e. count only the      */
     436             :     /* space owned by the garbage collector)                            */
     437         163 :     return (size_t)(GC_heapsize - GC_unmapped_bytes);
     438             : }
     439             : 
     440           0 : GC_API size_t GC_CALL GC_get_free_bytes(void)
     441             : {
     442             :     /* ignore the memory space returned to OS */
     443           0 :     return (size_t)(GC_large_free_bytes - GC_unmapped_bytes);
     444             : }
     445             : 
     446           0 : GC_API size_t GC_CALL GC_get_unmapped_bytes(void)
     447             : {
     448           0 :     return (size_t)GC_unmapped_bytes;
     449             : }
     450             : 
     451           0 : GC_API size_t GC_CALL GC_get_bytes_since_gc(void)
     452             : {
     453           0 :     return (size_t)GC_bytes_allocd;
     454             : }
     455             : 
     456           0 : GC_API size_t GC_CALL GC_get_total_bytes(void)
     457             : {
     458           0 :     return (size_t)(GC_bytes_allocd + GC_bytes_allocd_before_gc);
     459             : }
     460             : 
     461             : /* Return the heap usage information.  This is a thread-safe (atomic)   */
     462             : /* alternative for the five above getters.  NULL pointer is allowed for */
     463             : /* any argument.  Returned (filled in) values are of word type.         */
     464           0 : GC_API void GC_CALL GC_get_heap_usage_safe(GC_word *pheap_size,
     465             :                         GC_word *pfree_bytes, GC_word *punmapped_bytes,
     466             :                         GC_word *pbytes_since_gc, GC_word *ptotal_bytes)
     467             : {
     468             :   DCL_LOCK_STATE;
     469             : 
     470           0 :   LOCK();
     471           0 :   if (pheap_size != NULL)
     472           0 :     *pheap_size = GC_heapsize - GC_unmapped_bytes;
     473           0 :   if (pfree_bytes != NULL)
     474           0 :     *pfree_bytes = GC_large_free_bytes - GC_unmapped_bytes;
     475           0 :   if (punmapped_bytes != NULL)
     476           0 :     *punmapped_bytes = GC_unmapped_bytes;
     477           0 :   if (pbytes_since_gc != NULL)
     478           0 :     *pbytes_since_gc = GC_bytes_allocd;
     479           0 :   if (ptotal_bytes != NULL)
     480           0 :     *ptotal_bytes = GC_bytes_allocd + GC_bytes_allocd_before_gc;
     481           0 :   UNLOCK();
     482           0 : }
     483             : 
     484             : 
     485             : #ifdef THREADS
     486           0 :   GC_API int GC_CALL GC_get_suspend_signal(void)
     487             :   {
     488             : #   ifdef SIG_SUSPEND
     489           0 :       return SIG_SUSPEND;
     490             : #   else
     491             :       return -1;
     492             : #   endif
     493             :   }
     494             : #endif /* THREADS */
     495             : 
     496             : #if !defined(_MAX_PATH) && (defined(MSWIN32) || defined(MSWINCE) \
     497             :                             || defined(CYGWIN32))
     498             : # define _MAX_PATH MAX_PATH
     499             : #endif
     500             : 
     501             : #ifdef GC_READ_ENV_FILE
     502             :   /* This works for Win32/WinCE for now.  Really useful only for WinCE. */
     503             :   STATIC char *GC_envfile_content = NULL;
     504             :                         /* The content of the GC "env" file with CR and */
     505             :                         /* LF replaced to '\0'.  NULL if the file is    */
     506             :                         /* missing or empty.  Otherwise, always ends    */
     507             :                         /* with '\0'.                                   */
     508             :   STATIC unsigned GC_envfile_length = 0;
     509             :                         /* Length of GC_envfile_content (if non-NULL).  */
     510             : 
     511             : # ifndef GC_ENVFILE_MAXLEN
     512             : #   define GC_ENVFILE_MAXLEN 0x4000
     513             : # endif
     514             : 
     515             :   /* The routine initializes GC_envfile_content from the GC "env" file. */
     516             :   STATIC void GC_envfile_init(void)
     517             :   {
     518             : #   if defined(MSWIN32) || defined(MSWINCE) || defined(CYGWIN32)
     519             :       HANDLE hFile;
     520             :       char *content;
     521             :       unsigned ofs;
     522             :       unsigned len;
     523             :       DWORD nBytesRead;
     524             :       TCHAR path[_MAX_PATH + 0x10]; /* buffer for path + ext */
     525             :       len = (unsigned)GetModuleFileName(NULL /* hModule */, path,
     526             :                                         _MAX_PATH + 1);
     527             :       /* If GetModuleFileName() has failed then len is 0. */
     528             :       if (len > 4 && path[len - 4] == (TCHAR)'.') {
     529             :         len -= 4; /* strip executable file extension */
     530             :       }
     531             :       memcpy(&path[len], TEXT(".gc.env"), sizeof(TEXT(".gc.env")));
     532             :       hFile = CreateFile(path, GENERIC_READ,
     533             :                          FILE_SHARE_READ | FILE_SHARE_WRITE,
     534             :                          NULL /* lpSecurityAttributes */, OPEN_EXISTING,
     535             :                          FILE_ATTRIBUTE_NORMAL, NULL /* hTemplateFile */);
     536             :       if (hFile == INVALID_HANDLE_VALUE)
     537             :         return; /* the file is absent or the operation is failed */
     538             :       len = (unsigned)GetFileSize(hFile, NULL);
     539             :       if (len <= 1 || len >= GC_ENVFILE_MAXLEN) {
     540             :         CloseHandle(hFile);
     541             :         return; /* invalid file length - ignoring the file content */
     542             :       }
     543             :       /* At this execution point, GC_setpagesize() and GC_init_win32()  */
     544             :       /* must already be called (for GET_MEM() to work correctly).      */
     545             :       content = (char *)GET_MEM(len + 1);
     546             :       if (content == NULL) {
     547             :         CloseHandle(hFile);
     548             :         return; /* allocation failure */
     549             :       }
     550             :       ofs = 0;
     551             :       nBytesRead = (DWORD)-1L;
     552             :           /* Last ReadFile() call should clear nBytesRead on success. */
     553             :       while (ReadFile(hFile, content + ofs, len - ofs + 1, &nBytesRead,
     554             :                       NULL /* lpOverlapped */) && nBytesRead != 0) {
     555             :         if ((ofs += nBytesRead) > len)
     556             :           break;
     557             :       }
     558             :       CloseHandle(hFile);
     559             :       if (ofs != len || nBytesRead != 0)
     560             :         return; /* read operation is failed - ignoring the file content */
     561             :       content[ofs] = '\0';
     562             :       while (ofs-- > 0) {
     563             :        if (content[ofs] == '\r' || content[ofs] == '\n')
     564             :          content[ofs] = '\0';
     565             :       }
     566             :       GC_envfile_length = len + 1;
     567             :       GC_envfile_content = content;
     568             : #   endif
     569             :   }
     570             : 
     571             :   /* This routine scans GC_envfile_content for the specified            */
     572             :   /* environment variable (and returns its value if found).             */
     573             :   GC_INNER char * GC_envfile_getenv(const char *name)
     574             :   {
     575             :     char *p;
     576             :     char *end_of_content;
     577             :     unsigned namelen;
     578             : #   ifndef NO_GETENV
     579             :       p = getenv(name); /* try the standard getenv() first */
     580             :       if (p != NULL)
     581             :         return *p != '\0' ? p : NULL;
     582             : #   endif
     583             :     p = GC_envfile_content;
     584             :     if (p == NULL)
     585             :       return NULL; /* "env" file is absent (or empty) */
     586             :     namelen = strlen(name);
     587             :     if (namelen == 0) /* a sanity check */
     588             :       return NULL;
     589             :     for (end_of_content = p + GC_envfile_length;
     590             :          p != end_of_content; p += strlen(p) + 1) {
     591             :       if (strncmp(p, name, namelen) == 0 && *(p += namelen) == '=') {
     592             :         p++; /* the match is found; skip '=' */
     593             :         return *p != '\0' ? p : NULL;
     594             :       }
     595             :       /* If not matching then skip to the next line. */
     596             :     }
     597             :     return NULL; /* no match found */
     598             :   }
     599             : #endif /* GC_READ_ENV_FILE */
     600             : 
     601             : GC_INNER GC_bool GC_is_initialized = FALSE;
     602             : 
     603             : #if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS)
     604             :     GC_INNER CRITICAL_SECTION GC_write_cs;
     605             : #endif
     606             : 
     607           0 : STATIC void GC_exit_check(void)
     608             : {
     609           0 :    GC_gcollect();
     610           0 : }
     611             : 
     612             : #ifdef UNIX_LIKE
     613           0 :   static void looping_handler(int sig)
     614             :   {
     615           0 :     GC_err_printf("Caught signal %d: looping in handler\n", sig);
     616           0 :     for (;;) {}
     617             :   }
     618             : 
     619             :   static GC_bool installed_looping_handler = FALSE;
     620             : 
     621         163 :   static void maybe_install_looping_handler(void)
     622             :   {
     623             :     /* Install looping handler before the write fault handler, so we    */
     624             :     /* handle write faults correctly.                                   */
     625         163 :     if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) {
     626           0 :       GC_set_and_save_fault_handler(looping_handler);
     627           0 :       installed_looping_handler = TRUE;
     628             :     }
     629         163 :   }
     630             : 
     631             : #else /* !UNIX_LIKE */
     632             : # define maybe_install_looping_handler()
     633             : #endif
     634             : 
     635             : #if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
     636             :   STATIC int GC_stdout = 1;
     637             :   STATIC int GC_stderr = 2;
     638             :   STATIC int GC_log = 2; /* stderr */
     639             : #endif
     640             : 
     641           0 : STATIC word GC_parse_mem_size_arg(const char *str)
     642             : {
     643             :   char *endptr;
     644           0 :   word result = 0; /* bad value */
     645             :   char ch;
     646             : 
     647           0 :   if (*str != '\0') {
     648           0 :     result = (word)STRTOULL(str, &endptr, 10);
     649           0 :     ch = *endptr;
     650           0 :     if (ch != '\0') {
     651           0 :       if (*(endptr + 1) != '\0')
     652           0 :         return 0;
     653             :       /* Allow k, M or G suffix. */
     654           0 :       switch (ch) {
     655             :       case 'K':
     656             :       case 'k':
     657           0 :         result <<= 10;
     658           0 :         break;
     659             :       case 'M':
     660             :       case 'm':
     661           0 :         result <<= 20;
     662           0 :         break;
     663             :       case 'G':
     664             :       case 'g':
     665           0 :         result <<= 30;
     666           0 :         break;
     667             :       default:
     668           0 :         result = 0;
     669             :       }
     670             :     }
     671             :   }
     672           0 :   return result;
     673             : }
     674             : 
     675         163 : GC_API void GC_CALL GC_init(void)
     676             : {
     677             :     /* LOCK(); -- no longer does anything this early. */
     678             :     word initial_heap_sz;
     679             :     IF_CANCEL(int cancel_state;)
     680             : 
     681         163 :     if (GC_is_initialized) return;
     682             : #   ifdef REDIRECT_MALLOC
     683             :       {
     684             :         static GC_bool init_started = FALSE;
     685             :         if (init_started)
     686             :           ABORT("Redirected malloc() called during GC init");
     687             :         init_started = TRUE;
     688             :       }
     689             : #   endif
     690             : 
     691             : #   ifdef GC_INITIAL_HEAP_SIZE
     692             :       initial_heap_sz = divHBLKSZ(GC_INITIAL_HEAP_SIZE);
     693             : #   else
     694         163 :       initial_heap_sz = (word)MINHINCR;
     695             : #   endif
     696         163 :     DISABLE_CANCEL(cancel_state);
     697             :     /* Note that although we are nominally called with the */
     698             :     /* allocation lock held, the allocation lock is now    */
     699             :     /* only really acquired once a second thread is forked.*/
     700             :     /* And the initialization code needs to run before     */
     701             :     /* then.  Thus we really don't hold any locks, and can */
     702             :     /* in fact safely initialize them here.                */
     703             : #   ifdef THREADS
     704             :       GC_ASSERT(!GC_need_to_lock);
     705             : #     ifdef SN_TARGET_PS3
     706             :         {
     707             :           pthread_mutexattr_t mattr;
     708             :           pthread_mutexattr_init(&mattr);
     709             :           pthread_mutex_init(&GC_allocate_ml, &mattr);
     710             :           pthread_mutexattr_destroy(&mattr);
     711             :         }
     712             : #     endif
     713             : #   endif /* THREADS */
     714             : #   if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
     715             :      {
     716             : #     ifndef MSWINCE
     717             :         BOOL (WINAPI *pfn) (LPCRITICAL_SECTION, DWORD) = NULL;
     718             :         HMODULE hK32 = GetModuleHandle(TEXT("kernel32.dll"));
     719             :         if (hK32)
     720             :           pfn = (BOOL (WINAPI *) (LPCRITICAL_SECTION, DWORD))
     721             :                 GetProcAddress (hK32,
     722             :                                 "InitializeCriticalSectionAndSpinCount");
     723             :         if (pfn)
     724             :             pfn(&GC_allocate_ml, 4000);
     725             :         else
     726             : #     endif /* !MSWINCE */
     727             :         /* else */ InitializeCriticalSection (&GC_allocate_ml);
     728             :      }
     729             : #   endif /* GC_WIN32_THREADS */
     730             : #   if (defined(MSWIN32) || defined(MSWINCE)) && defined(THREADS)
     731             :       InitializeCriticalSection(&GC_write_cs);
     732             : #   endif
     733         163 :     GC_setpagesize();
     734             : #   ifdef MSWIN32
     735             :       GC_init_win32();
     736             : #   endif
     737             : #   ifdef GC_READ_ENV_FILE
     738             :       GC_envfile_init();
     739             : #   endif
     740             : #   ifndef SMALL_CONFIG
     741             : #     ifdef GC_PRINT_VERBOSE_STATS
     742             :         /* This is useful for debugging and profiling on platforms with */
     743             :         /* missing getenv() (like WinCE).                               */
     744             :         GC_print_stats = VERBOSE;
     745             : #     else
     746         163 :         if (0 != GETENV("GC_PRINT_VERBOSE_STATS")) {
     747           0 :           GC_print_stats = VERBOSE;
     748         163 :         } else if (0 != GETENV("GC_PRINT_STATS")) {
     749           0 :           GC_print_stats = 1;
     750             :         }
     751             : #     endif
     752             : #     if defined(UNIX_LIKE) || defined(CYGWIN32)
     753             :         {
     754         163 :           char * file_name = GETENV("GC_LOG_FILE");
     755         163 :           if (0 != file_name) {
     756           0 :             int log_d = open(file_name, O_CREAT|O_WRONLY|O_APPEND, 0666);
     757           0 :             if (log_d < 0) {
     758           0 :               GC_err_printf("Failed to open %s as log file\n", file_name);
     759             :             } else {
     760             :               char *str;
     761           0 :               GC_log = log_d;
     762           0 :               str = GETENV("GC_ONLY_LOG_TO_FILE");
     763             : #             ifdef GC_ONLY_LOG_TO_FILE
     764             :                 /* The similar environment variable set to "0"  */
     765             :                 /* overrides the effect of the macro defined.   */
     766             :                 if (str != NULL && *str == '0' && *(str + 1) == '\0')
     767             : #             else
     768             :                 /* Otherwise setting the environment variable   */
     769             :                 /* to anything other than "0" will prevent from */
     770             :                 /* redirecting stdout/err to the log file.      */
     771           0 :                 if (str == NULL || (*str == '0' && *(str + 1) == '\0'))
     772             : #             endif
     773             :               {
     774           0 :                 GC_stdout = log_d;
     775           0 :                 GC_stderr = log_d;
     776             :               }
     777             :             }
     778             :           }
     779             :         }
     780             : #     endif
     781             : #   endif /* !SMALL_CONFIG */
     782             : #   ifndef NO_DEBUGGING
     783         163 :       if (0 != GETENV("GC_DUMP_REGULARLY")) {
     784           0 :         GC_dump_regularly = TRUE;
     785             :       }
     786             : #   endif
     787             : #   ifdef KEEP_BACK_PTRS
     788             :       {
     789             :         char * backtraces_string = GETENV("GC_BACKTRACES");
     790             :         if (0 != backtraces_string) {
     791             :           GC_backtraces = atol(backtraces_string);
     792             :           if (backtraces_string[0] == '\0') GC_backtraces = 1;
     793             :         }
     794             :       }
     795             : #   endif
     796         163 :     if (0 != GETENV("GC_FIND_LEAK")) {
     797           0 :       GC_find_leak = 1;
     798             :     }
     799             : #   ifndef SHORT_DBG_HDRS
     800         163 :       if (0 != GETENV("GC_FINDLEAK_DELAY_FREE")) {
     801           0 :         GC_findleak_delay_free = TRUE;
     802             :       }
     803             : #   endif
     804         163 :     if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
     805           0 :       GC_all_interior_pointers = 1;
     806             :     }
     807         163 :     if (0 != GETENV("GC_DONT_GC")) {
     808           0 :       GC_dont_gc = 1;
     809             :     }
     810         163 :     if (0 != GETENV("GC_PRINT_BACK_HEIGHT")) {
     811           0 :       GC_print_back_height = TRUE;
     812             :     }
     813         163 :     if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) {
     814           0 :       GC_large_alloc_warn_interval = LONG_MAX;
     815             :     }
     816             :     {
     817         163 :       char * addr_string = GETENV("GC_TRACE");
     818         163 :       if (0 != addr_string) {
     819             : #       ifndef ENABLE_TRACE
     820           0 :           WARN("Tracing not enabled: Ignoring GC_TRACE value\n", 0);
     821             : #       else
     822             :           word addr = (word)STRTOULL(addr_string, NULL, 16);
     823             :           if (addr < 0x1000)
     824             :               WARN("Unlikely trace address: %p\n", addr);
     825             :           GC_trace_addr = (ptr_t)addr;
     826             : #       endif
     827             :       }
     828             :     }
     829             : #   ifndef GC_DISABLE_INCREMENTAL
     830             :       {
     831         163 :         char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
     832         163 :         if (0 != time_limit_string) {
     833           0 :           long time_limit = atol(time_limit_string);
     834           0 :           if (time_limit < 5) {
     835           0 :             WARN("GC_PAUSE_TIME_TARGET environment variable value too small "
     836             :                  "or bad syntax: Ignoring\n", 0);
     837             :           } else {
     838           0 :             GC_time_limit = time_limit;
     839             :           }
     840             :         }
     841             :       }
     842             : #   endif
     843             : #   ifndef SMALL_CONFIG
     844             :       {
     845         163 :         char * full_freq_string = GETENV("GC_FULL_FREQUENCY");
     846         163 :         if (full_freq_string != NULL) {
     847           0 :           int full_freq = atoi(full_freq_string);
     848           0 :           if (full_freq > 0)
     849           0 :             GC_full_freq = full_freq;
     850             :         }
     851             :       }
     852             : #   endif
     853             :     {
     854         163 :       char * interval_string = GETENV("GC_LARGE_ALLOC_WARN_INTERVAL");
     855         163 :       if (0 != interval_string) {
     856           0 :         long interval = atol(interval_string);
     857           0 :         if (interval <= 0) {
     858           0 :           WARN("GC_LARGE_ALLOC_WARN_INTERVAL environment variable has "
     859             :                "bad value: Ignoring\n", 0);
     860             :         } else {
     861           0 :           GC_large_alloc_warn_interval = interval;
     862             :         }
     863             :       }
     864             :     }
     865             :     {
     866         163 :         char * space_divisor_string = GETENV("GC_FREE_SPACE_DIVISOR");
     867         163 :         if (space_divisor_string != NULL) {
     868           0 :           int space_divisor = atoi(space_divisor_string);
     869           0 :           if (space_divisor > 0)
     870           0 :             GC_free_space_divisor = (GC_word)space_divisor;
     871             :         }
     872             :     }
     873             : #   ifdef USE_MUNMAP
     874             :       {
     875             :         char * string = GETENV("GC_UNMAP_THRESHOLD");
     876             :         if (string != NULL) {
     877             :           if (*string == '0' && *(string + 1) == '\0') {
     878             :             /* "0" is used to disable unmapping. */
     879             :             GC_unmap_threshold = 0;
     880             :           } else {
     881             :             int unmap_threshold = atoi(string);
     882             :             if (unmap_threshold > 0)
     883             :               GC_unmap_threshold = unmap_threshold;
     884             :           }
     885             :         }
     886             :       }
     887             :       {
     888             :         char * string = GETENV("GC_FORCE_UNMAP_ON_GCOLLECT");
     889             :         if (string != NULL) {
     890             :           if (*string == '0' && *(string + 1) == '\0') {
     891             :             /* "0" is used to turn off the mode. */
     892             :             GC_force_unmap_on_gcollect = FALSE;
     893             :           } else {
     894             :             GC_force_unmap_on_gcollect = TRUE;
     895             :           }
     896             :         }
     897             :       }
     898             :       {
     899             :         char * string = GETENV("GC_USE_ENTIRE_HEAP");
     900             :         if (string != NULL) {
     901             :           if (*string == '0' && *(string + 1) == '\0') {
     902             :             /* "0" is used to turn off the mode. */
     903             :             GC_use_entire_heap = FALSE;
     904             :           } else {
     905             :             GC_use_entire_heap = TRUE;
     906             :           }
     907             :         }
     908             :       }
     909             : #   endif
     910         163 :     maybe_install_looping_handler();
     911             :     /* Adjust normal object descriptor for extra allocation.    */
     912         163 :     if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
     913           0 :       GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
     914             :     }
     915         163 :     GC_exclude_static_roots_inner(beginGC_arrays, endGC_arrays);
     916         163 :     GC_exclude_static_roots_inner(beginGC_obj_kinds, endGC_obj_kinds);
     917             : #   ifdef SEPARATE_GLOBALS
     918             :       GC_exclude_static_roots_inner(beginGC_objfreelist, endGC_objfreelist);
     919             :       GC_exclude_static_roots_inner(beginGC_aobjfreelist, endGC_aobjfreelist);
     920             : #   endif
     921             : #   if defined(USE_PROC_FOR_LIBRARIES) && defined(GC_LINUX_THREADS)
     922             :         WARN("USE_PROC_FOR_LIBRARIES + GC_LINUX_THREADS performs poorly.\n", 0);
     923             :         /* If thread stacks are cached, they tend to be scanned in      */
     924             :         /* entirety as part of the root set.  This wil grow them to     */
     925             :         /* maximum size, and is generally not desirable.                */
     926             : #   endif
     927             : #   if defined(SEARCH_FOR_DATA_START)
     928         163 :         GC_init_linux_data_start();
     929             : #   endif
     930             : #   if defined(NETBSD) && defined(__ELF__)
     931             :         GC_init_netbsd_elf();
     932             : #   endif
     933             : #   if !defined(THREADS) || defined(GC_PTHREADS) \
     934             :         || defined(GC_WIN32_THREADS) || defined(GC_SOLARIS_THREADS)
     935         163 :       if (GC_stackbottom == 0) {
     936         163 :         GC_stackbottom = GC_get_main_stack_base();
     937             : #       if (defined(LINUX) || defined(HPUX)) && defined(IA64)
     938             :           GC_register_stackbottom = GC_get_register_stack_base();
     939             : #       endif
     940             :       } else {
     941             : #       if (defined(LINUX) || defined(HPUX)) && defined(IA64)
     942             :           if (GC_register_stackbottom == 0) {
     943             :             WARN("GC_register_stackbottom should be set with GC_stackbottom\n", 0);
     944             :             /* The following may fail, since we may rely on             */
     945             :             /* alignment properties that may not hold with a user set   */
     946             :             /* GC_stackbottom.                                          */
     947             :             GC_register_stackbottom = GC_get_register_stack_base();
     948             :           }
     949             : #       endif
     950             :       }
     951             : #   endif
     952             :     GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word));
     953             :     GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
     954             :     GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
     955             : #   ifndef THREADS
     956             :       GC_ASSERT(!((word)GC_stackbottom HOTTER_THAN (word)GC_approx_sp()));
     957             : #   endif
     958             : #   if !defined(_AUX_SOURCE) || defined(__GNUC__)
     959             :       GC_STATIC_ASSERT((word)(-1) > (word)0);
     960             :       /* word should be unsigned */
     961             : #   endif
     962             : #   if !defined(__BORLANDC__) && !defined(__CC_ARM) \
     963             :        && !(defined(__clang__) && defined(X86_64)) /* Workaround */
     964             :       GC_STATIC_ASSERT((ptr_t)(word)(-1) > (ptr_t)0);
     965             :       /* Ptr_t comparisons should behave as unsigned comparisons.       */
     966             : #   endif
     967             :     GC_STATIC_ASSERT((signed_word)(-1) < (signed_word)0);
     968             : #   ifndef GC_DISABLE_INCREMENTAL
     969         163 :       if (GC_incremental || 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
     970             :         /* For GWW_VDB on Win32, this needs to happen before any        */
     971             :         /* heap memory is allocated.                                    */
     972           0 :         GC_dirty_init();
     973             :         GC_ASSERT(GC_bytes_allocd == 0);
     974           0 :         GC_incremental = TRUE;
     975             :       }
     976             : #   endif
     977             : 
     978             :     /* Add initial guess of root sets.  Do this first, since sbrk(0)    */
     979             :     /* might be used.                                                   */
     980         163 :       if (GC_REGISTER_MAIN_STATIC_DATA()) GC_register_data_segments();
     981         163 :     GC_init_headers();
     982         163 :     GC_bl_init();
     983         163 :     GC_mark_init();
     984             :     {
     985         163 :         char * sz_str = GETENV("GC_INITIAL_HEAP_SIZE");
     986         163 :         if (sz_str != NULL) {
     987           0 :           initial_heap_sz = GC_parse_mem_size_arg(sz_str);
     988           0 :           if (initial_heap_sz <= MINHINCR * HBLKSIZE) {
     989           0 :             WARN("Bad initial heap size %s - ignoring it.\n", sz_str);
     990             :           }
     991           0 :           initial_heap_sz = divHBLKSZ(initial_heap_sz);
     992             :         }
     993             :     }
     994             :     {
     995         163 :         char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE");
     996         163 :         if (sz_str != NULL) {
     997           0 :           word max_heap_sz = GC_parse_mem_size_arg(sz_str);
     998           0 :           if (max_heap_sz < initial_heap_sz * HBLKSIZE) {
     999           0 :             WARN("Bad maximum heap size %s - ignoring it.\n", sz_str);
    1000             :           }
    1001           0 :           if (0 == GC_max_retries) GC_max_retries = 2;
    1002           0 :           GC_set_max_heap_size(max_heap_sz);
    1003             :         }
    1004             :     }
    1005         163 :     if (!GC_expand_hp_inner(initial_heap_sz)) {
    1006           0 :         GC_err_printf("Can't start up: not enough memory\n");
    1007           0 :         EXIT();
    1008             :     }
    1009         163 :     if (GC_all_interior_pointers)
    1010           0 :       GC_initialize_offsets();
    1011         163 :     GC_register_displacement_inner(0L);
    1012             : #   if defined(GC_LINUX_THREADS) && defined(REDIRECT_MALLOC)
    1013             :       if (!GC_all_interior_pointers) {
    1014             :         /* TLS ABI uses pointer-sized offsets for dtv. */
    1015             :         GC_register_displacement_inner(sizeof(void *));
    1016             :       }
    1017             : #   endif
    1018         163 :     GC_init_size_map();
    1019             : #   ifdef PCR
    1020             :       if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
    1021             :           != PCR_ERes_okay) {
    1022             :           ABORT("Can't lock load state");
    1023             :       } else if (PCR_IL_Unlock() != PCR_ERes_okay) {
    1024             :           ABORT("Can't unlock load state");
    1025             :       }
    1026             :       PCR_IL_Unlock();
    1027             :       GC_pcr_install();
    1028             : #   endif
    1029         163 :     GC_is_initialized = TRUE;
    1030             : #   if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
    1031         163 :         GC_thr_init();
    1032             : #   endif
    1033         163 :     COND_DUMP;
    1034             :     /* Get black list set up and/or incremental GC started */
    1035         163 :       if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
    1036             : #   ifdef STUBBORN_ALLOC
    1037             :         GC_stubborn_init();
    1038             : #   endif
    1039             :     /* Convince lint that some things are used */
    1040             : #   ifdef LINT
    1041             :       {
    1042             :           extern char * const GC_copyright[];
    1043             :           GC_noop(GC_copyright, GC_find_header, GC_push_one,
    1044             :                   GC_call_with_alloc_lock, GC_dont_expand,
    1045             : #                 ifndef NO_DEBUGGING
    1046             :                     GC_dump,
    1047             : #                 endif
    1048             :                   GC_register_finalizer_no_order);
    1049             :       }
    1050             : #   endif
    1051             : 
    1052         163 :     if (GC_find_leak) {
    1053             :       /* This is to give us at least one chance to detect leaks.        */
    1054             :       /* This may report some very benign leaks, but ...                */
    1055           0 :       atexit(GC_exit_check);
    1056             :     }
    1057             : 
    1058             :     /* The rest of this again assumes we don't really hold      */
    1059             :     /* the allocation lock.                                     */
    1060             : #   if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
    1061             :         /* Make sure marker threads are started and thread local */
    1062             :         /* allocation is initialized, in case we didn't get      */
    1063             :         /* called from GC_init_parallel.                         */
    1064         163 :         GC_init_parallel();
    1065             : #   endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
    1066             : 
    1067             : #   if defined(DYNAMIC_LOADING) && defined(DARWIN)
    1068             :         /* This must be called WITHOUT the allocation lock held */
    1069             :         /* and before any threads are created.                  */
    1070             :         GC_init_dyld();
    1071             : #   endif
    1072         163 :     RESTORE_CANCEL(cancel_state);
    1073             : }
    1074             : 
    1075           0 : GC_API void GC_CALL GC_enable_incremental(void)
    1076             : {
    1077             : # if !defined(GC_DISABLE_INCREMENTAL) && !defined(KEEP_BACK_PTRS)
    1078             :     DCL_LOCK_STATE;
    1079             :     /* If we are keeping back pointers, the GC itself dirties all */
    1080             :     /* pages on which objects have been marked, making            */
    1081             :     /* incremental GC pointless.                                  */
    1082           0 :     if (!GC_find_leak && 0 == GETENV("GC_DISABLE_INCREMENTAL")) {
    1083           0 :       LOCK();
    1084           0 :       if (!GC_incremental) {
    1085           0 :         GC_setpagesize();
    1086             :         /* if (GC_no_win32_dlls) goto out; Should be win32S test? */
    1087           0 :         maybe_install_looping_handler(); /* Before write fault handler! */
    1088           0 :         GC_incremental = TRUE;
    1089           0 :         if (!GC_is_initialized) {
    1090           0 :           GC_init();
    1091             :         } else {
    1092           0 :           GC_dirty_init();
    1093             :         }
    1094           0 :         if (GC_dirty_maintained && !GC_dont_gc) {
    1095             :                                 /* Can't easily do it if GC_dont_gc.    */
    1096           0 :           if (GC_bytes_allocd > 0) {
    1097             :             /* There may be unmarked reachable objects. */
    1098           0 :             GC_gcollect_inner();
    1099             :           }
    1100             :             /* else we're OK in assuming everything's   */
    1101             :             /* clean since nothing can point to an      */
    1102             :             /* unmarked object.                         */
    1103           0 :           GC_read_dirty();
    1104             :         }
    1105             :       }
    1106           0 :       UNLOCK();
    1107           0 :       return;
    1108             :     }
    1109             : # endif
    1110           0 :   GC_init();
    1111             : }
    1112             : 
    1113             : #if defined(MSWIN32) || defined(MSWINCE)
    1114             : 
    1115             : # if defined(_MSC_VER) && defined(_DEBUG) && !defined(MSWINCE)
    1116             : #   include <crtdbg.h>
    1117             : # endif
    1118             : 
    1119             :   STATIC HANDLE GC_log = 0;
    1120             : 
    1121             :   void GC_deinit(void)
    1122             :   {
    1123             : #   ifdef THREADS
    1124             :       if (GC_is_initialized) {
    1125             :         DeleteCriticalSection(&GC_write_cs);
    1126             :       }
    1127             : #   endif
    1128             :   }
    1129             : 
    1130             : # ifdef THREADS
    1131             : #   ifdef PARALLEL_MARK
    1132             : #     define IF_NEED_TO_LOCK(x) if (GC_parallel || GC_need_to_lock) x
    1133             : #   else
    1134             : #     define IF_NEED_TO_LOCK(x) if (GC_need_to_lock) x
    1135             : #   endif
    1136             : # else
    1137             : #   define IF_NEED_TO_LOCK(x)
    1138             : # endif /* !THREADS */
    1139             : 
    1140             :   STATIC HANDLE GC_CreateLogFile(void)
    1141             :   {
    1142             : #   if !defined(NO_GETENV_WIN32) || !defined(OLD_WIN32_LOG_FILE)
    1143             :       TCHAR logPath[_MAX_PATH + 0x10]; /* buffer for path + ext */
    1144             : #   endif
    1145             :     /* Use GetEnvironmentVariable instead of GETENV() for unicode support. */
    1146             : #   ifndef NO_GETENV_WIN32
    1147             :       if (GetEnvironmentVariable(TEXT("GC_LOG_FILE"), logPath,
    1148             :                                  _MAX_PATH + 1) - 1U >= (DWORD)_MAX_PATH)
    1149             : #   endif
    1150             :     {
    1151             :       /* Env var not found or its value too long.       */
    1152             : #     ifdef OLD_WIN32_LOG_FILE
    1153             :         return CreateFile(TEXT("gc.log"), GENERIC_WRITE, FILE_SHARE_READ,
    1154             :                           NULL /* lpSecurityAttributes */, CREATE_ALWAYS,
    1155             :                           FILE_FLAG_WRITE_THROUGH, NULL /* hTemplateFile */);
    1156             : #     else
    1157             :         int len = (int)GetModuleFileName(NULL /* hModule */, logPath,
    1158             :                                          _MAX_PATH + 1);
    1159             :         /* If GetModuleFileName() has failed then len is 0. */
    1160             :         if (len > 4 && logPath[len - 4] == (TCHAR)'.') {
    1161             :           len -= 4; /* strip executable file extension */
    1162             :         }
    1163             :         /* strcat/wcscat() are deprecated on WinCE, so use memcpy()     */
    1164             :         memcpy(&logPath[len], TEXT(".gc.log"), sizeof(TEXT(".gc.log")));
    1165             : #     endif
    1166             :     }
    1167             : #   if !defined(NO_GETENV_WIN32) || !defined(OLD_WIN32_LOG_FILE)
    1168             :       return CreateFile(logPath, GENERIC_WRITE, FILE_SHARE_READ,
    1169             :                         NULL /* lpSecurityAttributes */, CREATE_ALWAYS,
    1170             :                         GC_print_stats == VERBOSE ? FILE_ATTRIBUTE_NORMAL :
    1171             :                             /* immediately flush writes unless very verbose */
    1172             :                             FILE_ATTRIBUTE_NORMAL | FILE_FLAG_WRITE_THROUGH,
    1173             :                         NULL /* hTemplateFile */);
    1174             : #   endif
    1175             :   }
    1176             : 
    1177             :   STATIC int GC_write(const char *buf, size_t len)
    1178             :   {
    1179             :       BOOL tmp;
    1180             :       DWORD written;
    1181             :       if (len == 0)
    1182             :           return 0;
    1183             :       IF_NEED_TO_LOCK(EnterCriticalSection(&GC_write_cs));
    1184             : #     ifdef THREADS
    1185             :         GC_ASSERT(!GC_write_disabled);
    1186             : #     endif
    1187             :       if (GC_log == INVALID_HANDLE_VALUE) {
    1188             :           IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs));
    1189             :           return -1;
    1190             :       } else if (GC_log == 0) {
    1191             :         GC_log = GC_CreateLogFile();
    1192             :         /* Ignore open log failure if the collector is built with       */
    1193             :         /* print_stats always set on.                                   */
    1194             : #       ifndef GC_PRINT_VERBOSE_STATS
    1195             :           if (GC_log == INVALID_HANDLE_VALUE)
    1196             :             ABORT("Open of log file failed");
    1197             : #       endif
    1198             :       }
    1199             :       tmp = WriteFile(GC_log, buf, (DWORD)len, &written, NULL);
    1200             :       if (!tmp)
    1201             :           DebugBreak();
    1202             : #     if defined(_MSC_VER) && defined(_DEBUG)
    1203             : #         ifdef MSWINCE
    1204             :               /* There is no CrtDbgReport() in WinCE */
    1205             :               {
    1206             :                   WCHAR wbuf[1024];
    1207             :                   /* Always use Unicode variant of OutputDebugString() */
    1208             :                   wbuf[MultiByteToWideChar(CP_ACP, 0 /* dwFlags */,
    1209             :                                 buf, len, wbuf,
    1210             :                                 sizeof(wbuf) / sizeof(wbuf[0]) - 1)] = 0;
    1211             :                   OutputDebugStringW(wbuf);
    1212             :               }
    1213             : #         else
    1214             :               _CrtDbgReport(_CRT_WARN, NULL, 0, NULL, "%.*s", len, buf);
    1215             : #         endif
    1216             : #     endif
    1217             :       IF_NEED_TO_LOCK(LeaveCriticalSection(&GC_write_cs));
    1218             :       return tmp ? (int)written : -1;
    1219             :   }
    1220             : 
    1221             :   /* FIXME: This is pretty ugly ... */
    1222             : # define WRITE(f, buf, len) GC_write(buf, len)
    1223             : 
    1224             : #elif defined(OS2) || defined(MACOS)
    1225             :   STATIC FILE * GC_stdout = NULL;
    1226             :   STATIC FILE * GC_stderr = NULL;
    1227             :   STATIC FILE * GC_log = NULL;
    1228             : 
    1229             :   /* Initialize GC_log (and the friends) passed to GC_write().  */
    1230             :   STATIC void GC_set_files(void)
    1231             :   {
    1232             :     if (GC_stdout == NULL) {
    1233             :       GC_stdout = stdout;
    1234             :     }
    1235             :     if (GC_stderr == NULL) {
    1236             :       GC_stderr = stderr;
    1237             :     }
    1238             :     if (GC_log == NULL) {
    1239             :       GC_log = stderr;
    1240             :     }
    1241             :   }
    1242             : 
    1243             :   GC_INLINE int GC_write(FILE *f, const char *buf, size_t len)
    1244             :   {
    1245             :     int res = fwrite(buf, 1, len, f);
    1246             :     fflush(f);
    1247             :     return res;
    1248             :   }
    1249             : 
    1250             : # define WRITE(f, buf, len) (GC_set_files(), GC_write(f, buf, len))
    1251             : 
    1252             : #else
    1253             : # if !defined(AMIGA) && !defined(__CC_ARM)
    1254             : #   include <unistd.h>
    1255             : # endif
    1256             : 
    1257           0 :   STATIC int GC_write(int fd, const char *buf, size_t len)
    1258             :   {
    1259             : #   if defined(ECOS) || defined(NOSYS)
    1260             : #     ifdef ECOS
    1261             :         /* FIXME: This seems to be defined nowhere at present.  */
    1262             :         /* _Jv_diag_write(buf, len); */
    1263             : #     else
    1264             :         /* No writing.  */
    1265             : #     endif
    1266             :       return len;
    1267             : #   else
    1268           0 :       int bytes_written = 0;
    1269             :       int result;
    1270             :       IF_CANCEL(int cancel_state;)
    1271             : 
    1272           0 :       DISABLE_CANCEL(cancel_state);
    1273           0 :       while ((size_t)bytes_written < len) {
    1274             : #        ifdef GC_SOLARIS_THREADS
    1275             :              result = syscall(SYS_write, fd, buf + bytes_written,
    1276             :                                              len - bytes_written);
    1277             : #        else
    1278           0 :              result = write(fd, buf + bytes_written, len - bytes_written);
    1279             : #        endif
    1280           0 :          if (-1 == result) {
    1281           0 :              RESTORE_CANCEL(cancel_state);
    1282           0 :              return(result);
    1283             :          }
    1284           0 :          bytes_written += result;
    1285             :       }
    1286           0 :       RESTORE_CANCEL(cancel_state);
    1287           0 :       return(bytes_written);
    1288             : #   endif
    1289             :   }
    1290             : 
    1291             : # define WRITE(f, buf, len) GC_write(f, buf, len)
    1292             : #endif /* !MSWIN32 && !OS2 && !MACOS */
    1293             : 
    1294             : #define BUFSZ 1024
    1295             : 
    1296             : #ifdef NO_VSNPRINTF
    1297             :   /* In case this function is missing (eg., in DJGPP v2.0.3).   */
    1298             : # define vsnprintf(buf, bufsz, format, args) vsprintf(buf, format, args)
    1299             : #elif defined(_MSC_VER)
    1300             : # ifdef MSWINCE
    1301             :     /* _vsnprintf is deprecated in WinCE */
    1302             : #   define vsnprintf StringCchVPrintfA
    1303             : # else
    1304             : #   define vsnprintf _vsnprintf
    1305             : # endif
    1306             : #endif
    1307             : /* A version of printf that is unlikely to call malloc, and is thus safer */
    1308             : /* to call from the collector in case malloc has been bound to GC_malloc. */
    1309             : /* Floating point arguments and formats should be avoided, since fp       */
    1310             : /* conversion is more likely to allocate.                                 */
    1311             : /* Assumes that no more than BUFSZ-1 characters are written at once.      */
    1312           0 : void GC_printf(const char *format, ...)
    1313             : {
    1314             :     va_list args;
    1315             :     char buf[BUFSZ+1];
    1316             : 
    1317           0 :     if (GC_quiet) return;
    1318           0 :     va_start(args, format);
    1319           0 :     buf[BUFSZ] = 0x15;
    1320           0 :     (void) vsnprintf(buf, BUFSZ, format, args);
    1321           0 :     va_end(args);
    1322           0 :     if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
    1323           0 :     if (WRITE(GC_stdout, buf, strlen(buf)) < 0)
    1324           0 :       ABORT("write to stdout failed");
    1325             : }
    1326             : 
    1327           0 : void GC_err_printf(const char *format, ...)
    1328             : {
    1329             :     va_list args;
    1330             :     char buf[BUFSZ+1];
    1331             : 
    1332           0 :     va_start(args, format);
    1333           0 :     buf[BUFSZ] = 0x15;
    1334           0 :     (void) vsnprintf(buf, BUFSZ, format, args);
    1335           0 :     va_end(args);
    1336           0 :     if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
    1337           0 :     if (WRITE(GC_stderr, buf, strlen(buf)) < 0)
    1338           0 :       ABORT("write to stderr failed");
    1339           0 : }
    1340             : 
    1341           0 : void GC_log_printf(const char *format, ...)
    1342             : {
    1343             :     va_list args;
    1344             :     char buf[BUFSZ+1];
    1345             : 
    1346           0 :     va_start(args, format);
    1347           0 :     buf[BUFSZ] = 0x15;
    1348           0 :     (void) vsnprintf(buf, BUFSZ, format, args);
    1349           0 :     va_end(args);
    1350           0 :     if (buf[BUFSZ] != 0x15) ABORT("GC_printf clobbered stack");
    1351           0 :     if (WRITE(GC_log, buf, strlen(buf)) < 0)
    1352           0 :       ABORT("write to log failed");
    1353           0 : }
    1354             : 
    1355             : /* This is equivalent to GC_err_printf("%s",s). */
    1356           0 : void GC_err_puts(const char *s)
    1357             : {
    1358           0 :     if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed");
    1359           0 : }
    1360             : 
    1361           0 : STATIC void GC_CALLBACK GC_default_warn_proc(char *msg, GC_word arg)
    1362             : {
    1363           0 :     GC_err_printf(msg, arg);
    1364           0 : }
    1365             : 
    1366             : GC_INNER GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
    1367             : 
    1368             : /* This is recommended for production code (release). */
    1369           0 : GC_API void GC_CALLBACK GC_ignore_warn_proc(char *msg, GC_word arg)
    1370             : {
    1371           0 :     if (GC_print_stats) {
    1372             :       /* Don't ignore warnings if stats printing is on. */
    1373           0 :       GC_default_warn_proc(msg, arg);
    1374             :     }
    1375           0 : }
    1376             : 
    1377         163 : GC_API void GC_CALL GC_set_warn_proc(GC_warn_proc p)
    1378             : {
    1379             :     DCL_LOCK_STATE;
    1380             :     GC_ASSERT(p != 0);
    1381             : #   ifdef GC_WIN32_THREADS
    1382             : #     ifdef CYGWIN32
    1383             :         /* Need explicit GC_INIT call */
    1384             :         GC_ASSERT(GC_is_initialized);
    1385             : #     else
    1386             :         if (!GC_is_initialized) GC_init();
    1387             : #     endif
    1388             : #   endif
    1389         163 :     LOCK();
    1390         163 :     GC_current_warn_proc = p;
    1391         163 :     UNLOCK();
    1392         163 : }
    1393             : 
    1394           0 : GC_API GC_warn_proc GC_CALL GC_get_warn_proc(void)
    1395             : {
    1396             :     GC_warn_proc result;
    1397             :     DCL_LOCK_STATE;
    1398           0 :     LOCK();
    1399           0 :     result = GC_current_warn_proc;
    1400           0 :     UNLOCK();
    1401           0 :     return(result);
    1402             : }
    1403             : 
    1404             : #if !defined(PCR) && !defined(SMALL_CONFIG)
    1405             :   /* Abort the program with a message. msg must not be NULL. */
    1406           0 :   void GC_abort(const char *msg)
    1407             :   {
    1408             : #   if defined(MSWIN32)
    1409             : #     ifndef DONT_USE_USER32_DLL
    1410             :         /* Use static binding to "user32.dll".  */
    1411             :         (void)MessageBoxA(NULL, msg, "Fatal error in GC", MB_ICONERROR|MB_OK);
    1412             : #     else
    1413             :         /* This simplifies linking - resolve "MessageBoxA" at run-time. */
    1414             :         HINSTANCE hU32 = LoadLibrary(TEXT("user32.dll"));
    1415             :         if (hU32) {
    1416             :           FARPROC pfn = GetProcAddress(hU32, "MessageBoxA");
    1417             :           if (pfn)
    1418             :             (void)(*(int (WINAPI *)(HWND, LPCSTR, LPCSTR, UINT))pfn)(
    1419             :                                 NULL /* hWnd */, msg, "Fatal error in GC",
    1420             :                                 MB_ICONERROR | MB_OK);
    1421             :           (void)FreeLibrary(hU32);
    1422             :         }
    1423             : #     endif
    1424             :       /* Also duplicate msg to GC log file.     */
    1425             : #   endif
    1426             :       /* Avoid calling GC_err_printf() here, as GC_abort() could be     */
    1427             :       /* called from it.  Note 1: this is not an atomic output.         */
    1428             :       /* Note 2: possible write errors are ignored.                     */
    1429           0 :       if (WRITE(GC_stderr, (void *)msg, strlen(msg)) >= 0)
    1430           0 :         (void)WRITE(GC_stderr, (void *)("\n"), 1);
    1431             : 
    1432           0 :     if (GETENV("GC_LOOP_ON_ABORT") != NULL) {
    1433             :             /* In many cases it's easier to debug a running process.    */
    1434             :             /* It's arguably nicer to sleep, but that makes it harder   */
    1435             :             /* to look at the thread if the debugger doesn't know much  */
    1436             :             /* about threads.                                           */
    1437           0 :             for(;;) {}
    1438             :     }
    1439             : #   ifndef LINT2
    1440           0 :       if (!msg) return; /* to suppress compiler warnings in ABORT callers. */
    1441             : #   endif
    1442             : #   if defined(MSWIN32) && (defined(NO_DEBUGGING) || defined(LINT2))
    1443             :       /* A more user-friendly abort after showing fatal message.        */
    1444             :         _exit(-1); /* exit on error without running "at-exit" callbacks */
    1445             : #   elif defined(MSWINCE) && defined(NO_DEBUGGING)
    1446             :         ExitProcess(-1);
    1447             : #   elif defined(MSWIN32) || defined(MSWINCE)
    1448             :         DebugBreak();
    1449             :                 /* Note that on a WinCE box, this could be silently     */
    1450             :                 /* ignored (i.e., the program is not aborted).          */
    1451             : #   else
    1452           0 :         (void) abort();
    1453             : #   endif
    1454             :   }
    1455             : #endif /* !SMALL_CONFIG */
    1456             : 
    1457           0 : GC_API void GC_CALL GC_enable(void)
    1458             : {
    1459             :     DCL_LOCK_STATE;
    1460           0 :     LOCK();
    1461           0 :     GC_dont_gc--;
    1462           0 :     UNLOCK();
    1463           0 : }
    1464             : 
    1465           0 : GC_API void GC_CALL GC_disable(void)
    1466             : {
    1467             :     DCL_LOCK_STATE;
    1468           0 :     LOCK();
    1469           0 :     GC_dont_gc++;
    1470           0 :     UNLOCK();
    1471           0 : }
    1472             : 
    1473           0 : GC_API int GC_CALL GC_is_disabled(void)
    1474             : {
    1475           0 :     return GC_dont_gc != 0;
    1476             : }
    1477             : 
    1478             : /* Helper procedures for new kind creation.     */
    1479           0 : GC_API void ** GC_CALL GC_new_free_list_inner(void)
    1480             : {
    1481           0 :     void *result = GC_INTERNAL_MALLOC((MAXOBJGRANULES+1)*sizeof(ptr_t),
    1482           0 :                                       PTRFREE);
    1483           0 :     if (result == 0) ABORT("Failed to allocate freelist for new kind");
    1484           0 :     BZERO(result, (MAXOBJGRANULES+1)*sizeof(ptr_t));
    1485           0 :     return result;
    1486             : }
    1487             : 
    1488           0 : GC_API void ** GC_CALL GC_new_free_list(void)
    1489             : {
    1490             :     void *result;
    1491             :     DCL_LOCK_STATE;
    1492           0 :     LOCK();
    1493           0 :     result = GC_new_free_list_inner();
    1494           0 :     UNLOCK();
    1495           0 :     return result;
    1496             : }
    1497             : 
    1498           0 : GC_API unsigned GC_CALL GC_new_kind_inner(void **fl, GC_word descr,
    1499             :                                         int adjust, int clear)
    1500             : {
    1501           0 :     unsigned result = GC_n_kinds++;
    1502             : 
    1503           0 :     if (GC_n_kinds > MAXOBJKINDS) ABORT("Too many kinds");
    1504           0 :     GC_obj_kinds[result].ok_freelist = fl;
    1505           0 :     GC_obj_kinds[result].ok_reclaim_list = 0;
    1506           0 :     GC_obj_kinds[result].ok_descriptor = descr;
    1507           0 :     GC_obj_kinds[result].ok_relocate_descr = adjust;
    1508           0 :     GC_obj_kinds[result].ok_init = clear;
    1509           0 :     return result;
    1510             : }
    1511             : 
    1512           0 : GC_API unsigned GC_CALL GC_new_kind(void **fl, GC_word descr, int adjust,
    1513             :                                     int clear)
    1514             : {
    1515             :     unsigned result;
    1516             :     DCL_LOCK_STATE;
    1517           0 :     LOCK();
    1518           0 :     result = GC_new_kind_inner(fl, descr, adjust, clear);
    1519           0 :     UNLOCK();
    1520           0 :     return result;
    1521             : }
    1522             : 
    1523           0 : GC_API unsigned GC_CALL GC_new_proc_inner(GC_mark_proc proc)
    1524             : {
    1525           0 :     unsigned result = GC_n_mark_procs++;
    1526             : 
    1527           0 :     if (GC_n_mark_procs > MAX_MARK_PROCS) ABORT("Too many mark procedures");
    1528           0 :     GC_mark_procs[result] = proc;
    1529           0 :     return result;
    1530             : }
    1531             : 
    1532           0 : GC_API unsigned GC_CALL GC_new_proc(GC_mark_proc proc)
    1533             : {
    1534             :     unsigned result;
    1535             :     DCL_LOCK_STATE;
    1536           0 :     LOCK();
    1537           0 :     result = GC_new_proc_inner(proc);
    1538           0 :     UNLOCK();
    1539           0 :     return result;
    1540             : }
    1541             : 
    1542         499 : GC_API void * GC_CALL GC_call_with_stack_base(GC_stack_base_func fn, void *arg)
    1543             : {
    1544             :     struct GC_stack_base base;
    1545             :     void *result;
    1546             : 
    1547         499 :     base.mem_base = (void *)&base;
    1548             : #   ifdef IA64
    1549             :       base.reg_base = (void *)GC_save_regs_in_stack();
    1550             :       /* Unnecessarily flushes register stack,          */
    1551             :       /* but that probably doesn't hurt.                */
    1552             : #   endif
    1553         499 :     result = fn(&base, arg);
    1554             :     /* Strongly discourage the compiler from treating the above */
    1555             :     /* as a tail call.                                          */
    1556         151 :     GC_noop1((word)(&base));
    1557         151 :     return result;
    1558             : }
    1559             : 
    1560             : #ifndef THREADS
    1561             : 
    1562             : GC_INNER ptr_t GC_blocked_sp = NULL;
    1563             :         /* NULL value means we are not inside GC_do_blocking() call. */
    1564             : # ifdef IA64
    1565             :     STATIC ptr_t GC_blocked_register_sp = NULL;
    1566             : # endif
    1567             : 
    1568             : GC_INNER struct GC_traced_stack_sect_s *GC_traced_stack_sect = NULL;
    1569             : 
    1570             : /* This is nearly the same as in win32_threads.c        */
    1571             : GC_API void * GC_CALL GC_call_with_gc_active(GC_fn_type fn,
    1572             :                                              void * client_data)
    1573             : {
    1574             :     struct GC_traced_stack_sect_s stacksect;
    1575             :     GC_ASSERT(GC_is_initialized);
    1576             : 
    1577             :     /* Adjust our stack base value (this could happen if        */
    1578             :     /* GC_get_main_stack_base() is unimplemented or broken for  */
    1579             :     /* the platform).                                           */
    1580             :     if (GC_stackbottom HOTTER_THAN (ptr_t)(&stacksect))
    1581             :       GC_stackbottom = (ptr_t)(&stacksect);
    1582             : 
    1583             :     if (GC_blocked_sp == NULL) {
    1584             :       /* We are not inside GC_do_blocking() - do nothing more.  */
    1585             :       return fn(client_data);
    1586             :     }
    1587             : 
    1588             :     /* Setup new "stack section".       */
    1589             :     stacksect.saved_stack_ptr = GC_blocked_sp;
    1590             : #   ifdef IA64
    1591             :       /* This is the same as in GC_call_with_stack_base().      */
    1592             :       stacksect.backing_store_end = GC_save_regs_in_stack();
    1593             :       /* Unnecessarily flushes register stack,          */
    1594             :       /* but that probably doesn't hurt.                */
    1595             :       stacksect.saved_backing_store_ptr = GC_blocked_register_sp;
    1596             : #   endif
    1597             :     stacksect.prev = GC_traced_stack_sect;
    1598             :     GC_blocked_sp = NULL;
    1599             :     GC_traced_stack_sect = &stacksect;
    1600             : 
    1601             :     client_data = fn(client_data);
    1602             :     GC_ASSERT(GC_blocked_sp == NULL);
    1603             :     GC_ASSERT(GC_traced_stack_sect == &stacksect);
    1604             : 
    1605             :     /* Restore original "stack section".        */
    1606             :     GC_traced_stack_sect = stacksect.prev;
    1607             : #   ifdef IA64
    1608             :       GC_blocked_register_sp = stacksect.saved_backing_store_ptr;
    1609             : #   endif
    1610             :     GC_blocked_sp = stacksect.saved_stack_ptr;
    1611             : 
    1612             :     return client_data; /* result */
    1613             : }
    1614             : 
    1615             : /* This is nearly the same as in win32_threads.c        */
    1616             : /*ARGSUSED*/
    1617             : STATIC void GC_do_blocking_inner(ptr_t data, void * context)
    1618             : {
    1619             :     struct blocking_data * d = (struct blocking_data *) data;
    1620             :     GC_ASSERT(GC_is_initialized);
    1621             :     GC_ASSERT(GC_blocked_sp == NULL);
    1622             : #   ifdef SPARC
    1623             :         GC_blocked_sp = GC_save_regs_in_stack();
    1624             : #   else
    1625             :         GC_blocked_sp = (ptr_t) &d; /* save approx. sp */
    1626             : #   endif
    1627             : #   ifdef IA64
    1628             :         GC_blocked_register_sp = GC_save_regs_in_stack();
    1629             : #   endif
    1630             : 
    1631             :     d -> client_data = (d -> fn)(d -> client_data);
    1632             : 
    1633             : #   ifdef SPARC
    1634             :         GC_ASSERT(GC_blocked_sp != NULL);
    1635             : #   else
    1636             :         GC_ASSERT(GC_blocked_sp == (ptr_t) &d);
    1637             : #   endif
    1638             :     GC_blocked_sp = NULL;
    1639             : }
    1640             : 
    1641             : #endif /* !THREADS */
    1642             : 
    1643             : /* Wrapper for functions that are likely to block (or, at least, do not */
    1644             : /* allocate garbage collected memory and/or manipulate pointers to the  */
    1645             : /* garbage collected heap) for an appreciable length of time.           */
    1646             : /* In the single threaded case, GC_do_blocking() (together              */
    1647             : /* with GC_call_with_gc_active()) might be used to make stack scanning  */
    1648             : /* more precise (i.e. scan only stack frames of functions that allocate */
    1649             : /* garbage collected memory and/or manipulate pointers to the garbage   */
    1650             : /* collected heap).                                                     */
    1651           0 : GC_API void * GC_CALL GC_do_blocking(GC_fn_type fn, void * client_data)
    1652             : {
    1653             :     struct blocking_data my_data;
    1654             : 
    1655           0 :     my_data.fn = fn;
    1656           0 :     my_data.client_data = client_data;
    1657           0 :     GC_with_callee_saves_pushed(GC_do_blocking_inner, (ptr_t)(&my_data));
    1658           0 :     return my_data.client_data; /* result */
    1659             : }
    1660             : 
    1661             : #if !defined(NO_DEBUGGING)
    1662           0 :   GC_API void GC_CALL GC_dump(void)
    1663             :   {
    1664           0 :     GC_printf("***Static roots:\n");
    1665           0 :     GC_print_static_roots();
    1666           0 :     GC_printf("\n***Heap sections:\n");
    1667           0 :     GC_print_heap_sects();
    1668           0 :     GC_printf("\n***Free blocks:\n");
    1669           0 :     GC_print_hblkfreelist();
    1670           0 :     GC_printf("\n***Blocks in use:\n");
    1671           0 :     GC_print_block_list();
    1672           0 :   }
    1673             : #endif /* !NO_DEBUGGING */
    1674             : 
    1675             : /* Getter functions for the public Read-only variables.                 */
    1676             : 
    1677             : /* GC_get_gc_no() is unsynchronized and should be typically called      */
    1678             : /* inside the context of GC_call_with_alloc_lock() to prevent data      */
    1679             : /* races (on multiprocessors).                                          */
    1680           0 : GC_API GC_word GC_CALL GC_get_gc_no(void)
    1681             : {
    1682           0 :     return GC_gc_no;
    1683             : }
    1684             : 
    1685             : #ifdef THREADS
    1686           0 :   GC_API int GC_CALL GC_get_parallel(void)
    1687             :   {
    1688             :     /* GC_parallel is initialized at start-up.  */
    1689           0 :     return GC_parallel;
    1690             :   }
    1691             : #endif
    1692             : 
    1693             : /* Setter and getter functions for the public R/W function variables.   */
    1694             : /* These functions are synchronized (like GC_set_warn_proc() and        */
    1695             : /* GC_get_warn_proc()).                                                 */
    1696             : 
    1697           0 : GC_API void GC_CALL GC_set_oom_fn(GC_oom_func fn)
    1698             : {
    1699             :     GC_ASSERT(fn != 0);
    1700             :     DCL_LOCK_STATE;
    1701           0 :     LOCK();
    1702           0 :     GC_oom_fn = fn;
    1703           0 :     UNLOCK();
    1704           0 : }
    1705             : 
    1706           3 : GC_API GC_oom_func GC_CALL GC_get_oom_fn(void)
    1707             : {
    1708             :     GC_oom_func fn;
    1709             :     DCL_LOCK_STATE;
    1710           3 :     LOCK();
    1711           3 :     fn = GC_oom_fn;
    1712           3 :     UNLOCK();
    1713           3 :     return fn;
    1714             : }
    1715             : 
    1716           0 : GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc fn)
    1717             : {
    1718             :     /* fn may be 0 (means no finalizer notifier). */
    1719             :     DCL_LOCK_STATE;
    1720           0 :     LOCK();
    1721           0 :     GC_finalizer_notifier = fn;
    1722           0 :     UNLOCK();
    1723           0 : }
    1724             : 
    1725           0 : GC_API GC_finalizer_notifier_proc GC_CALL GC_get_finalizer_notifier(void)
    1726             : {
    1727             :     GC_finalizer_notifier_proc fn;
    1728             :     DCL_LOCK_STATE;
    1729           0 :     LOCK();
    1730           0 :     fn = GC_finalizer_notifier;
    1731           0 :     UNLOCK();
    1732           0 :     return fn;
    1733             : }
    1734             : 
    1735             : /* Setter and getter functions for the public numeric R/W variables.    */
    1736             : /* It is safe to call these functions even before GC_INIT().            */
    1737             : /* These functions are unsynchronized and should be typically called    */
    1738             : /* inside the context of GC_call_with_alloc_lock() (if called after     */
    1739             : /* GC_INIT()) to prevent data races (unless it is guaranteed the        */
    1740             : /* collector is not multi-threaded at that execution point).            */
    1741             : 
    1742           0 : GC_API void GC_CALL GC_set_find_leak(int value)
    1743             : {
    1744             :     /* value is of boolean type. */
    1745           0 :     GC_find_leak = value;
    1746           0 : }
    1747             : 
    1748           0 : GC_API int GC_CALL GC_get_find_leak(void)
    1749             : {
    1750           0 :     return GC_find_leak;
    1751             : }
    1752             : 
    1753           0 : GC_API void GC_CALL GC_set_all_interior_pointers(int value)
    1754             : {
    1755             :     DCL_LOCK_STATE;
    1756             : 
    1757           0 :     GC_all_interior_pointers = value ? 1 : 0;
    1758           0 :     if (GC_is_initialized) {
    1759             :       /* It is not recommended to change GC_all_interior_pointers value */
    1760             :       /* after GC is initialized but it seems GC could work correctly   */
    1761             :       /* even after switching the mode.                                 */
    1762           0 :       LOCK();
    1763           0 :       GC_initialize_offsets(); /* NOTE: this resets manual offsets as well */
    1764           0 :       if (!GC_all_interior_pointers)
    1765           0 :         GC_bl_init_no_interiors();
    1766           0 :       UNLOCK();
    1767             :     }
    1768           0 : }
    1769             : 
    1770           0 : GC_API int GC_CALL GC_get_all_interior_pointers(void)
    1771             : {
    1772           0 :     return GC_all_interior_pointers;
    1773             : }
    1774             : 
    1775           0 : GC_API void GC_CALL GC_set_finalize_on_demand(int value)
    1776             : {
    1777             :     GC_ASSERT(value != -1);
    1778             :     /* value is of boolean type. */
    1779           0 :     GC_finalize_on_demand = value;
    1780           0 : }
    1781             : 
    1782           0 : GC_API int GC_CALL GC_get_finalize_on_demand(void)
    1783             : {
    1784           0 :     return GC_finalize_on_demand;
    1785             : }
    1786             : 
    1787           0 : GC_API void GC_CALL GC_set_java_finalization(int value)
    1788             : {
    1789             :     GC_ASSERT(value != -1);
    1790             :     /* value is of boolean type. */
    1791           0 :     GC_java_finalization = value;
    1792           0 : }
    1793             : 
    1794           0 : GC_API int GC_CALL GC_get_java_finalization(void)
    1795             : {
    1796           0 :     return GC_java_finalization;
    1797             : }
    1798             : 
    1799           0 : GC_API void GC_CALL GC_set_dont_expand(int value)
    1800             : {
    1801             :     GC_ASSERT(value != -1);
    1802             :     /* value is of boolean type. */
    1803           0 :     GC_dont_expand = value;
    1804           0 : }
    1805             : 
    1806           0 : GC_API int GC_CALL GC_get_dont_expand(void)
    1807             : {
    1808           0 :     return GC_dont_expand;
    1809             : }
    1810             : 
    1811           0 : GC_API void GC_CALL GC_set_no_dls(int value)
    1812             : {
    1813             :     GC_ASSERT(value != -1);
    1814             :     /* value is of boolean type. */
    1815           0 :     GC_no_dls = value;
    1816           0 : }
    1817             : 
    1818           0 : GC_API int GC_CALL GC_get_no_dls(void)
    1819             : {
    1820           0 :     return GC_no_dls;
    1821             : }
    1822             : 
    1823           0 : GC_API void GC_CALL GC_set_non_gc_bytes(GC_word value)
    1824             : {
    1825           0 :     GC_non_gc_bytes = value;
    1826           0 : }
    1827             : 
    1828           0 : GC_API GC_word GC_CALL GC_get_non_gc_bytes(void)
    1829             : {
    1830           0 :     return GC_non_gc_bytes;
    1831             : }
    1832             : 
    1833           0 : GC_API void GC_CALL GC_set_free_space_divisor(GC_word value)
    1834             : {
    1835             :     GC_ASSERT(value > 0);
    1836           0 :     GC_free_space_divisor = value;
    1837           0 : }
    1838             : 
    1839           0 : GC_API GC_word GC_CALL GC_get_free_space_divisor(void)
    1840             : {
    1841           0 :     return GC_free_space_divisor;
    1842             : }
    1843             : 
    1844           0 : GC_API void GC_CALL GC_set_max_retries(GC_word value)
    1845             : {
    1846             :     GC_ASSERT(value != ~(GC_word)0);
    1847           0 :     GC_max_retries = value;
    1848           0 : }
    1849             : 
    1850           0 : GC_API GC_word GC_CALL GC_get_max_retries(void)
    1851             : {
    1852           0 :     return GC_max_retries;
    1853             : }
    1854             : 
    1855           0 : GC_API void GC_CALL GC_set_dont_precollect(int value)
    1856             : {
    1857             :     GC_ASSERT(value != -1);
    1858             :     /* value is of boolean type. */
    1859           0 :     GC_dont_precollect = value;
    1860           0 : }
    1861             : 
    1862           0 : GC_API int GC_CALL GC_get_dont_precollect(void)
    1863             : {
    1864           0 :     return GC_dont_precollect;
    1865             : }
    1866             : 
    1867           0 : GC_API void GC_CALL GC_set_full_freq(int value)
    1868             : {
    1869             :     GC_ASSERT(value >= 0);
    1870           0 :     GC_full_freq = value;
    1871           0 : }
    1872             : 
    1873           0 : GC_API int GC_CALL GC_get_full_freq(void)
    1874             : {
    1875           0 :     return GC_full_freq;
    1876             : }
    1877             : 
    1878           0 : GC_API void GC_CALL GC_set_time_limit(unsigned long value)
    1879             : {
    1880             :     GC_ASSERT(value != (unsigned long)-1L);
    1881           0 :     GC_time_limit = value;
    1882           0 : }
    1883             : 
    1884           0 : GC_API unsigned long GC_CALL GC_get_time_limit(void)
    1885             : {
    1886           0 :     return GC_time_limit;
    1887             : }
    1888             : 
    1889           0 : GC_API void GC_CALL GC_set_force_unmap_on_gcollect(int value)
    1890             : {
    1891           0 :     GC_force_unmap_on_gcollect = (GC_bool)value;
    1892           0 : }
    1893             : 
    1894           0 : GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void)
    1895             : {
    1896           0 :     return (int)GC_force_unmap_on_gcollect;
    1897             : }

Generated by: LCOV version 1.11