[BACK]Return to misc.c CVS log [TXT][DIR] Up to [local] / OpenXM_contrib2 / asir2000 / gc

Annotation of OpenXM_contrib2/asir2000/gc/misc.c, Revision 1.8

1.1       noro        1: /*
                      2:  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
                      3:  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
1.6       noro        4:  * Copyright (c) 1999-2001 by Hewlett-Packard Company. All rights reserved.
1.1       noro        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: /* Boehm, July 31, 1995 5:02 pm PDT */
                     16:
                     17:
                     18: #include <stdio.h>
1.6       noro       19: #include <limits.h>
1.4       noro       20: #ifndef _WIN32_WCE
1.1       noro       21: #include <signal.h>
1.4       noro       22: #endif
1.1       noro       23:
                     24: #define I_HIDE_POINTERS        /* To make GC_call_with_alloc_lock visible */
1.4       noro       25: #include "private/gc_pmark.h"
1.1       noro       26:
1.6       noro       27: #ifdef GC_SOLARIS_THREADS
1.1       noro       28: # include <sys/syscall.h>
                     29: #endif
1.4       noro       30: #if defined(MSWIN32) || defined(MSWINCE)
                     31: # define WIN32_LEAN_AND_MEAN
                     32: # define NOSERVICE
1.1       noro       33: # include <windows.h>
1.4       noro       34: # include <tchar.h>
1.1       noro       35: #endif
                     36:
                     37: # ifdef THREADS
                     38: #   ifdef PCR
                     39: #     include "il/PCR_IL.h"
                     40:       PCR_Th_ML GC_allocate_ml;
                     41: #   else
                     42: #     ifdef SRC_M3
                     43:        /* Critical section counter is defined in the M3 runtime        */
                     44:        /* That's all we use.                                           */
                     45: #     else
1.6       noro       46: #      ifdef GC_SOLARIS_THREADS
1.1       noro       47:          mutex_t GC_allocate_ml;       /* Implicitly initialized.      */
                     48: #      else
1.6       noro       49: #          if defined(GC_WIN32_THREADS)
                     50: #             if defined(GC_PTHREADS)
                     51:                  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
1.7       noro       52: #            elif defined(GC_DLL)
1.4       noro       53:                 __declspec(dllexport) CRITICAL_SECTION GC_allocate_ml;
                     54: #            else
                     55:                 CRITICAL_SECTION GC_allocate_ml;
                     56: #            endif
1.1       noro       57: #          else
1.6       noro       58: #             if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS)
                     59: #              if defined(USE_SPIN_LOCK)
                     60:                  pthread_t GC_lock_holder = NO_THREAD;
                     61: #              else
1.2       noro       62:                  pthread_mutex_t GC_allocate_ml = PTHREAD_MUTEX_INITIALIZER;
1.4       noro       63:                  pthread_t GC_lock_holder = NO_THREAD;
                     64:                        /* Used only for assertions, and to prevent      */
                     65:                        /* recursive reentry in the system call wrapper. */
1.6       noro       66: #              endif
                     67: #            else
1.2       noro       68:                  --> declare allocator lock here
1.1       noro       69: #            endif
                     70: #         endif
                     71: #      endif
                     72: #     endif
                     73: #   endif
                     74: # endif
                     75:
1.6       noro       76: #if defined(NOSYS) || defined(ECOS)
                     77: #undef STACKBASE
                     78: #endif
                     79:
1.7       noro       80: /* Dont unnecessarily call GC_register_main_static_data() in case      */
                     81: /* dyn_load.c isn't linked in.                                         */
                     82: #ifdef DYNAMIC_LOADING
                     83: # define GC_REGISTER_MAIN_STATIC_DATA() GC_register_main_static_data()
                     84: #else
                     85: # define GC_REGISTER_MAIN_STATIC_DATA() TRUE
                     86: #endif
                     87:
1.1       noro       88: GC_FAR struct _GC_arrays GC_arrays /* = { 0 } */;
                     89:
                     90:
                     91: GC_bool GC_debugging_started = FALSE;
                     92:        /* defined here so we don't have to load debug_malloc.o */
                     93:
1.4       noro       94: void (*GC_check_heap) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
1.6       noro       95: void (*GC_print_all_smashed) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
1.1       noro       96:
1.4       noro       97: void (*GC_start_call_back) GC_PROTO((void)) = (void (*) GC_PROTO((void)))0;
1.1       noro       98:
                     99: ptr_t GC_stackbottom = 0;
                    100:
1.4       noro      101: #ifdef IA64
                    102:   ptr_t GC_register_stackbottom = 0;
                    103: #endif
                    104:
1.1       noro      105: GC_bool GC_dont_gc = 0;
                    106:
1.4       noro      107: GC_bool GC_dont_precollect = 0;
                    108:
1.1       noro      109: GC_bool GC_quiet = 0;
                    110:
1.4       noro      111: GC_bool GC_print_stats = 0;
                    112:
1.6       noro      113: GC_bool GC_print_back_height = 0;
                    114:
1.7       noro      115: #ifndef NO_DEBUGGING
                    116:   GC_bool GC_dump_regularly = 0;  /* Generate regular debugging dumps. */
                    117: #endif
                    118:
1.2       noro      119: #ifdef FIND_LEAK
                    120:   int GC_find_leak = 1;
                    121: #else
                    122:   int GC_find_leak = 0;
                    123: #endif
                    124:
1.4       noro      125: #ifdef ALL_INTERIOR_POINTERS
                    126:   int GC_all_interior_pointers = 1;
                    127: #else
                    128:   int GC_all_interior_pointers = 0;
                    129: #endif
                    130:
1.8     ! noro      131: #if 0
1.6       noro      132: long GC_large_alloc_warn_interval = 5;
1.8     ! noro      133: #else
        !           134: long GC_large_alloc_warn_interval = LONG_MAX;
        !           135: #endif
1.6       noro      136:        /* Interval between unsuppressed warnings.      */
                    137:
                    138: long GC_large_alloc_warn_suppressed = 0;
                    139:        /* Number of warnings suppressed so far.        */
                    140:
