Annotation of OpenXM_contrib/gc/alloc.c, Revision 1.1
1.1 ! maekawa 1: /*
! 2: * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
! 3: * Copyright (c) 1991-1994 by Xerox Corporation. All rights reserved.
! 4: * Copyright (c) 1998 by Silicon Graphics. All rights reserved.
! 5: *
! 6: * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
! 7: * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
! 8: *
! 9: * Permission is hereby granted to use or copy this program
! 10: * for any purpose, provided the above notices are retained on all copies.
! 11: * Permission to modify the code and to distribute modified code is granted,
! 12: * provided the above notices are retained, and a notice that the code was
! 13: * modified is included with the above copyright notice.
! 14: *
! 15: */
! 16:
! 17:
! 18: # include "gc_priv.h"
! 19:
! 20: # include <stdio.h>
! 21: # ifndef MACOS
! 22: # include <signal.h>
! 23: # include <sys/types.h>
! 24: # endif
! 25:
! 26: /*
! 27: * Separate free lists are maintained for different sized objects
! 28: * up to MAXOBJSZ.
! 29: * The call GC_allocobj(i,k) ensures that the freelist for
! 30: * kind k objects of size i points to a non-empty
! 31: * free list. It returns a pointer to the first entry on the free list.
! 32: * In a single-threaded world, GC_allocobj may be called to allocate
! 33: * an object of (small) size i as follows:
! 34: *
! 35: * opp = &(GC_objfreelist[i]);
! 36: * if (*opp == 0) GC_allocobj(i, NORMAL);
! 37: * ptr = *opp;
! 38: * *opp = obj_link(ptr);
! 39: *
! 40: * Note that this is very fast if the free list is non-empty; it should
! 41: * only involve the execution of 4 or 5 simple instructions.
! 42: * All composite objects on freelists are cleared, except for
! 43: * their first word.
! 44: */
! 45:
! 46: /*
! 47: * The allocator uses GC_allochblk to allocate large chunks of objects.
! 48: * These chunks all start on addresses which are multiples of
! 49: * HBLKSZ. Each allocated chunk has an associated header,
! 50: * which can be located quickly based on the address of the chunk.
! 51: * (See headers.c for details.)
! 52: * This makes it possible to check quickly whether an
! 53: * arbitrary address corresponds to an object administered by the
! 54: * allocator.
! 55: */
! 56:
! 57: word GC_non_gc_bytes = 0; /* Number of bytes not intended to be collected */
! 58:
! 59: word GC_gc_no = 0;
! 60:
! 61: #ifndef SMALL_CONFIG
! 62: int GC_incremental = 0; /* By default, stop the world. */
! 63: #endif
! 64:
! 65: int GC_full_freq = 4; /* Every 5th collection is a full */
! 66: /* collection. */
! 67:
! 68: char * GC_copyright[] =
! 69: {"Copyright 1988,1989 Hans-J. Boehm and Alan J. Demers ",
! 70: "Copyright (c) 1991-1995 by Xerox Corporation. All rights reserved. ",
! 71: "Copyright (c) 1996-1998 by Silicon Graphics. All rights reserved. ",
! 72: "THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY",
! 73: " EXPRESSED OR IMPLIED. ANY USE IS AT YOUR OWN RISK.",
! 74: "See source code for details." };
! 75:
! 76: # include "version.h"
! 77:
! 78: /* some more variables */
! 79:
! 80: extern signed_word GC_mem_found; /* Number of reclaimed longwords */
! 81: /* after garbage collection */
! 82:
! 83: GC_bool GC_dont_expand = 0;
! 84:
! 85: word GC_free_space_divisor = 4;
! 86:
! 87: extern GC_bool GC_collection_in_progress();
! 88: /* Collection is in progress, or was abandoned. */
! 89:
! 90: int GC_never_stop_func GC_PROTO((void)) { return(0); }
! 91:
! 92: CLOCK_TYPE GC_start_time; /* Time at which we stopped world. */
! 93: /* used only in GC_timeout_stop_func. */
! 94:
! 95: int GC_n_attempts = 0; /* Number of attempts at finishing */
! 96: /* collection within TIME_LIMIT */
! 97:
! 98: #ifdef SMALL_CONFIG
! 99: # define GC_timeout_stop_func GC_never_stop_func
! 100: #else
! 101: int GC_timeout_stop_func GC_PROTO((void))
! 102: {
! 103: CLOCK_TYPE current_time;
! 104: static unsigned count = 0;
! 105: unsigned long time_diff;
! 106:
! 107: if ((count++ & 3) != 0) return(0);
! 108: GET_TIME(current_time);
! 109: time_diff = MS_TIME_DIFF(current_time,GC_start_time);
! 110: if (time_diff >= TIME_LIMIT) {
! 111: # ifdef PRINTSTATS
! 112: GC_printf0("Abandoning stopped marking after ");
! 113: GC_printf1("%lu msecs", (unsigned long)time_diff);
! 114: GC_printf1("(attempt %d)\n", (unsigned long) GC_n_attempts);
! 115: # endif
! 116: return(1);
! 117: }
! 118: return(0);
! 119: }
! 120: #endif /* !SMALL_CONFIG */
! 121:
! 122: /* Return the minimum number of words that must be allocated between */
! 123: /* collections to amortize the collection cost. */
! 124: static word min_words_allocd()
! 125: {
! 126: # ifdef THREADS
! 127: /* We punt, for now. */
! 128: register signed_word stack_size = 10000;
! 129: # else
! 130: int dummy;
! 131: register signed_word stack_size = (ptr_t)(&dummy) - GC_stackbottom;
! 132: # endif
! 133: register word total_root_size; /* includes double stack size, */
! 134: /* since the stack is expensive */
! 135: /* to scan. */
! 136:
! 137: if (stack_size < 0) stack_size = -stack_size;
! 138: total_root_size = 2 * stack_size + GC_root_size;
! 139: if (GC_incremental) {
! 140: return(BYTES_TO_WORDS(GC_heapsize + total_root_size)
! 141: / (2 * GC_free_space_divisor));
! 142: } else {
! 143: return(BYTES_TO_WORDS(GC_heapsize + total_root_size)
! 144: / GC_free_space_divisor);
! 145: }
! 146: }
! 147:
! 148: /* Return the number of words allocated, adjusted for explicit storage */
! 149: /* management, etc.. This number is used in deciding when to trigger */
! 150: /* collections. */
! 151: word GC_adj_words_allocd()
! 152: {
! 153: register signed_word result;
! 154: register signed_word expl_managed =
! 155: BYTES_TO_WORDS((long)GC_non_gc_bytes
! 156: - (long)GC_non_gc_bytes_at_gc);
! 157:
! 158: /* Don't count what was explicitly freed, or newly allocated for */
! 159: /* explicit management. Note that deallocating an explicitly */
! 160: /* managed object should not alter result, assuming the client */
! 161: /* is playing by the rules. */
! 162: result = (signed_word)GC_words_allocd
! 163: - (signed_word)GC_mem_freed - expl_managed;
! 164: if (result > (signed_word)GC_words_allocd) {
! 165: result = GC_words_allocd;
! 166: /* probably client bug or unfortunate scheduling */
! 167: }
! 168: result += GC_words_finalized;
! 169: /* We count objects enqueued for finalization as though they */
! 170: /* had been reallocated this round. Finalization is user */
! 171: /* visible progress. And if we don't count this, we have */
! 172: /* stability problems for programs that finalize all objects. */
! 173: result += GC_words_wasted;
! 174: /* This doesn't reflect useful work. But if there is lots of */
! 175: /* new fragmentation, the same is probably true of the heap, */
! 176: /* and the collection will be correspondingly cheaper. */
! 177: if (result < (signed_word)(GC_words_allocd >> 3)) {
! 178: /* Always count at least 1/8 of the allocations. We don't want */
! 179: /* to collect too infrequently, since that would inhibit */
! 180: /* coalescing of free storage blocks. */
! 181: /* This also makes us partially robust against client bugs. */
! 182: return(GC_words_allocd >> 3);
! 183: } else {
! 184: return(result);
! 185: }
! 186: }
! 187:
! 188:
! 189: /* Clear up a few frames worth of garbage left at the top of the stack. */
! 190: /* This is used to prevent us from accidentally treating garbade left */
! 191: /* on the stack by other parts of the collector as roots. This */
! 192: /* differs from the code in misc.c, which actually tries to keep the */
! 193: /* stack clear of long-lived, client-generated garbage. */
! 194: void GC_clear_a_few_frames()
! 195: {
! 196: # define NWORDS 64
! 197: word frames[NWORDS];
! 198: register int i;
! 199:
! 200: for (i = 0; i < NWORDS; i++) frames[i] = 0;
! 201: }
! 202:
! 203: /* Have we allocated enough to amortize a collection? */
! 204: GC_bool GC_should_collect()
! 205: {
! 206: return(GC_adj_words_allocd() >= min_words_allocd());
! 207: }
! 208:
! 209: void GC_notify_full_gc()
! 210: {
! 211: if (GC_start_call_back != (void (*)())0) {
! 212: (*GC_start_call_back)();
! 213: }
! 214: }
! 215:
! 216: /*
! 217: * Initiate a garbage collection if appropriate.
! 218: * Choose judiciously
! 219: * between partial, full, and stop-world collections.
! 220: * Assumes lock held, signals disabled.
! 221: */
! 222: void GC_maybe_gc()
! 223: {
! 224: static int n_partial_gcs = 0;
! 225: GC_bool is_full_gc = FALSE;
! 226:
! 227: if (GC_should_collect()) {
! 228: if (!GC_incremental) {
! 229: GC_notify_full_gc();
! 230: GC_gcollect_inner();
! 231: n_partial_gcs = 0;
! 232: return;
! 233: } else if (n_partial_gcs >= GC_full_freq) {
! 234: # ifdef PRINTSTATS
! 235: GC_printf2(
! 236: "***>Full mark for collection %lu after %ld allocd bytes\n",
! 237: (unsigned long) GC_gc_no+1,
! 238: (long)WORDS_TO_BYTES(GC_words_allocd));
! 239: # endif
! 240: GC_promote_black_lists();
! 241: (void)GC_reclaim_all((GC_stop_func)0, TRUE);
! 242: GC_clear_marks();
! 243: n_partial_gcs = 0;
! 244: GC_notify_full_gc();
! 245: is_full_gc = TRUE;
! 246: } else {
! 247: n_partial_gcs++;
! 248: }
! 249: /* We try to mark with the world stopped. */
! 250: /* If we run out of time, this turns into */
! 251: /* incremental marking. */
! 252: GET_TIME(GC_start_time);
! 253: if (GC_stopped_mark(GC_timeout_stop_func)) {
! 254: # ifdef SAVE_CALL_CHAIN
! 255: GC_save_callers(GC_last_stack);
! 256: # endif
! 257: GC_finish_collection();
! 258: } else {
! 259: if (!is_full_gc) {
! 260: /* Count this as the first attempt */
! 261: GC_n_attempts++;
! 262: }
! 263: }
! 264: }
! 265: }
! 266:
! 267:
! 268: /*
! 269: * Stop the world garbage collection. Assumes lock held, signals disabled.
! 270: * If stop_func is not GC_never_stop_func, then abort if stop_func returns TRUE.
! 271: */
! 272: GC_bool GC_try_to_collect_inner(stop_func)
! 273: GC_stop_func stop_func;
! 274: {
! 275: if (GC_incremental && GC_collection_in_progress()) {
! 276: # ifdef PRINTSTATS
! 277: GC_printf0(
! 278: "GC_try_to_collect_inner: finishing collection in progress\n");
! 279: # endif /* PRINTSTATS */
! 280: /* Just finish collection already in progress. */
! 281: while(GC_collection_in_progress()) {
! 282: if (stop_func()) return(FALSE);
! 283: GC_collect_a_little_inner(1);
! 284: }
! 285: }
! 286: # ifdef PRINTSTATS
! 287: GC_printf2(
! 288: "Initiating full world-stop collection %lu after %ld allocd bytes\n",
! 289: (unsigned long) GC_gc_no+1,
! 290: (long)WORDS_TO_BYTES(GC_words_allocd));
! 291: # endif
! 292: GC_promote_black_lists();
! 293: /* Make sure all blocks have been reclaimed, so sweep routines */
! 294: /* don't see cleared mark bits. */
! 295: /* If we're guaranteed to finish, then this is unnecessary. */
! 296: if (stop_func != GC_never_stop_func
! 297: && !GC_reclaim_all(stop_func, FALSE)) {
! 298: /* Aborted. So far everything is still consistent. */
! 299: return(FALSE);
! 300: }
! 301: GC_invalidate_mark_state(); /* Flush mark stack. */
! 302: GC_clear_marks();
! 303: # ifdef SAVE_CALL_CHAIN
! 304: GC_save_callers(GC_last_stack);
! 305: # endif
! 306: if (!GC_stopped_mark(stop_func)) {
! 307: if (!GC_incremental) {
! 308: /* We're partially done and have no way to complete or use */
! 309: /* current work. Reestablish invariants as cheaply as */
! 310: /* possible. */
! 311: GC_invalidate_mark_state();
! 312: GC_unpromote_black_lists();
! 313: } /* else we claim the world is already still consistent. We'll */
! 314: /* finish incrementally. */
! 315: return(FALSE);
! 316: }
! 317: GC_finish_collection();
! 318: return(TRUE);
! 319: }
! 320:
! 321:
! 322:
! 323: /*
! 324: * Perform n units of garbage collection work. A unit is intended to touch
! 325: * roughly GC_RATE pages. Every once in a while, we do more than that.
! 326: * This needa to be a fairly large number with our current incremental
! 327: * GC strategy, since otherwise we allocate too much during GC, and the
! 328: * cleanup gets expensive.
! 329: */
! 330: # define GC_RATE 10
! 331: # define MAX_PRIOR_ATTEMPTS 1
! 332: /* Maximum number of prior attempts at world stop marking */
! 333: /* A value of 1 means that we finish the seconf time, no matter */
! 334: /* how long it takes. Doesn't count the initial root scan */
! 335: /* for a full GC. */
! 336:
! 337: int GC_deficit = 0; /* The number of extra calls to GC_mark_some */
! 338: /* that we have made. */
! 339:
! 340: void GC_collect_a_little_inner(n)
! 341: int n;
! 342: {
! 343: register int i;
! 344:
! 345: if (GC_incremental && GC_collection_in_progress()) {
! 346: for (i = GC_deficit; i < GC_RATE*n; i++) {
! 347: if (GC_mark_some((ptr_t)0)) {
! 348: /* Need to finish a collection */
! 349: # ifdef SAVE_CALL_CHAIN
! 350: GC_save_callers(GC_last_stack);
! 351: # endif
! 352: if (GC_n_attempts < MAX_PRIOR_ATTEMPTS) {
! 353: GET_TIME(GC_start_time);
! 354: if (!GC_stopped_mark(GC_timeout_stop_func)) {
! 355: GC_n_attempts++;
! 356: break;
! 357: }
! 358: } else {
! 359: (void)GC_stopped_mark(GC_never_stop_func);
! 360: }
! 361: GC_finish_collection();
! 362: break;
! 363: }
! 364: }
! 365: if (GC_deficit > 0) GC_deficit -= GC_RATE*n;
! 366: if (GC_deficit < 0) GC_deficit = 0;
! 367: } else {
! 368: GC_maybe_gc();
! 369: }
! 370: }
! 371:
! 372: int GC_collect_a_little GC_PROTO(())
! 373: {
! 374: int result;
! 375: DCL_LOCK_STATE;
! 376:
! 377: DISABLE_SIGNALS();
! 378: LOCK();
! 379: GC_collect_a_little_inner(1);
! 380: result = (int)GC_collection_in_progress();
! 381: UNLOCK();
! 382: ENABLE_SIGNALS();
! 383: return(result);
! 384: }
! 385:
! 386: /*
! 387: * Assumes lock is held, signals are disabled.
! 388: * We stop the world.
! 389: * If stop_func() ever returns TRUE, we may fail and return FALSE.
! 390: * Increment GC_gc_no if we succeed.
! 391: */
! 392: GC_bool GC_stopped_mark(stop_func)
! 393: GC_stop_func stop_func;
! 394: {
! 395: register int i;
! 396: int dummy;
! 397: # ifdef PRINTSTATS
! 398: CLOCK_TYPE start_time, current_time;
! 399: # endif
! 400:
! 401: STOP_WORLD();
! 402: # ifdef PRINTSTATS
! 403: GET_TIME(start_time);
! 404: GC_printf1("--> Marking for collection %lu ",
! 405: (unsigned long) GC_gc_no + 1);
! 406: GC_printf2("after %lu allocd bytes + %lu wasted bytes\n",
! 407: (unsigned long) WORDS_TO_BYTES(GC_words_allocd),
! 408: (unsigned long) WORDS_TO_BYTES(GC_words_wasted));
! 409: # endif
! 410:
! 411: /* Mark from all roots. */
! 412: /* Minimize junk left in my registers and on the stack */
! 413: GC_clear_a_few_frames();
! 414: GC_noop(0,0,0,0,0,0);
! 415: GC_initiate_gc();
! 416: for(i = 0;;i++) {
! 417: if ((*stop_func)()) {
! 418: # ifdef PRINTSTATS
! 419: GC_printf0("Abandoned stopped marking after ");
! 420: GC_printf1("%lu iterations\n",
! 421: (unsigned long)i);
! 422: # endif
! 423: GC_deficit = i; /* Give the mutator a chance. */
! 424: START_WORLD();
! 425: return(FALSE);
! 426: }
! 427: if (GC_mark_some((ptr_t)(&dummy))) break;
! 428: }
! 429:
! 430: GC_gc_no++;
! 431: # ifdef PRINTSTATS
! 432: GC_printf2("Collection %lu reclaimed %ld bytes",
! 433: (unsigned long) GC_gc_no - 1,
! 434: (long)WORDS_TO_BYTES(GC_mem_found));
! 435: GC_printf1(" ---> heapsize = %lu bytes\n",
! 436: (unsigned long) GC_heapsize);
! 437: /* Printf arguments may be pushed in funny places. Clear the */
! 438: /* space. */
! 439: GC_printf0("");
! 440: # endif
! 441:
! 442: /* Check all debugged objects for consistency */
! 443: if (GC_debugging_started) {
! 444: (*GC_check_heap)();
! 445: }
! 446:
! 447: # ifdef PRINTTIMES
! 448: GET_TIME(current_time);
! 449: GC_printf1("World-stopped marking took %lu msecs\n",
! 450: MS_TIME_DIFF(current_time,start_time));
! 451: # endif
! 452: START_WORLD();
! 453: return(TRUE);
! 454: }
! 455:
! 456:
! 457: /* Finish up a collection. Assumes lock is held, signals are disabled, */
! 458: /* but the world is otherwise running. */
! 459: void GC_finish_collection()
! 460: {
! 461: # ifdef PRINTTIMES
! 462: CLOCK_TYPE start_time;
! 463: CLOCK_TYPE finalize_time;
! 464: CLOCK_TYPE done_time;
! 465:
! 466: GET_TIME(start_time);
! 467: finalize_time = start_time;
! 468: # endif
! 469:
! 470: # ifdef GATHERSTATS
! 471: GC_mem_found = 0;
! 472: # endif
! 473: # ifdef FIND_LEAK
! 474: /* Mark all objects on the free list. All objects should be */
! 475: /* marked when we're done. */
! 476: {
! 477: register word size; /* current object size */
! 478: register ptr_t p; /* pointer to current object */
! 479: register struct hblk * h; /* pointer to block containing *p */
! 480: register hdr * hhdr;
! 481: register int word_no; /* "index" of *p in *q */
! 482: int kind;
! 483:
! 484: for (kind = 0; kind < GC_n_kinds; kind++) {
! 485: for (size = 1; size <= MAXOBJSZ; size++) {
! 486: for (p= GC_obj_kinds[kind].ok_freelist[size];
! 487: p != 0; p=obj_link(p)){
! 488: h = HBLKPTR(p);
! 489: hhdr = HDR(h);
! 490: word_no = (((word *)p) - ((word *)h));
! 491: set_mark_bit_from_hdr(hhdr, word_no);
! 492: }
! 493: }
! 494: }
! 495: }
! 496: /* Check that everything is marked */
! 497: GC_start_reclaim(TRUE);
! 498: # else
! 499:
! 500: GC_finalize();
! 501: # ifdef STUBBORN_ALLOC
! 502: GC_clean_changing_list();
! 503: # endif
! 504:
! 505: # ifdef PRINTTIMES
! 506: GET_TIME(finalize_time);
! 507: # endif
! 508:
! 509: /* Clear free list mark bits, in case they got accidentally marked */
! 510: /* Note: HBLKPTR(p) == pointer to head of block containing *p */
! 511: /* Also subtract memory remaining from GC_mem_found count. */
! 512: /* Note that composite objects on free list are cleared. */
! 513: /* Thus accidentally marking a free list is not a problem; only */
! 514: /* objects on the list itself will be marked, and that's fixed here. */
! 515: {
! 516: register word size; /* current object size */
! 517: register ptr_t p; /* pointer to current object */
! 518: register struct hblk * h; /* pointer to block containing *p */
! 519: register hdr * hhdr;
! 520: register int word_no; /* "index" of *p in *q */
! 521: int kind;
! 522:
! 523: for (kind = 0; kind < GC_n_kinds; kind++) {
! 524: for (size = 1; size <= MAXOBJSZ; size++) {
! 525: for (p= GC_obj_kinds[kind].ok_freelist[size];
! 526: p != 0; p=obj_link(p)){
! 527: h = HBLKPTR(p);
! 528: hhdr = HDR(h);
! 529: word_no = (((word *)p) - ((word *)h));
! 530: clear_mark_bit_from_hdr(hhdr, word_no);
! 531: # ifdef GATHERSTATS
! 532: GC_mem_found -= size;
! 533: # endif
! 534: }
! 535: }
! 536: }
! 537: }
! 538:
! 539:
! 540: # ifdef PRINTSTATS
! 541: GC_printf1("Bytes recovered before sweep - f.l. count = %ld\n",
! 542: (long)WORDS_TO_BYTES(GC_mem_found));
! 543: # endif
! 544:
! 545: /* Reconstruct free lists to contain everything not marked */
! 546: GC_start_reclaim(FALSE);
! 547:
! 548: # endif /* !FIND_LEAK */
! 549:
! 550: # ifdef PRINTSTATS
! 551: GC_printf2(
! 552: "Immediately reclaimed %ld bytes in heap of size %lu bytes\n",
! 553: (long)WORDS_TO_BYTES(GC_mem_found),
! 554: (unsigned long)GC_heapsize);
! 555: GC_printf2("%lu (atomic) + %lu (composite) collectable bytes in use\n",
! 556: (unsigned long)WORDS_TO_BYTES(GC_atomic_in_use),
! 557: (unsigned long)WORDS_TO_BYTES(GC_composite_in_use));
! 558: # endif
! 559:
! 560: GC_n_attempts = 0;
! 561: /* Reset or increment counters for next cycle */
! 562: GC_words_allocd_before_gc += GC_words_allocd;
! 563: GC_non_gc_bytes_at_gc = GC_non_gc_bytes;
! 564: GC_words_allocd = 0;
! 565: GC_words_wasted = 0;
! 566: GC_mem_freed = 0;
! 567:
! 568: # ifdef PRINTTIMES
! 569: GET_TIME(done_time);
! 570: GC_printf2("Finalize + initiate sweep took %lu + %lu msecs\n",
! 571: MS_TIME_DIFF(finalize_time,start_time),
! 572: MS_TIME_DIFF(done_time,finalize_time));
! 573: # endif
! 574: }
! 575:
! 576: /* Externally callable routine to invoke full, stop-world collection */
! 577: # if defined(__STDC__) || defined(__cplusplus)
! 578: int GC_try_to_collect(GC_stop_func stop_func)
! 579: # else
! 580: int GC_try_to_collect(stop_func)
! 581: GC_stop_func stop_func;
! 582: # endif
! 583: {
! 584: int result;
! 585: DCL_LOCK_STATE;
! 586:
! 587: GC_INVOKE_FINALIZERS();
! 588: DISABLE_SIGNALS();
! 589: LOCK();
! 590: ENTER_GC();
! 591: if (!GC_is_initialized) GC_init_inner();
! 592: /* Minimize junk left in my registers */
! 593: GC_noop(0,0,0,0,0,0);
! 594: result = (int)GC_try_to_collect_inner(stop_func);
! 595: EXIT_GC();
! 596: UNLOCK();
! 597: ENABLE_SIGNALS();
! 598: if(result) GC_INVOKE_FINALIZERS();
! 599: return(result);
! 600: }
! 601:
! 602: void GC_gcollect GC_PROTO(())
! 603: {
! 604: GC_notify_full_gc();
! 605: (void)GC_try_to_collect(GC_never_stop_func);
! 606: }
! 607:
! 608: word GC_n_heap_sects = 0; /* Number of sections currently in heap. */
! 609:
! 610: /*
! 611: * Use the chunk of memory starting at p of syze bytes as part of the heap.
! 612: * Assumes p is HBLKSIZE aligned, and bytes is a multiple of HBLKSIZE.
! 613: */
! 614: void GC_add_to_heap(p, bytes)
! 615: struct hblk *p;
! 616: word bytes;
! 617: {
! 618: word words;
! 619:
! 620: if (GC_n_heap_sects >= MAX_HEAP_SECTS) {
! 621: ABORT("Too many heap sections: Increase MAXHINCR or MAX_HEAP_SECTS");
! 622: }
! 623: if (!GC_install_header(p)) {
! 624: /* This is extremely unlikely. Can't add it. This will */
! 625: /* almost certainly result in a 0 return from the allocator, */
! 626: /* which is entirely appropriate. */
! 627: return;
! 628: }
! 629: GC_heap_sects[GC_n_heap_sects].hs_start = (ptr_t)p;
! 630: GC_heap_sects[GC_n_heap_sects].hs_bytes = bytes;
! 631: GC_n_heap_sects++;
! 632: words = BYTES_TO_WORDS(bytes - HDR_BYTES);
! 633: HDR(p) -> hb_sz = words;
! 634: GC_freehblk(p);
! 635: GC_heapsize += bytes;
! 636: if ((ptr_t)p <= GC_least_plausible_heap_addr
! 637: || GC_least_plausible_heap_addr == 0) {
! 638: GC_least_plausible_heap_addr = (ptr_t)p - sizeof(word);
! 639: /* Making it a little smaller than necessary prevents */
! 640: /* us from getting a false hit from the variable */
! 641: /* itself. There's some unintentional reflection */
! 642: /* here. */
! 643: }
! 644: if ((ptr_t)p + bytes >= GC_greatest_plausible_heap_addr) {
! 645: GC_greatest_plausible_heap_addr = (ptr_t)p + bytes;
! 646: }
! 647: }
! 648:
! 649: #ifdef PRESERVE_LAST
! 650:
! 651: GC_bool GC_protect_last_block = FALSE;
! 652:
! 653: GC_bool GC_in_last_heap_sect(p)
! 654: ptr_t p;
! 655: {
! 656: struct HeapSect * last_heap_sect;
! 657: ptr_t start;
! 658: ptr_t end;
! 659:
! 660: if (!GC_protect_last_block) return FALSE;
! 661: last_heap_sect = &(GC_heap_sects[GC_n_heap_sects-1]);
! 662: start = last_heap_sect -> hs_start;
! 663: if (p < start) return FALSE;
! 664: end = start + last_heap_sect -> hs_bytes;
! 665: if (p >= end) return FALSE;
! 666: return TRUE;
! 667: }
! 668: #endif
! 669:
! 670: # if !defined(NO_DEBUGGING)
! 671: void GC_print_heap_sects()
! 672: {
! 673: register unsigned i;
! 674:
! 675: GC_printf1("Total heap size: %lu\n", (unsigned long) GC_heapsize);
! 676: for (i = 0; i < GC_n_heap_sects; i++) {
! 677: unsigned long start = (unsigned long) GC_heap_sects[i].hs_start;
! 678: unsigned long len = (unsigned long) GC_heap_sects[i].hs_bytes;
! 679: struct hblk *h;
! 680: unsigned nbl = 0;
! 681:
! 682: GC_printf3("Section %ld from 0x%lx to 0x%lx ", (unsigned long)i,
! 683: start, (unsigned long)(start + len));
! 684: for (h = (struct hblk *)start; h < (struct hblk *)(start + len); h++) {
! 685: if (GC_is_black_listed(h, HBLKSIZE)) nbl++;
! 686: }
! 687: GC_printf2("%lu/%lu blacklisted\n", (unsigned long)nbl,
! 688: (unsigned long)(len/HBLKSIZE));
! 689: }
! 690: }
! 691: # endif
! 692:
! 693: ptr_t GC_least_plausible_heap_addr = (ptr_t)ONES;
! 694: ptr_t GC_greatest_plausible_heap_addr = 0;
! 695:
! 696: ptr_t GC_max(x,y)
! 697: ptr_t x, y;
! 698: {
! 699: return(x > y? x : y);
! 700: }
! 701:
! 702: ptr_t GC_min(x,y)
! 703: ptr_t x, y;
! 704: {
! 705: return(x < y? x : y);
! 706: }
! 707:
! 708: # if defined(__STDC__) || defined(__cplusplus)
! 709: void GC_set_max_heap_size(GC_word n)
! 710: # else
! 711: void GC_set_max_heap_size(n)
! 712: GC_word n;
! 713: # endif
! 714: {
! 715: GC_max_heapsize = n;
! 716: }
! 717:
! 718: GC_word GC_max_retries = 0;
! 719:
! 720: /*
! 721: * this explicitly increases the size of the heap. It is used
! 722: * internally, but may also be invoked from GC_expand_hp by the user.
! 723: * The argument is in units of HBLKSIZE.
! 724: * Tiny values of n are rounded up.
! 725: * Returns FALSE on failure.
! 726: */
! 727: GC_bool GC_expand_hp_inner(n)
! 728: word n;
! 729: {
! 730: word bytes;
! 731: struct hblk * space;
! 732: word expansion_slop; /* Number of bytes by which we expect the */
! 733: /* heap to expand soon. */
! 734:
! 735: if (n < MINHINCR) n = MINHINCR;
! 736: bytes = n * HBLKSIZE;
! 737: /* Make sure bytes is a multiple of GC_page_size */
! 738: {
! 739: word mask = GC_page_size - 1;
! 740: bytes += mask;
! 741: bytes &= ~mask;
! 742: }
! 743:
! 744: if (GC_max_heapsize != 0 && GC_heapsize + bytes > GC_max_heapsize) {
! 745: /* Exceeded self-imposed limit */
! 746: return(FALSE);
! 747: }
! 748: space = GET_MEM(bytes);
! 749: if( space == 0 ) {
! 750: return(FALSE);
! 751: }
! 752: # ifdef PRINTSTATS
! 753: GC_printf2("Increasing heap size by %lu after %lu allocated bytes\n",
! 754: (unsigned long)bytes,
! 755: (unsigned long)WORDS_TO_BYTES(GC_words_allocd));
! 756: # ifdef UNDEFINED
! 757: GC_printf1("Root size = %lu\n", GC_root_size);
! 758: GC_print_block_list(); GC_print_hblkfreelist();
! 759: GC_printf0("\n");
! 760: # endif
! 761: # endif
! 762: expansion_slop = 8 * WORDS_TO_BYTES(min_words_allocd());
! 763: if (5 * HBLKSIZE * MAXHINCR > expansion_slop) {
! 764: expansion_slop = 5 * HBLKSIZE * MAXHINCR;
! 765: }
! 766: if (GC_last_heap_addr == 0 && !((word)space & SIGNB)
! 767: || GC_last_heap_addr != 0 && GC_last_heap_addr < (ptr_t)space) {
! 768: /* Assume the heap is growing up */
! 769: GC_greatest_plausible_heap_addr =
! 770: GC_max(GC_greatest_plausible_heap_addr,
! 771: (ptr_t)space + bytes + expansion_slop);
! 772: } else {
! 773: /* Heap is growing down */
! 774: GC_least_plausible_heap_addr =
! 775: GC_min(GC_least_plausible_heap_addr,
! 776: (ptr_t)space - expansion_slop);
! 777: }
! 778: GC_prev_heap_addr = GC_last_heap_addr;
! 779: GC_last_heap_addr = (ptr_t)space;
! 780: GC_add_to_heap(space, bytes);
! 781: return(TRUE);
! 782: }
! 783:
! 784: /* Really returns a bool, but it's externally visible, so that's clumsy. */
! 785: /* Arguments is in bytes. */
! 786: # if defined(__STDC__) || defined(__cplusplus)
! 787: int GC_expand_hp(size_t bytes)
! 788: # else
! 789: int GC_expand_hp(bytes)
! 790: size_t bytes;
! 791: # endif
! 792: {
! 793: int result;
! 794: DCL_LOCK_STATE;
! 795:
! 796: DISABLE_SIGNALS();
! 797: LOCK();
! 798: if (!GC_is_initialized) GC_init_inner();
! 799: result = (int)GC_expand_hp_inner(divHBLKSZ((word)bytes));
! 800: # ifdef PRESERVE_LAST
! 801: if (result) GC_protect_last_block = FALSE;
! 802: # endif
! 803: UNLOCK();
! 804: ENABLE_SIGNALS();
! 805: return(result);
! 806: }
! 807:
! 808: unsigned GC_fail_count = 0;
! 809: /* How many consecutive GC/expansion failures? */
! 810: /* Reset by GC_allochblk. */
! 811:
! 812: GC_bool GC_collect_or_expand(needed_blocks, ignore_off_page)
! 813: word needed_blocks;
! 814: GC_bool ignore_off_page;
! 815: {
! 816:
! 817: if (!GC_incremental && !GC_dont_gc && GC_should_collect()) {
! 818: GC_notify_full_gc();
! 819: GC_gcollect_inner();
! 820: } else {
! 821: word blocks_to_get = GC_heapsize/(HBLKSIZE*GC_free_space_divisor)
! 822: + needed_blocks;
! 823:
! 824: if (blocks_to_get > MAXHINCR) {
! 825: word slop;
! 826:
! 827: if (ignore_off_page) {
! 828: slop = 4;
! 829: } else {
! 830: slop = 2*divHBLKSZ(BL_LIMIT);
! 831: if (slop > needed_blocks) slop = needed_blocks;
! 832: }
! 833: if (needed_blocks + slop > MAXHINCR) {
! 834: blocks_to_get = needed_blocks + slop;
! 835: } else {
! 836: blocks_to_get = MAXHINCR;
! 837: }
! 838: }
! 839: if (!GC_expand_hp_inner(blocks_to_get)
! 840: && !GC_expand_hp_inner(needed_blocks)) {
! 841: if (GC_fail_count++ < GC_max_retries) {
! 842: WARN("Out of Memory! Trying to continue ...\n", 0);
! 843: GC_notify_full_gc();
! 844: GC_gcollect_inner();
! 845: } else {
! 846: WARN("Out of Memory! Returning NIL!\n", 0);
! 847: return(FALSE);
! 848: }
! 849: } else {
! 850: # ifdef PRINTSTATS
! 851: if (GC_fail_count) {
! 852: GC_printf0("Memory available again ...\n");
! 853: }
! 854: # endif
! 855: # ifdef PRESERVE_LAST
! 856: if (needed_blocks > 1) GC_protect_last_block = TRUE;
! 857: /* We were forced to expand the heap as the result */
! 858: /* of a large block allocation. Avoid breaking up */
! 859: /* new block into small pieces. */
! 860: # endif
! 861: }
! 862: }
! 863: return(TRUE);
! 864: }
! 865:
! 866: /*
! 867: * Make sure the object free list for sz is not empty.
! 868: * Return a pointer to the first object on the free list.
! 869: * The object MUST BE REMOVED FROM THE FREE LIST BY THE CALLER.
! 870: * Assumes we hold the allocator lock and signals are disabled.
! 871: *
! 872: */
! 873: ptr_t GC_allocobj(sz, kind)
! 874: word sz;
! 875: int kind;
! 876: {
! 877: register ptr_t * flh = &(GC_obj_kinds[kind].ok_freelist[sz]);
! 878:
! 879: if (sz == 0) return(0);
! 880:
! 881: while (*flh == 0) {
! 882: ENTER_GC();
! 883: /* Do our share of marking work */
! 884: if(GC_incremental && !GC_dont_gc) GC_collect_a_little_inner(1);
! 885: /* Sweep blocks for objects of this size */
! 886: GC_continue_reclaim(sz, kind);
! 887: EXIT_GC();
! 888: if (*flh == 0) {
! 889: GC_new_hblk(sz, kind);
! 890: }
! 891: if (*flh == 0) {
! 892: ENTER_GC();
! 893: if (!GC_collect_or_expand((word)1,FALSE)) {
! 894: EXIT_GC();
! 895: return(0);
! 896: }
! 897: EXIT_GC();
! 898: }
! 899: }
! 900:
! 901: return(*flh);
! 902: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>