Annotation of OpenXM_contrib/gc/allchblk.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: /* Boehm, August 9, 1995 5:08 pm PDT */
! 16:
! 17: #define DEBUG
! 18: #undef DEBUG
! 19: #include <stdio.h>
! 20: #include "gc_priv.h"
! 21:
! 22:
! 23: /*
! 24: * allocate/free routines for heap blocks
! 25: * Note that everything called from outside the garbage collector
! 26: * should be prepared to abort at any point as the result of a signal.
! 27: */
! 28:
! 29: /*
! 30: * Free heap blocks are kept on a list sorted by address.
! 31: * The hb_hdr.hbh_sz field of a free heap block contains the length
! 32: * (in bytes) of the entire block.
! 33: * Neighbors are coalesced.
! 34: */
! 35:
! 36: # define MAX_BLACK_LIST_ALLOC (2*HBLKSIZE)
! 37: /* largest block we will allocate starting on a black */
! 38: /* listed block. Must be >= HBLKSIZE. */
! 39:
! 40: struct hblk * GC_hblkfreelist = 0;
! 41:
! 42: struct hblk *GC_savhbp = (struct hblk *)0; /* heap block preceding next */
! 43: /* block to be examined by */
! 44: /* GC_allochblk. */
! 45:
! 46: # if !defined(NO_DEBUGGING)
! 47: void GC_print_hblkfreelist()
! 48: {
! 49: struct hblk * h = GC_hblkfreelist;
! 50: word total_free = 0;
! 51: hdr * hhdr = HDR(h);
! 52: word sz;
! 53:
! 54: while (h != 0) {
! 55: sz = hhdr -> hb_sz;
! 56: GC_printf2("0x%lx size %lu ", (unsigned long)h, (unsigned long)sz);
! 57: total_free += sz;
! 58: if (GC_is_black_listed(h, HBLKSIZE) != 0) {
! 59: GC_printf0("start black listed\n");
! 60: } else if (GC_is_black_listed(h, hhdr -> hb_sz) != 0) {
! 61: GC_printf0("partially black listed\n");
! 62: } else {
! 63: GC_printf0("not black listed\n");
! 64: }
! 65: h = hhdr -> hb_next;
! 66: hhdr = HDR(h);
! 67: }
! 68: GC_printf1("Total of %lu bytes on free list\n", (unsigned long)total_free);
! 69: }
! 70:
! 71: # endif /* NO_DEBUGGING */
! 72:
! 73: /* Initialize hdr for a block containing the indicated size and */
! 74: /* kind of objects. */
! 75: /* Return FALSE on failure. */
! 76: static GC_bool setup_header(hhdr, sz, kind, flags)
! 77: register hdr * hhdr;
! 78: word sz; /* object size in words */
! 79: int kind;
! 80: unsigned char flags;
! 81: {
! 82: register word descr;
! 83:
! 84: /* Add description of valid object pointers */
! 85: if (!GC_add_map_entry(sz)) return(FALSE);
! 86: hhdr -> hb_map = GC_obj_map[sz > MAXOBJSZ? 0 : sz];
! 87:
! 88: /* Set size, kind and mark proc fields */
! 89: hhdr -> hb_sz = sz;
! 90: hhdr -> hb_obj_kind = kind;
! 91: hhdr -> hb_flags = flags;
! 92: descr = GC_obj_kinds[kind].ok_descriptor;
! 93: if (GC_obj_kinds[kind].ok_relocate_descr) descr += WORDS_TO_BYTES(sz);
! 94: hhdr -> hb_descr = descr;
! 95:
! 96: /* Clear mark bits */
! 97: GC_clear_hdr_marks(hhdr);
! 98:
! 99: hhdr -> hb_last_reclaimed = (unsigned short)GC_gc_no;
! 100: return(TRUE);
! 101: }
! 102:
! 103: #ifdef EXACT_FIRST
! 104: # define LAST_TRIP 2
! 105: #else
! 106: # define LAST_TRIP 1
! 107: #endif
! 108:
! 109: word GC_max_hblk_size = HBLKSIZE;
! 110:
! 111: /*
! 112: * Allocate (and return pointer to) a heap block
! 113: * for objects of size sz words.
! 114: *
! 115: * NOTE: We set obj_map field in header correctly.
! 116: * Caller is resposnsible for building an object freelist in block.
! 117: *
! 118: * We clear the block if it is destined for large objects, and if
! 119: * kind requires that newly allocated objects be cleared.
! 120: */
! 121: struct hblk *
! 122: GC_allochblk(sz, kind, flags)
! 123: word sz;
! 124: int kind;
! 125: unsigned char flags; /* IGNORE_OFF_PAGE or 0 */
! 126: {
! 127: register struct hblk *thishbp;
! 128: register hdr * thishdr; /* Header corr. to thishbp */
! 129: register struct hblk *hbp;
! 130: register hdr * hhdr; /* Header corr. to hbp */
! 131: struct hblk *prevhbp;
! 132: register hdr * phdr; /* Header corr. to prevhbp */
! 133: signed_word size_needed; /* number of bytes in requested objects */
! 134: signed_word size_avail; /* bytes available in this block */
! 135: int trip_count = 0;
! 136:
! 137: size_needed = HBLKSIZE * OBJ_SZ_TO_BLOCKS(sz);
! 138: if ((word)size_needed > GC_max_hblk_size)
! 139: GC_max_hblk_size = size_needed;
! 140:
! 141: /* search for a big enough block in free list */
! 142: hbp = GC_savhbp;
! 143: hhdr = HDR(hbp);
! 144: for(;;) {
! 145:
! 146: prevhbp = hbp;
! 147: phdr = hhdr;
! 148: hbp = (prevhbp == 0? GC_hblkfreelist : phdr->hb_next);
! 149: hhdr = HDR(hbp);
! 150:
! 151: if( prevhbp == GC_savhbp) {
! 152: if (trip_count == LAST_TRIP) return(0);
! 153: ++trip_count;
! 154: }
! 155:
! 156: if( hbp == 0 ) continue;
! 157:
! 158: size_avail = hhdr->hb_sz;
! 159: # ifdef EXACT_FIRST
! 160: if (trip_count <= 1 && size_avail != size_needed) continue;
! 161: # endif
! 162: if (size_avail < size_needed) continue;
! 163: # ifdef PRESERVE_LAST
! 164: if (size_avail != size_needed
! 165: && !GC_incremental
! 166: && (word)size_needed <= GC_max_hblk_size/2
! 167: && GC_in_last_heap_sect((ptr_t)hbp)
! 168: && GC_should_collect()) {
! 169: continue;
! 170: }
! 171: # endif
! 172: /* If the next heap block is obviously better, go on. */
! 173: /* This prevents us from disassembling a single large block */
! 174: /* to get tiny blocks. */
! 175: {
! 176: signed_word next_size;
! 177:
! 178: thishbp = hhdr -> hb_next;
! 179: if (thishbp == 0) thishbp = GC_hblkfreelist;
! 180: thishdr = HDR(thishbp);
! 181: next_size = (signed_word)(thishdr -> hb_sz);
! 182: if (next_size < size_avail
! 183: && next_size >= size_needed
! 184: && !GC_is_black_listed(thishbp, (word)size_needed)) {
! 185: continue;
! 186: }
! 187: }
! 188: if ( !IS_UNCOLLECTABLE(kind) &&
! 189: (kind != PTRFREE || size_needed > MAX_BLACK_LIST_ALLOC)) {
! 190: struct hblk * lasthbp = hbp;
! 191: ptr_t search_end = (ptr_t)hbp + size_avail - size_needed;
! 192: signed_word orig_avail = size_avail;
! 193: signed_word eff_size_needed = ((flags & IGNORE_OFF_PAGE)?
! 194: HBLKSIZE
! 195: : size_needed);
! 196:
! 197:
! 198: while ((ptr_t)lasthbp <= search_end
! 199: && (thishbp = GC_is_black_listed(lasthbp,
! 200: (word)eff_size_needed))) {
! 201: lasthbp = thishbp;
! 202: }
! 203: size_avail -= (ptr_t)lasthbp - (ptr_t)hbp;
! 204: thishbp = lasthbp;
! 205: if (size_avail >= size_needed) {
! 206: if (thishbp != hbp && GC_install_header(thishbp)) {
! 207: /* Split the block at thishbp */
! 208: thishdr = HDR(thishbp);
! 209: /* GC_invalidate_map not needed, since we will */
! 210: /* allocate this block. */
! 211: thishdr -> hb_next = hhdr -> hb_next;
! 212: thishdr -> hb_sz = size_avail;
! 213: hhdr -> hb_sz = (ptr_t)thishbp - (ptr_t)hbp;
! 214: hhdr -> hb_next = thishbp;
! 215: /* Advance to thishbp */
! 216: prevhbp = hbp;
! 217: phdr = hhdr;
! 218: hbp = thishbp;
! 219: hhdr = thishdr;
! 220: }
! 221: } else if (size_needed > (signed_word)BL_LIMIT
! 222: && orig_avail - size_needed
! 223: > (signed_word)BL_LIMIT) {
! 224: /* Punt, since anything else risks unreasonable heap growth. */
! 225: WARN("Needed to allocate blacklisted block at 0x%lx\n",
! 226: (word)hbp);
! 227: thishbp = hbp;
! 228: size_avail = orig_avail;
! 229: } else if (size_avail == 0
! 230: && size_needed == HBLKSIZE
! 231: && prevhbp != 0) {
! 232: # ifndef FIND_LEAK
! 233: static unsigned count = 0;
! 234:
! 235: /* The block is completely blacklisted. We need */
! 236: /* to drop some such blocks, since otherwise we spend */
! 237: /* all our time traversing them if pointerfree */
! 238: /* blocks are unpopular. */
! 239: /* A dropped block will be reconsidered at next GC. */
! 240: if ((++count & 3) == 0) {
! 241: /* Allocate and drop the block in small chunks, to */
! 242: /* maximize the chance that we will recover some */
! 243: /* later. */
! 244: struct hblk * limit = hbp + (hhdr->hb_sz/HBLKSIZE);
! 245: struct hblk * h;
! 246:
! 247: GC_words_wasted += hhdr->hb_sz;
! 248: phdr -> hb_next = hhdr -> hb_next;
! 249: for (h = hbp; h < limit; h++) {
! 250: if (h == hbp || GC_install_header(h)) {
! 251: hhdr = HDR(h);
! 252: (void) setup_header(
! 253: hhdr,
! 254: BYTES_TO_WORDS(HBLKSIZE - HDR_BYTES),
! 255: PTRFREE, 0); /* Cant fail */
! 256: if (GC_debugging_started) {
! 257: BZERO(hbp + HDR_BYTES, HBLKSIZE - HDR_BYTES);
! 258: }
! 259: }
! 260: }
! 261: /* Restore hbp to point at free block */
! 262: if (GC_savhbp == hbp) GC_savhbp = prevhbp;
! 263: hbp = prevhbp;
! 264: hhdr = phdr;
! 265: if (hbp == GC_savhbp) --trip_count;
! 266: }
! 267: # endif
! 268: }
! 269: }
! 270: if( size_avail >= size_needed ) {
! 271: /* found a big enough block */
! 272: /* let thishbp --> the block */
! 273: /* set prevhbp, hbp to bracket it */
! 274: thishbp = hbp;
! 275: thishdr = hhdr;
! 276: if( size_avail == size_needed ) {
! 277: hbp = hhdr->hb_next;
! 278: hhdr = HDR(hbp);
! 279: } else {
! 280: hbp = (struct hblk *)
! 281: (((word)thishbp) + size_needed);
! 282: if (!GC_install_header(hbp)) {
! 283: hbp = thishbp;
! 284: continue;
! 285: }
! 286: hhdr = HDR(hbp);
! 287: GC_invalidate_map(hhdr);
! 288: hhdr->hb_next = thishdr->hb_next;
! 289: hhdr->hb_sz = size_avail - size_needed;
! 290: }
! 291: /* remove *thishbp from hblk freelist */
! 292: if( prevhbp == 0 ) {
! 293: GC_hblkfreelist = hbp;
! 294: } else {
! 295: phdr->hb_next = hbp;
! 296: }
! 297: /* save current list search position */
! 298: GC_savhbp = hbp;
! 299: break;
! 300: }
! 301: }
! 302:
! 303: /* Notify virtual dirty bit implementation that we are about to write. */
! 304: GC_write_hint(thishbp);
! 305: /* This should deal better with large blocks. */
! 306:
! 307: /* Add it to map of valid blocks */
! 308: if (!GC_install_counts(thishbp, (word)size_needed)) return(0);
! 309: /* This leaks memory under very rare conditions. */
! 310:
! 311: /* Set up header */
! 312: if (!setup_header(thishdr, sz, kind, flags)) {
! 313: GC_remove_counts(thishbp, (word)size_needed);
! 314: return(0); /* ditto */
! 315: }
! 316:
! 317: /* Clear block if necessary */
! 318: if (GC_debugging_started
! 319: || sz > MAXOBJSZ && GC_obj_kinds[kind].ok_init) {
! 320: BZERO(thishbp + HDR_BYTES, size_needed - HDR_BYTES);
! 321: }
! 322:
! 323: /* We just successfully allocated a block. Restart count of */
! 324: /* consecutive failures. */
! 325: {
! 326: extern unsigned GC_fail_count;
! 327:
! 328: GC_fail_count = 0;
! 329: }
! 330:
! 331: return( thishbp );
! 332: }
! 333:
! 334: struct hblk * GC_freehblk_ptr = 0; /* Search position hint for GC_freehblk */
! 335:
! 336: /*
! 337: * Free a heap block.
! 338: *
! 339: * Coalesce the block with its neighbors if possible.
! 340: *
! 341: * All mark words are assumed to be cleared.
! 342: */
! 343: void
! 344: GC_freehblk(p)
! 345: register struct hblk *p;
! 346: {
! 347: register hdr *phdr; /* Header corresponding to p */
! 348: register struct hblk *hbp, *prevhbp;
! 349: register hdr *hhdr, *prevhdr;
! 350: register signed_word size;
! 351:
! 352: /* GC_savhbp may become invalid due to coalescing. Clear it. */
! 353: GC_savhbp = (struct hblk *)0;
! 354:
! 355: phdr = HDR(p);
! 356: size = phdr->hb_sz;
! 357: size = HBLKSIZE * OBJ_SZ_TO_BLOCKS(size);
! 358: GC_remove_counts(p, (word)size);
! 359: phdr->hb_sz = size;
! 360: GC_invalidate_map(phdr);
! 361: prevhbp = 0;
! 362:
! 363: /* The following optimization was suggested by David Detlefs. */
! 364: /* Note that the header cannot be NIL, since there cannot be an */
! 365: /* intervening call to GC_freehblk without resetting */
! 366: /* GC_freehblk_ptr. */
! 367: if (GC_freehblk_ptr != 0 &&
! 368: HDR(GC_freehblk_ptr)->hb_map == GC_invalid_map &&
! 369: (ptr_t)GC_freehblk_ptr < (ptr_t)p) {
! 370: hbp = GC_freehblk_ptr;
! 371: } else {
! 372: hbp = GC_hblkfreelist;
! 373: };
! 374: hhdr = HDR(hbp);
! 375:
! 376: while( (hbp != 0) && (hbp < p) ) {
! 377: prevhbp = hbp;
! 378: prevhdr = hhdr;
! 379: hbp = hhdr->hb_next;
! 380: hhdr = HDR(hbp);
! 381: }
! 382: GC_freehblk_ptr = prevhbp;
! 383:
! 384: /* Check for duplicate deallocation in the easy case */
! 385: if (hbp != 0 && (ptr_t)p + size > (ptr_t)hbp
! 386: || prevhbp != 0 && (ptr_t)prevhbp + prevhdr->hb_sz > (ptr_t)p) {
! 387: GC_printf1("Duplicate large block deallocation of 0x%lx\n",
! 388: (unsigned long) p);
! 389: GC_printf2("Surrounding free blocks are 0x%lx and 0x%lx\n",
! 390: (unsigned long) prevhbp, (unsigned long) hbp);
! 391: }
! 392:
! 393: /* Coalesce with successor, if possible */
! 394: if( (((word)p)+size) == ((word)hbp) ) {
! 395: phdr->hb_next = hhdr->hb_next;
! 396: phdr->hb_sz += hhdr->hb_sz;
! 397: GC_remove_header(hbp);
! 398: } else {
! 399: phdr->hb_next = hbp;
! 400: }
! 401:
! 402:
! 403: if( prevhbp == 0 ) {
! 404: GC_hblkfreelist = p;
! 405: } else if( (((word)prevhbp) + prevhdr->hb_sz)
! 406: == ((word)p) ) {
! 407: /* Coalesce with predecessor */
! 408: prevhdr->hb_next = phdr->hb_next;
! 409: prevhdr->hb_sz += phdr->hb_sz;
! 410: GC_remove_header(p);
! 411: } else {
! 412: prevhdr->hb_next = p;
! 413: }
! 414: }
! 415:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>