1.1       noro      141: /*ARGSUSED*/
                    142: GC_PTR GC_default_oom_fn GC_PROTO((size_t bytes_requested))
                    143: {
                    144:     return(0);
                    145: }
                    146:
                    147: GC_PTR (*GC_oom_fn) GC_PROTO((size_t bytes_requested)) = GC_default_oom_fn;
                    148:
                    149: extern signed_word GC_mem_found;
                    150:
1.7       noro      151: void * GC_project2(arg1, arg2)
                    152: void *arg1;
                    153: void *arg2;
                    154: {
                    155:   return arg2;
                    156: }
                    157:
1.1       noro      158: # ifdef MERGE_SIZES
                    159:     /* Set things up so that GC_size_map[i] >= words(i),               */
                    160:     /* but not too much bigger                                         */
                    161:     /* and so that size_map contains relatively few distinct entries   */
                    162:     /* This is stolen from Russ Atkinson's Cedar quantization          */
                    163:     /* alogrithm (but we precompute it).                               */
                    164:
                    165:
                    166:     void GC_init_size_map()
                    167:     {
                    168:        register unsigned i;
                    169:
1.4       noro      170:        /* Map size 0 to something bigger.                      */
                    171:        /* This avoids problems at lower levels.                */
                    172:        /* One word objects don't have to be 2 word aligned,    */
                    173:        /* unless we're using mark bytes.                       */
                    174:          for (i = 0; i < sizeof(word); i++) {
                    175:              GC_size_map[i] = MIN_WORDS;
1.1       noro      176:          }
1.4       noro      177: #        if MIN_WORDS > 1
                    178:            GC_size_map[sizeof(word)] = MIN_WORDS;
                    179: #        else
                    180:            GC_size_map[sizeof(word)] = ROUNDED_UP_WORDS(sizeof(word));
                    181: #        endif
1.1       noro      182:        for (i = sizeof(word) + 1; i <= 8 * sizeof(word); i++) {
1.4       noro      183:            GC_size_map[i] = ALIGNED_WORDS(i);
1.1       noro      184:        }
                    185:        for (i = 8*sizeof(word) + 1; i <= 16 * sizeof(word); i++) {
                    186:              GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 1) & (~1);
                    187:        }
1.3       noro      188: #      ifdef GC_GCJ_SUPPORT
                    189:           /* Make all sizes up to 32 words predictable, so that a      */
                    190:           /* compiler can statically perform the same computation,     */
                    191:           /* or at least a computation that results in similar size    */
                    192:           /* classes.                                                  */
                    193:           for (i = 16*sizeof(word) + 1; i <= 32 * sizeof(word); i++) {
                    194:              GC_size_map[i] = (ROUNDED_UP_WORDS(i) + 3) & (~3);
                    195:           }
                    196: #      endif
1.1       noro      197:        /* We leave the rest of the array to be filled in on demand. */
                    198:     }
                    199:
                    200:     /* Fill in additional entries in GC_size_map, including the ith one */
                    201:     /* We assume the ith entry is currently 0.                         */
                    202:     /* Note that a filled in section of the array ending at n always    */
                    203:     /* has length at least n/4.                                                */
                    204:     void GC_extend_size_map(i)
                    205:     word i;
                    206:     {
                    207:         word orig_word_sz = ROUNDED_UP_WORDS(i);
                    208:         word word_sz = orig_word_sz;
                    209:        register word byte_sz = WORDS_TO_BYTES(word_sz);
                    210:                                /* The size we try to preserve.         */
                    211:                                /* Close to to i, unless this would     */
                    212:                                /* introduce too many distinct sizes.   */
                    213:        word smaller_than_i = byte_sz - (byte_sz >> 3);
                    214:        word much_smaller_than_i = byte_sz - (byte_sz >> 2);
                    215:        register word low_limit;        /* The lowest indexed entry we  */
                    216:                                        /* initialize.                  */
                    217:        register word j;
                    218:
                    219:        if (GC_size_map[smaller_than_i] == 0) {
                    220:            low_limit = much_smaller_than_i;
                    221:            while (GC_size_map[low_limit] != 0) low_limit++;
                    222:        } else {
                    223:            low_limit = smaller_than_i + 1;
                    224:            while (GC_size_map[low_limit] != 0) low_limit++;
                    225:            word_sz = ROUNDED_UP_WORDS(low_limit);
                    226:            word_sz += word_sz >> 3;
                    227:            if (word_sz < orig_word_sz) word_sz = orig_word_sz;
                    228:        }
                    229: #      ifdef ALIGN_DOUBLE
                    230:            word_sz += 1;
                    231:            word_sz &= ~1;
                    232: #      endif
                    233:        if (word_sz > MAXOBJSZ) {
                    234:            word_sz = MAXOBJSZ;
                    235:        }
                    236:        /* If we can fit the same number of larger objects in a block,  */
                    237:        /* do so.                                                       */
                    238:        {
                    239:            size_t number_of_objs = BODY_SZ/word_sz;
                    240:            word_sz = BODY_SZ/number_of_objs;
                    241: #          ifdef ALIGN_DOUBLE
                    242:                word_sz &= ~1;
                    243: #          endif
                    244:        }
                    245:        byte_sz = WORDS_TO_BYTES(word_sz);
1.4       noro      246:        if (GC_all_interior_pointers) {
1.1       noro      247:            /* We need one extra byte; don't fill in GC_size_map[byte_sz] */
                    248:            byte_sz--;
1.4       noro      249:        }
1.1       noro      250:
                    251:        for (j = low_limit; j <= byte_sz; j++) GC_size_map[j] = word_sz;
                    252:     }
                    253: # endif
                    254:
                    255:
                    256: /*
                    257:  * The following is a gross hack to deal with a problem that can occur
                    258:  * on machines that are sloppy about stack frame sizes, notably SPARC.
                    259:  * Bogus pointers may be written to the stack and not cleared for
                    260:  * a LONG time, because they always fall into holes in stack frames
                    261:  * that are not written.  We partially address this by clearing
                    262:  * sections of the stack whenever we get control.
                    263:  */
                    264: word GC_stack_last_cleared = 0;        /* GC_no when we last did this */
                    265: # ifdef THREADS
1.4       noro      266: #   define BIG_CLEAR_SIZE 2048 /* Clear this much now and then.        */
                    267: #   define SMALL_CLEAR_SIZE 256 /* Clear this much every time.         */
