[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.10

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

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