1.1       noro      268: # endif
1.4       noro      269: # define CLEAR_SIZE 213  /* Granularity for GC_clear_stack_inner */
1.1       noro      270: # define DEGRADE_RATE 50
                    271:
                    272: word GC_min_sp;                /* Coolest stack pointer value from which we've */
                    273:                        /* already cleared the stack.                   */
                    274:
                    275: word GC_high_water;
                    276:                        /* "hottest" stack pointer value we have seen   */
                    277:                        /* recently.  Degrades over time.               */
                    278:
                    279: word GC_words_allocd_at_reset;
                    280:
1.4       noro      281: #if defined(ASM_CLEAR_CODE)
1.1       noro      282:   extern ptr_t GC_clear_stack_inner();
1.4       noro      283: #else
1.1       noro      284: /* Clear the stack up to about limit.  Return arg. */
                    285: /*ARGSUSED*/
                    286: ptr_t GC_clear_stack_inner(arg, limit)
                    287: ptr_t arg;
                    288: word limit;
                    289: {
                    290:     word dummy[CLEAR_SIZE];
                    291:
                    292:     BZERO(dummy, CLEAR_SIZE*sizeof(word));
                    293:     if ((word)(dummy) COOLER_THAN limit) {
                    294:         (void) GC_clear_stack_inner(arg, limit);
                    295:     }
                    296:     /* Make sure the recursive call is not a tail call, and the bzero  */
                    297:     /* call is not recognized as dead code.                            */
                    298:     GC_noop1((word)dummy);
                    299:     return(arg);
                    300: }
                    301: #endif
                    302:
                    303: /* Clear some of the inaccessible part of the stack.  Returns its      */
                    304: /* argument, so it can be used in a tail call position, hence clearing  */
                    305: /* another frame.                                                      */
                    306: ptr_t GC_clear_stack(arg)
                    307: ptr_t arg;
                    308: {
                    309:     register word sp = (word)GC_approx_sp();  /* Hotter than actual sp */
                    310: #   ifdef THREADS
1.4       noro      311:         word dummy[SMALL_CLEAR_SIZE];
                    312:        static unsigned random_no = 0;
                    313:                                         /* Should be more random than it is ... */
                    314:                                 /* Used to occasionally clear a bigger  */
                    315:                                 /* chunk.                               */
1.1       noro      316: #   endif
1.4       noro      317:     register word limit;
1.1       noro      318:
                    319: #   define SLOP 400
                    320:        /* Extra bytes we clear every time.  This clears our own        */
                    321:        /* activation record, and should cause more frequent            */
                    322:        /* clearing near the cold end of the stack, a good thing.       */
                    323: #   define GC_SLOP 4000
                    324:        /* We make GC_high_water this much hotter than we really saw    */
                    325:        /* saw it, to cover for GC noise etc. above our current frame.  */
                    326: #   define CLEAR_THRESHOLD 100000
                    327:        /* We restart the clearing process after this many bytes of     */
                    328:        /* allocation.  Otherwise very heavily recursive programs       */
                    329:        /* with sparse stacks may result in heaps that grow almost      */
                    330:        /* without bounds.  As the heap gets larger, collection         */
                    331:        /* frequency decreases, thus clearing frequency would decrease, */
                    332:        /* thus more junk remains accessible, thus the heap gets        */
                    333:        /* larger ...                                                   */
                    334: # ifdef THREADS
1.4       noro      335:     if (++random_no % 13 == 0) {
                    336:        limit = sp;
                    337:        MAKE_HOTTER(limit, BIG_CLEAR_SIZE*sizeof(word));
1.6       noro      338:         limit &= ~0xf; /* Make it sufficiently aligned for assembly    */
                    339:                        /* implementations of GC_clear_stack_inner.     */
1.4       noro      340:        return GC_clear_stack_inner(arg, limit);
                    341:     } else {
                    342:        BZERO(dummy, SMALL_CLEAR_SIZE*sizeof(word));
                    343:        return arg;
                    344:     }
1.1       noro      345: # else
                    346:     if (GC_gc_no > GC_stack_last_cleared) {
                    347:         /* Start things over, so we clear the entire stack again */
                    348:         if (GC_stack_last_cleared == 0) GC_high_water = (word) GC_stackbottom;
                    349:         GC_min_sp = GC_high_water;
                    350:         GC_stack_last_cleared = GC_gc_no;
                    351:         GC_words_allocd_at_reset = GC_words_allocd;
                    352:     }
                    353:     /* Adjust GC_high_water */
                    354:         MAKE_COOLER(GC_high_water, WORDS_TO_BYTES(DEGRADE_RATE) + GC_SLOP);
                    355:         if (sp HOTTER_THAN GC_high_water) {
                    356:             GC_high_water = sp;
                    357:         }
                    358:         MAKE_HOTTER(GC_high_water, GC_SLOP);
                    359:     limit = GC_min_sp;
                    360:     MAKE_HOTTER(limit, SLOP);
                    361:     if (sp COOLER_THAN limit) {
                    362:         limit &= ~0xf; /* Make it sufficiently aligned for assembly    */
                    363:                        /* implementations of GC_clear_stack_inner.     */
                    364:         GC_min_sp = sp;
                    365:         return(GC_clear_stack_inner(arg, limit));
                    366:     } else if (WORDS_TO_BYTES(GC_words_allocd - GC_words_allocd_at_reset)
                    367:               > CLEAR_THRESHOLD) {
                    368:        /* Restart clearing process, but limit how much clearing we do. */
                    369:        GC_min_sp = sp;
                    370:        MAKE_HOTTER(GC_min_sp, CLEAR_THRESHOLD/4);
                    371:        if (GC_min_sp HOTTER_THAN GC_high_water) GC_min_sp = GC_high_water;
                    372:        GC_words_allocd_at_reset = GC_words_allocd;
                    373:     }
1.4       noro      374:     return(arg);
1.1       noro      375: # endif
                    376: }
                    377:
                    378:
                    379: /* Return a pointer to the base address of p, given a pointer to a     */
                    380: /* an address within an object.  Return 0 o.w.                         */
                    381: # ifdef __STDC__
                    382:     GC_PTR GC_base(GC_PTR p)
                    383: # else
                    384:     GC_PTR GC_base(p)
                    385:     GC_PTR p;
                    386: # endif
                    387: {
                    388:     register word r;
                    389:     register struct hblk *h;
                    390:     register bottom_index *bi;
                    391:     register hdr *candidate_hdr;
                    392:     register word limit;
                    393:
                    394:     r = (word)p;
                    395:     if (!GC_is_initialized) return 0;
                    396:     h = HBLKPTR(r);
                    397:     GET_BI(r, bi);
                    398:     candidate_hdr = HDR_FROM_BI(bi, r);
                    399:     if (candidate_hdr == 0) return(0);
                    400:     /* If it's a pointer to the middle of a large object, move it      */
                    401:     /* to the beginning.                                               */
                    402:        while (IS_FORWARDING_ADDR_OR_NIL(candidate_hdr)) {
                    403:           h = FORWARDED_ADDR(h,candidate_hdr);
1.4       noro      404:           r = (word)h;
1.1       noro      405:           candidate_hdr = HDR(h);
                    406:        }
                    407:     if (candidate_hdr -> hb_map == GC_invalid_map) return(0);
                    408:     /* Make sure r points to the beginning of the object */
                    409:        r &= ~(WORDS_TO_BYTES(1) - 1);
                    410:         {
1.4       noro      411:            register int offset = HBLKDISPL(r);
1.1       noro      412:            register signed_word sz = candidate_hdr -> hb_sz;
1.4       noro      413:            register signed_word map_entry;
1.1       noro      414:
1.4       noro      415:            map_entry = MAP_ENTRY((candidate_hdr -> hb_map), offset);
                    416:            if (map_entry > CPP_MAX_OFFSET) {
                    417:                map_entry = (signed_word)(BYTES_TO_WORDS(offset)) % sz;
                    418:             }
                    419:             r -= WORDS_TO_BYTES(map_entry);
                    420:             limit = r + WORDS_TO_BYTES(sz);
                    421:            if (limit > (word)(h + 1)
                    422:                && sz <= BYTES_TO_WORDS(HBLKSIZE)) {
1.1       noro      423:                return(0);
1.4       noro      424:            }
1.1       noro      425:            if ((word)p >= limit) return(0);
                    426:        }
                    427:     return((GC_PTR)r);
                    428: }
                    429:
                    430:
                    431: /* Return the size of an object, given a pointer to its base.          */
                    432: /* (For small obects this also happens to work from interior pointers, */
                    433: /* but that shouldn't be relied upon.)                                 */
                    434: # ifdef __STDC__
                    435:     size_t GC_size(GC_PTR p)
                    436: # else
                    437:     size_t GC_size(p)
                    438:     GC_PTR p;
                    439: # endif
                    440: {
                    441:     register int sz;
                    442:     register hdr * hhdr = HDR(p);
                    443:
                    444:     sz = WORDS_TO_BYTES(hhdr -> hb_sz);
1.4       noro      445:     return(sz);
1.1       noro      446: }
                    447:
                    448: size_t GC_get_heap_size GC_PROTO(())
                    449: {
                    450:     return ((size_t) GC_heapsize);
                    451: }
                    452:
1.2       noro      453: size_t GC_get_free_bytes GC_PROTO(())
                    454: {
                    455:     return ((size_t) GC_large_free_bytes);
                    456: }
                    457:
1.1       noro      458: size_t GC_get_bytes_since_gc GC_PROTO(())
                    459: {
                    460:     return ((size_t) WORDS_TO_BYTES(GC_words_allocd));
                    461: }
                    462:
1.4       noro      463: size_t GC_get_total_bytes GC_PROTO(())
                    464: {
                    465:     return ((size_t) WORDS_TO_BYTES(GC_words_allocd+GC_words_allocd_before_gc));
                    466: }
                    467:
1.1       noro      468: GC_bool GC_is_initialized = FALSE;
                    469:
                    470: void GC_init()
                    471: {
                    472:     DCL_LOCK_STATE;
                    473:
                    474:     DISABLE_SIGNALS();
1.6       noro      475:
                    476: #if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS)
                    477:     if (!GC_is_initialized) InitializeCriticalSection(&GC_allocate_ml);
                    478: #endif /* MSWIN32 */
                    479:
1.1       noro      480:     LOCK();
                    481:     GC_init_inner();
                    482:     UNLOCK();
                    483:     ENABLE_SIGNALS();
                    484:
1.6       noro      485: #   if defined(PARALLEL_MARK) || defined(THREAD_LOCAL_ALLOC)
                    486:        /* Make sure marker threads and started and thread local */
                    487:        /* allocation is initialized, in case we didn't get      */
                    488:        /* called from GC_init_parallel();                       */
                    489:         {
                    490:          extern void GC_init_parallel(void);
                    491:          GC_init_parallel();
                    492:        }
                    493: #   endif /* PARALLEL_MARK || THREAD_LOCAL_ALLOC */
1.7       noro      494:
                    495: #   if defined(DYNAMIC_LOADING) && defined(DARWIN)
                    496:     {
                    497:         /* This must be called WITHOUT the allocation lock held
                    498:         and before any threads are created */
                    499:         extern void GC_init_dyld();
                    500:         GC_init_dyld();
                    501:     }
                    502: #   endif
1.1       noro      503: }
                    504:
1.4       noro      505: #if defined(MSWIN32) || defined(MSWINCE)
                    506:     CRITICAL_SECTION GC_write_cs;
                    507: #endif
                    508:
1.1       noro      509: #ifdef MSWIN32
1.4       noro      510:     extern void GC_init_win32 GC_PROTO((void));
1.1       noro      511: #endif
                    512:
                    513: extern void GC_setpagesize();
                    514:
1.7       noro      515:
                    516: #ifdef MSWIN32
                    517: extern GC_bool GC_no_win32_dlls;
                    518: #else
                    519: # define GC_no_win32_dlls FALSE
                    520: #endif
                    521:
                    522: void GC_exit_check GC_PROTO((void))
                    523: {
                    524:    GC_gcollect();
                    525: }
                    526:
                    527: #ifdef SEARCH_FOR_DATA_START
                    528:   extern void GC_init_linux_data_start GC_PROTO((void));
                    529: #endif
                    530:
1.4       noro      531: #ifdef UNIX_LIKE
                    532:
                    533: extern void GC_set_and_save_fault_handler GC_PROTO((void (*handler)(int)));
                    534:
                    535: static void looping_handler(sig)
                    536: int sig;
                    537: {
                    538:     GC_err_printf1("Caught signal %d: looping in handler\n", sig);
                    539:     for(;;);
                    540: }
                    541:
1.7       noro      542: static GC_bool installed_looping_handler = FALSE;
                    543:
                    544: void maybe_install_looping_handler()
                    545: {
                    546:     /* Install looping handler before the write fault handler, so we   */
                    547:     /* handle write faults correctly.                                  */
                    548:       if (!installed_looping_handler && 0 != GETENV("GC_LOOP_ON_ABORT")) {
                    549:         GC_set_and_save_fault_handler(looping_handler);
                    550:         installed_looping_handler = TRUE;
                    551:       }
                    552: }
                    553:
                    554: #else /* !UNIX_LIKE */
                    555:
                    556: # define maybe_install_looping_handler()
                    557:
1.6       noro      558: #endif
                    559:
1.1       noro      560: void GC_init_inner()
                    561: {
1.4       noro      562: #   if !defined(THREADS) && defined(GC_ASSERTIONS)
1.1       noro      563:         word dummy;
                    564: #   endif
1.4       noro      565:     word initial_heap_sz = (word)MINHINCR;
1.1       noro      566:
                    567:     if (GC_is_initialized) return;
1.4       noro      568: #   ifdef PRINTSTATS
                    569:       GC_print_stats = 1;
                    570: #   endif
1.6       noro      571: #   if defined(MSWIN32) || defined(MSWINCE)
                    572:       InitializeCriticalSection(&GC_write_cs);
                    573: #   endif
1.4       noro      574:     if (0 != GETENV("GC_PRINT_STATS")) {
                    575:       GC_print_stats = 1;
                    576:     }
1.7       noro      577: #   ifndef NO_DEBUGGING
                    578:       if (0 != GETENV("GC_DUMP_REGULARLY")) {
                    579:         GC_dump_regularly = 1;
                    580:       }
                    581: #   endif
1.4       noro      582:     if (0 != GETENV("GC_FIND_LEAK")) {
                    583:       GC_find_leak = 1;
1.7       noro      584: #     ifdef __STDC__
                    585:         atexit(GC_exit_check);
                    586: #     endif
1.4       noro      587:     }
                    588:     if (0 != GETENV("GC_ALL_INTERIOR_POINTERS")) {
                    589:       GC_all_interior_pointers = 1;
                    590:     }
                    591:     if (0 != GETENV("GC_DONT_GC")) {
                    592:       GC_dont_gc = 1;
                    593:     }
1.6       noro      594:     if (0 != GETENV("GC_PRINT_BACK_HEIGHT")) {
                    595:       GC_print_back_height = 1;
                    596:     }
                    597:     if (0 != GETENV("GC_NO_BLACKLIST_WARNING")) {
                    598:       GC_large_alloc_warn_interval = LONG_MAX;
                    599:     }
                    600:     {
                    601:       char * time_limit_string = GETENV("GC_PAUSE_TIME_TARGET");
                    602:       if (0 != time_limit_string) {
                    603:         long time_limit = atol(time_limit_string);
                    604:         if (time_limit < 5) {
                    605:          WARN("GC_PAUSE_TIME_TARGET environment variable value too small "
                    606:               "or bad syntax: Ignoring\n", 0);
                    607:         } else {
                    608:          GC_time_limit = time_limit;
                    609:         }
                    610:       }
                    611:     }
                    612:     {
                    613:       char * interval_string = GETENV("GC_LARGE_ALLOC_WARN_INTERVAL");
                    614:       if (0 != interval_string) {
                    615:         long interval = atol(interval_string);
                    616:         if (interval <= 0) {
                    617:          WARN("GC_LARGE_ALLOC_WARN_INTERVAL environment variable has "
                    618:               "bad value: Ignoring\n", 0);
                    619:         } else {
                    620:          GC_large_alloc_warn_interval = interval;
                    621:         }
                    622:       }
                    623:     }
1.7       noro      624:     maybe_install_looping_handler();
1.4       noro      625:     /* Adjust normal object descriptor for extra allocation.   */
                    626:     if (ALIGNMENT > GC_DS_TAGS && EXTRA_BYTES != 0) {
                    627:       GC_obj_kinds[NORMAL].ok_descriptor = ((word)(-ALIGNMENT) | GC_DS_LENGTH);
                    628:     }
1.1       noro      629:     GC_setpagesize();
1.4       noro      630:     GC_exclude_static_roots(beginGC_arrays, endGC_arrays);
                    631:     GC_exclude_static_roots(beginGC_obj_kinds, endGC_obj_kinds);
                    632: #   ifdef SEPARATE_GLOBALS
                    633:       GC_exclude_static_roots(beginGC_objfreelist, endGC_objfreelist);
                    634:       GC_exclude_static_roots(beginGC_aobjfreelist, endGC_aobjfreelist);
1.1       noro      635: #   endif
                    636: #   ifdef MSWIN32
                    637:        GC_init_win32();
                    638: #   endif
1.3       noro      639: #   if defined(SEARCH_FOR_DATA_START)
1.1       noro      640:        GC_init_linux_data_start();
                    641: #   endif
1.6       noro      642: #   if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__)
1.4       noro      643:        GC_init_netbsd_elf();
                    644: #   endif
1.6       noro      645: #   if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS)
1.4       noro      646:         GC_thr_init();
                    647: #   endif
1.6       noro      648: #   ifdef GC_SOLARIS_THREADS
1.1       noro      649:        /* We need dirty bits in order to find live stack sections.     */
                    650:         GC_dirty_init();
                    651: #   endif
1.6       noro      652: #   if !defined(THREADS) || defined(GC_PTHREADS) || defined(GC_WIN32_THREADS) \
                    653:        || defined(GC_SOLARIS_THREADS)
1.1       noro      654:       if (GC_stackbottom == 0) {
                    655:        GC_stackbottom = GC_get_stack_base();
1.4       noro      656: #       if defined(LINUX) && defined(IA64)
                    657:          GC_register_stackbottom = GC_get_register_stack_base();
                    658: #       endif
1.7       noro      659:       } else {
                    660: #       if defined(LINUX) && defined(IA64)
                    661:          if (GC_register_stackbottom == 0) {
                    662:            WARN("GC_register_stackbottom should be set with GC_stackbottom", 0);
                    663:            /* The following is likely to fail, since we rely on        */
                    664:            /* alignment properties that may not hold with a user set   */
                    665:            /* GC_stackbottom.                                          */
                    666:            GC_register_stackbottom = GC_get_register_stack_base();
                    667:          }
                    668: #      endif
1.1       noro      669:       }
                    670: #   endif
1.7       noro      671:     GC_STATIC_ASSERT(sizeof (ptr_t) == sizeof(word));
                    672:     GC_STATIC_ASSERT(sizeof (signed_word) == sizeof(word));
                    673:     GC_STATIC_ASSERT(sizeof (struct hblk) == HBLKSIZE);
1.1       noro      674: #   ifndef THREADS
                    675: #     if defined(STACK_GROWS_UP) && defined(STACK_GROWS_DOWN)
                    676:        ABORT(
                    677:          "Only one of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
                    678: #     endif
                    679: #     if !defined(STACK_GROWS_UP) && !defined(STACK_GROWS_DOWN)
                    680:        ABORT(
                    681:          "One of STACK_GROWS_UP and STACK_GROWS_DOWN should be defd\n");
                    682: #     endif
                    683: #     ifdef STACK_GROWS_DOWN
1.4       noro      684:         GC_ASSERT((word)(&dummy) <= (word)GC_stackbottom);
1.1       noro      685: #     else
1.4       noro      686:         GC_ASSERT((word)(&dummy) >= (word)GC_stackbottom);
1.1       noro      687: #     endif
                    688: #   endif
                    689: #   if !defined(_AUX_SOURCE) || defined(__GNUC__)
1.4       noro      690:       GC_ASSERT((word)(-1) > (word)0);
                    691:       /* word should be unsigned */
1.1       noro      692: #   endif
1.4       noro      693:     GC_ASSERT((signed_word)(-1) < (signed_word)0);
1.1       noro      694:
                    695:     /* Add initial guess of root sets.  Do this first, since sbrk(0)   */
                    696:     /* might be used.                                                  */
1.7       noro      697:       if (GC_REGISTER_MAIN_STATIC_DATA()) GC_register_data_segments();
1.1       noro      698:     GC_init_headers();
                    699:     GC_bl_init();
                    700:     GC_mark_init();
1.4       noro      701:     {
                    702:        char * sz_str = GETENV("GC_INITIAL_HEAP_SIZE");
                    703:        if (sz_str != NULL) {
                    704:          initial_heap_sz = atoi(sz_str);
                    705:          if (initial_heap_sz <= MINHINCR * HBLKSIZE) {
                    706:            WARN("Bad initial heap size %s - ignoring it.\n",
                    707:                 sz_str);
                    708:          }
                    709:          initial_heap_sz = divHBLKSZ(initial_heap_sz);
                    710:        }
                    711:     }
1.7       noro      712:     {
                    713:        char * sz_str = GETENV("GC_MAXIMUM_HEAP_SIZE");
                    714:        if (sz_str != NULL) {
                    715:          word max_heap_sz = (word)atol(sz_str);
                    716:          if (max_heap_sz < initial_heap_sz * HBLKSIZE) {
                    717:            WARN("Bad maximum heap size %s - ignoring it.\n",
                    718:                 sz_str);
                    719:          }
                    720:          if (0 == GC_max_retries) GC_max_retries = 2;
                    721:          GC_set_max_heap_size(max_heap_sz);
                    722:        }
                    723:     }
1.4       noro      724:     if (!GC_expand_hp_inner(initial_heap_sz)) {
1.1       noro      725:         GC_err_printf0("Can't start up: not enough memory\n");
                    726:         EXIT();
                    727:     }
                    728:     /* Preallocate large object map.  It's otherwise inconvenient to   */
                    729:     /* deal with failure.                                              */
                    730:       if (!GC_add_map_entry((word)0)) {
                    731:         GC_err_printf0("Can't start up: not enough memory\n");
                    732:         EXIT();
                    733:       }
                    734:     GC_register_displacement_inner(0L);
                    735: #   ifdef MERGE_SIZES
                    736:       GC_init_size_map();
                    737: #   endif
                    738: #   ifdef PCR
                    739:       if (PCR_IL_Lock(PCR_Bool_false, PCR_allSigsBlocked, PCR_waitForever)
                    740:           != PCR_ERes_okay) {
                    741:           ABORT("Can't lock load state\n");
                    742:       } else if (PCR_IL_Unlock() != PCR_ERes_okay) {
                    743:           ABORT("Can't unlock load state\n");
                    744:       }
                    745:       PCR_IL_Unlock();
                    746:       GC_pcr_install();
                    747: #   endif
1.6       noro      748: #   if !defined(SMALL_CONFIG)
                    749:       if (!GC_no_win32_dlls && 0 != GETENV("GC_ENABLE_INCREMENTAL")) {
                    750:        GC_ASSERT(!GC_incremental);
                    751:         GC_setpagesize();
                    752: #       ifndef GC_SOLARIS_THREADS
                    753:           GC_dirty_init();
                    754: #       endif
                    755:         GC_ASSERT(GC_words_allocd == 0)
                    756:        GC_incremental = TRUE;
                    757:       }
                    758: #   endif /* !SMALL_CONFIG */
1.7       noro      759:     COND_DUMP;
1.6       noro      760:     /* Get black list set up and/or incrmental GC started */
                    761:       if (!GC_dont_precollect || GC_incremental) GC_gcollect_inner();
1.4       noro      762:     GC_is_initialized = TRUE;
1.1       noro      763: #   ifdef STUBBORN_ALLOC
                    764:        GC_stubborn_init();
                    765: #   endif
                    766:     /* Convince lint that some things are used */
                    767: #   ifdef LINT
                    768:       {
                    769:           extern char * GC_copyright[];
                    770:           extern int GC_read();
                    771:           extern void GC_register_finalizer_no_order();
                    772:
                    773:           GC_noop(GC_copyright, GC_find_header,
                    774:                   GC_push_one, GC_call_with_alloc_lock, GC_read,
                    775:                   GC_dont_expand,
                    776: #                ifndef NO_DEBUGGING
                    777:                    GC_dump,
                    778: #                endif
                    779:                   GC_register_finalizer_no_order);
                    780:       }
                    781: #   endif
                    782: }
                    783:
                    784: void GC_enable_incremental GC_PROTO(())
                    785: {
1.2       noro      786: # if !defined(SMALL_CONFIG)
                    787:   if (!GC_find_leak) {
1.1       noro      788:     DCL_LOCK_STATE;
                    789:
                    790:     DISABLE_SIGNALS();
                    791:     LOCK();
                    792:     if (GC_incremental) goto out;
                    793:     GC_setpagesize();
1.6       noro      794:     if (GC_no_win32_dlls) goto out;
1.7       noro      795: #   ifndef GC_SOLARIS_THREADS
                    796:       maybe_install_looping_handler();  /* Before write fault handler! */
                    797:       GC_dirty_init();
1.1       noro      798: #   endif
                    799:     if (!GC_is_initialized) {
                    800:         GC_init_inner();
                    801:     }
1.6       noro      802:     if (GC_incremental) goto out;
1.1       noro      803:     if (GC_dont_gc) {
                    804:         /* Can't easily do it. */
                    805:         UNLOCK();
                    806:        ENABLE_SIGNALS();
                    807:        return;
                    808:     }
                    809:     if (GC_words_allocd > 0) {
                    810:        /* There may be unmarked reachable objects      */
                    811:        GC_gcollect_inner();
                    812:     }   /* else we're OK in assuming everything's      */
                    813:        /* clean since nothing can point to an          */
                    814:        /* unmarked object.                             */
                    815:     GC_read_dirty();
                    816:     GC_incremental = TRUE;
                    817: out:
                    818:     UNLOCK();
                    819:     ENABLE_SIGNALS();
1.2       noro      820:   }
1.1       noro      821: # endif
                    822: }
                    823:
                    824:
1.4       noro      825: #if defined(MSWIN32) || defined(MSWINCE)
                    826: # define LOG_FILE _T("gc.log")
                    827:
                    828:   HANDLE GC_stdout = 0;
1.1       noro      829:
1.4       noro      830:   void GC_deinit()
                    831:   {
                    832:       if (GC_is_initialized) {
                    833:        DeleteCriticalSection(&GC_write_cs);
                    834:       }
                    835:   }
1.1       noro      836:
1.4       noro      837:   int GC_write(buf, len)
1.6       noro      838:   GC_CONST char * buf;
1.4       noro      839:   size_t len;
1.1       noro      840:   {
1.4       noro      841:       BOOL tmp;
                    842:       DWORD written;
                    843:       if (len == 0)
                    844:          return 0;
                    845:       EnterCriticalSection(&GC_write_cs);
                    846:       if (GC_stdout == INVALID_HANDLE_VALUE) {
                    847:          return -1;
                    848:       } else if (GC_stdout == 0) {
                    849:          GC_stdout = CreateFile(LOG_FILE, GENERIC_WRITE,
                    850:                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
                    851:                                 NULL, CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH,
                    852:                                 NULL);
                    853:          if (GC_stdout == INVALID_HANDLE_VALUE) ABORT("Open of log file failed");
                    854:       }
                    855:       tmp = WriteFile(GC_stdout, buf, len, &written, NULL);
                    856:       if (!tmp)
                    857:          DebugBreak();
                    858:       LeaveCriticalSection(&GC_write_cs);
                    859:       return tmp ? (int)written : -1;
1.1       noro      860:   }
                    861:
                    862: #endif
                    863:
                    864: #if defined(OS2) || defined(MACOS)
                    865: FILE * GC_stdout = NULL;
                    866: FILE * GC_stderr = NULL;
                    867: int GC_tmp;  /* Should really be local ... */
                    868:
                    869:   void GC_set_files()
                    870:   {
                    871:       if (GC_stdout == NULL) {
                    872:        GC_stdout = stdout;
                    873:     }
                    874:     if (GC_stderr == NULL) {
                    875:        GC_stderr = stderr;
                    876:     }
                    877:   }
                    878: #endif
                    879:
1.4       noro      880: #if !defined(OS2) && !defined(MACOS) && !defined(MSWIN32) && !defined(MSWINCE)
1.1       noro      881:   int GC_stdout = 1;
                    882:   int GC_stderr = 2;
                    883: # if !defined(AMIGA)
                    884: #   include <unistd.h>
                    885: # endif
                    886: #endif
                    887:
1.6       noro      888: #if !defined(MSWIN32) && !defined(MSWINCE) && !defined(OS2) \
                    889:     && !defined(MACOS)  && !defined(ECOS) && !defined(NOSYS)
1.1       noro      890: int GC_write(fd, buf, len)
                    891: int fd;
1.6       noro      892: GC_CONST char *buf;
1.1       noro      893: size_t len;
                    894: {
                    895:      register int bytes_written = 0;
                    896:      register int result;
                    897:
                    898:      while (bytes_written < len) {
1.6       noro      899: #      ifdef GC_SOLARIS_THREADS
1.1       noro      900:            result = syscall(SYS_write, fd, buf + bytes_written,
                    901:                                            len - bytes_written);
                    902: #      else
                    903:            result = write(fd, buf + bytes_written, len - bytes_written);
                    904: #      endif
                    905:        if (-1 == result) return(result);
                    906:        bytes_written += result;
                    907:     }
                    908:     return(bytes_written);
                    909: }
                    910: #endif /* UN*X */
                    911:
1.6       noro      912: #ifdef ECOS
                    913: int GC_write(fd, buf, len)
                    914: {
                    915:   _Jv_diag_write (buf, len);
                    916:   return len;
                    917: }
                    918: #endif
                    919:
                    920: #ifdef NOSYS
                    921: int GC_write(fd, buf, len)
                    922: {
                    923:   /* No writing.  */
                    924:   return len;
                    925: }
                    926: #endif
                    927:
                    928:
1.4       noro      929: #if defined(MSWIN32) || defined(MSWINCE)
                    930: #   define WRITE(f, buf, len) GC_write(buf, len)
1.1       noro      931: #else
                    932: #   if defined(OS2) || defined(MACOS)
                    933: #   define WRITE(f, buf, len) (GC_set_files(), \
                    934:                               GC_tmp = fwrite((buf), 1, (len), (f)), \
                    935:                               fflush(f), GC_tmp)
                    936: #   else
                    937: #     define WRITE(f, buf, len) GC_write((f), (buf), (len))
                    938: #   endif
                    939: #endif
                    940:
                    941: /* A version of printf that is unlikely to call malloc, and is thus safer */
                    942: /* to call from the collector in case malloc has been bound to GC_malloc. */
                    943: /* Assumes that no more than 1023 characters are written at once.        */
                    944: /* Assumes that all arguments have been converted to something of the    */
                    945: /* same size as long, and that the format conversions expect something   */
                    946: /* of that size.                                                         */
                    947: void GC_printf(format, a, b, c, d, e, f)
1.4       noro      948: GC_CONST char * format;
1.1       noro      949: long a, b, c, d, e, f;
                    950: {
                    951:     char buf[1025];
                    952:
                    953:     if (GC_quiet) return;
                    954:     buf[1024] = 0x15;
                    955:     (void) sprintf(buf, format, a, b, c, d, e, f);
                    956:     if (buf[1024] != 0x15) ABORT("GC_printf clobbered stack");
                    957:     if (WRITE(GC_stdout, buf, strlen(buf)) < 0) ABORT("write to stdout failed");
                    958: }
                    959:
                    960: void GC_err_printf(format, a, b, c, d, e, f)
1.4       noro      961: GC_CONST char * format;
1.1       noro      962: long a, b, c, d, e, f;
                    963: {
                    964:     char buf[1025];
                    965:
                    966:     buf[1024] = 0x15;
                    967:     (void) sprintf(buf, format, a, b, c, d, e, f);
                    968:     if (buf[1024] != 0x15) ABORT("GC_err_printf clobbered stack");
                    969:     if (WRITE(GC_stderr, buf, strlen(buf)) < 0) ABORT("write to stderr failed");
                    970: }
                    971:
                    972: void GC_err_puts(s)
1.4       noro      973: GC_CONST char *s;
1.1       noro      974: {
                    975:     if (WRITE(GC_stderr, s, strlen(s)) < 0) ABORT("write to stderr failed");
                    976: }
                    977:
1.4       noro      978: #if defined(LINUX) && !defined(SMALL_CONFIG)
                    979: void GC_err_write(buf, len)
                    980: GC_CONST char *buf;
                    981: size_t len;
                    982: {
                    983:     if (WRITE(GC_stderr, buf, len) < 0) ABORT("write to stderr failed");
                    984: }
                    985: #endif
                    986:
1.1       noro      987: # if defined(__STDC__) || defined(__cplusplus)
                    988:     void GC_default_warn_proc(char *msg, GC_word arg)
                    989: # else
                    990:     void GC_default_warn_proc(msg, arg)
                    991:     char *msg;
                    992:     GC_word arg;
                    993: # endif
                    994: {
                    995:     GC_err_printf1(msg, (unsigned long)arg);
                    996: }
                    997:
                    998: GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
                    999:
                   1000: # if defined(__STDC__) || defined(__cplusplus)
                   1001:     GC_warn_proc GC_set_warn_proc(GC_warn_proc p)
                   1002: # else
                   1003:     GC_warn_proc GC_set_warn_proc(p)
                   1004:     GC_warn_proc p;
                   1005: # endif
                   1006: {
                   1007:     GC_warn_proc result;
                   1008:
                   1009:     LOCK();
                   1010:     result = GC_current_warn_proc;
                   1011:     GC_current_warn_proc = p;
                   1012:     UNLOCK();
                   1013:     return(result);
                   1014: }
                   1015:
1.7       noro     1016: # if defined(__STDC__) || defined(__cplusplus)
                   1017:     GC_word GC_set_free_space_divisor (GC_word value)
                   1018: # else
                   1019:     GC_word GC_set_free_space_divisor (value)
                   1020:     GC_word value;
                   1021: # endif
                   1022: {
                   1023:     GC_word old = GC_free_space_divisor;
                   1024:     GC_free_space_divisor = value;
                   1025:     return old;
                   1026: }
1.1       noro     1027:
                   1028: #ifndef PCR
                   1029: void GC_abort(msg)
1.4       noro     1030: GC_CONST char * msg;
1.1       noro     1031: {
1.4       noro     1032: #   if defined(MSWIN32)
                   1033:       (void) MessageBoxA(NULL, msg, "Fatal error in gc", MB_ICONERROR|MB_OK);
                   1034:       DebugBreak();
                   1035: #   else
                   1036:       GC_err_printf1("%s\n", msg);
                   1037: #   endif
                   1038:     if (GETENV("GC_LOOP_ON_ABORT") != NULL) {
                   1039:            /* In many cases it's easier to debug a running process.    */
                   1040:            /* It's arguably nicer to sleep, but that makes it harder   */
                   1041:            /* to look at the thread if the debugger doesn't know much  */
                   1042:            /* about threads.                                           */
1.6       noro     1043:            for(;;) {}
1.4       noro     1044:     }
                   1045: #   ifdef MSWIN32
                   1046:        DebugBreak();
                   1047: #   else
                   1048:         (void) abort();
                   1049: #   endif
1.1       noro     1050: }
                   1051: #endif
                   1052:
                   1053: void GC_enable()
                   1054: {
1.7       noro     1055:     LOCK();
1.1       noro     1056:     GC_dont_gc--;
1.7       noro     1057:     UNLOCK();
1.1       noro     1058: }
                   1059:
                   1060: void GC_disable()
                   1061: {
1.7       noro     1062:     LOCK();
1.1       noro     1063:     GC_dont_gc++;
1.7       noro     1064:     UNLOCK();
1.1       noro     1065: }
                   1066:
                   1067: #if !defined(NO_DEBUGGING)
                   1068:
                   1069: void GC_dump()
                   1070: {
                   1071:     GC_printf0("***Static roots:\n");
                   1072:     GC_print_static_roots();
                   1073:     GC_printf0("\n***Heap sections:\n");
                   1074:     GC_print_heap_sects();
                   1075:     GC_printf0("\n***Free blocks:\n");
                   1076:     GC_print_hblkfreelist();
                   1077:     GC_printf0("\n***Blocks in use:\n");
                   1078:     GC_print_block_list();
1.7       noro     1079:     GC_printf0("\n***Finalization statistics:\n");
                   1080:     GC_print_finalization_stats();
1.1       noro     1081: }
                   1082:
1.4       noro     1083: #endif /* NO_DEBUGGING */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>