Annotation of OpenXM_contrib/gc/stubborn.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: *
! 5: * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
! 6: * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
! 7: *
! 8: * Permission is hereby granted to use or copy this program
! 9: * for any purpose, provided the above notices are retained on all copies.
! 10: * Permission to modify the code and to distribute modified code is granted,
! 11: * provided the above notices are retained, and a notice that the code was
! 12: * modified is included with the above copyright notice.
! 13: */
! 14: /* Boehm, July 31, 1995 5:02 pm PDT */
! 15:
! 16:
! 17: #include "gc_priv.h"
! 18:
! 19: # ifdef STUBBORN_ALLOC
! 20: /* Stubborn object (hard to change, nearly immutable) allocation. */
! 21:
! 22: extern ptr_t GC_clear_stack(); /* in misc.c, behaves like identity */
! 23:
! 24: #define GENERAL_MALLOC(lb,k) \
! 25: (GC_PTR)GC_clear_stack(GC_generic_malloc((word)lb, k))
! 26:
! 27: /* Data structure representing immutable objects that */
! 28: /* are still being initialized. */
! 29: /* This is a bit baroque in order to avoid acquiring */
! 30: /* the lock twice for a typical allocation. */
! 31:
! 32: GC_PTR * GC_changing_list_start;
! 33:
! 34: # ifdef THREADS
! 35: VOLATILE GC_PTR * VOLATILE GC_changing_list_current;
! 36: # else
! 37: GC_PTR * GC_changing_list_current;
! 38: # endif
! 39: /* Points at last added element. Also (ab)used for */
! 40: /* synchronization. Updates and reads are assumed atomic. */
! 41:
! 42: GC_PTR * GC_changing_list_limit;
! 43: /* Points at the last word of the buffer, which is always 0 */
! 44: /* All entries in (GC_changing_list_current, */
! 45: /* GC_changing_list_limit] are 0 */
! 46:
! 47:
! 48: void GC_stubborn_init()
! 49: {
! 50: # define INIT_SIZE 10
! 51:
! 52: GC_changing_list_start = (GC_PTR *)
! 53: GC_generic_malloc_inner(
! 54: (word)(INIT_SIZE * sizeof(GC_PTR)),
! 55: PTRFREE);
! 56: BZERO(GC_changing_list_start,
! 57: INIT_SIZE * sizeof(GC_PTR));
! 58: if (GC_changing_list_start == 0) {
! 59: GC_err_printf0("Insufficient space to start up\n");
! 60: ABORT("GC_stubborn_init: put of space");
! 61: }
! 62: GC_changing_list_current = GC_changing_list_start;
! 63: GC_changing_list_limit = GC_changing_list_start + INIT_SIZE - 1;
! 64: * GC_changing_list_limit = 0;
! 65: }
! 66:
! 67: /* Compact and possibly grow GC_uninit_list. The old copy is */
! 68: /* left alone. Lock must be held. */
! 69: /* When called GC_changing_list_current == GC_changing_list_limit */
! 70: /* which is one past the current element. */
! 71: /* When we finish GC_changing_list_current again points one past last */
! 72: /* element. */
! 73: /* Invariant while this is running: GC_changing_list_current */
! 74: /* points at a word containing 0. */
! 75: /* Returns FALSE on failure. */
! 76: GC_bool GC_compact_changing_list()
! 77: {
! 78: register GC_PTR *p, *q;
! 79: register word count = 0;
! 80: word old_size = (char **)GC_changing_list_limit
! 81: - (char **)GC_changing_list_start+1;
! 82: /* The casts are needed as a workaround for an Amiga bug */
! 83: register word new_size = old_size;
! 84: GC_PTR * new_list;
! 85:
! 86: for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
! 87: if (*p != 0) count++;
! 88: }
! 89: if (2 * count > old_size) new_size = 2 * count;
! 90: new_list = (GC_PTR *)
! 91: GC_generic_malloc_inner(
! 92: new_size * sizeof(GC_PTR), PTRFREE);
! 93: /* PTRFREE is a lie. But we don't want the collector to */
! 94: /* consider these. We do want the list itself to be */
! 95: /* collectable. */
! 96: if (new_list == 0) return(FALSE);
! 97: BZERO(new_list, new_size * sizeof(GC_PTR));
! 98: q = new_list;
! 99: for (p = GC_changing_list_start; p < GC_changing_list_limit; p++) {
! 100: if (*p != 0) *q++ = *p;
! 101: }
! 102: GC_changing_list_start = new_list;
! 103: GC_changing_list_limit = new_list + new_size - 1;
! 104: GC_changing_list_current = q;
! 105: return(TRUE);
! 106: }
! 107:
! 108: /* Add p to changing list. Clear p on failure. */
! 109: # define ADD_CHANGING(p) \
! 110: { \
! 111: register struct hblk * h = HBLKPTR(p); \
! 112: register word index = PHT_HASH(h); \
! 113: \
! 114: set_pht_entry_from_index(GC_changed_pages, index); \
! 115: } \
! 116: if (*GC_changing_list_current != 0 \
! 117: && ++GC_changing_list_current == GC_changing_list_limit) { \
! 118: if (!GC_compact_changing_list()) (p) = 0; \
! 119: } \
! 120: *GC_changing_list_current = p;
! 121:
! 122: void GC_change_stubborn(p)
! 123: GC_PTR p;
! 124: {
! 125: DCL_LOCK_STATE;
! 126:
! 127: DISABLE_SIGNALS();
! 128: LOCK();
! 129: ADD_CHANGING(p);
! 130: UNLOCK();
! 131: ENABLE_SIGNALS();
! 132: }
! 133:
! 134: void GC_end_stubborn_change(p)
! 135: GC_PTR p;
! 136: {
! 137: # ifdef THREADS
! 138: register VOLATILE GC_PTR * my_current = GC_changing_list_current;
! 139: # else
! 140: register GC_PTR * my_current = GC_changing_list_current;
! 141: # endif
! 142: register GC_bool tried_quick;
! 143: DCL_LOCK_STATE;
! 144:
! 145: if (*my_current == p) {
! 146: /* Hopefully the normal case. */
! 147: /* Compaction could not have been running when we started. */
! 148: *my_current = 0;
! 149: # ifdef THREADS
! 150: if (my_current == GC_changing_list_current) {
! 151: /* Compaction can't have run in the interim. */
! 152: /* We got away with the quick and dirty approach. */
! 153: return;
! 154: }
! 155: tried_quick = TRUE;
! 156: # else
! 157: return;
! 158: # endif
! 159: } else {
! 160: tried_quick = FALSE;
! 161: }
! 162: DISABLE_SIGNALS();
! 163: LOCK();
! 164: my_current = GC_changing_list_current;
! 165: for (; my_current >= GC_changing_list_start; my_current--) {
! 166: if (*my_current == p) {
! 167: *my_current = 0;
! 168: UNLOCK();
! 169: ENABLE_SIGNALS();
! 170: return;
! 171: }
! 172: }
! 173: if (!tried_quick) {
! 174: GC_err_printf1("Bad arg to GC_end_stubborn_change: 0x%lx\n",
! 175: (unsigned long)p);
! 176: ABORT("Bad arg to GC_end_stubborn_change");
! 177: }
! 178: UNLOCK();
! 179: ENABLE_SIGNALS();
! 180: }
! 181:
! 182: /* Allocate lb bytes of composite (pointerful) data */
! 183: /* No pointer fields may be changed after a call to */
! 184: /* GC_end_stubborn_change(p) where p is the value */
! 185: /* returned by GC_malloc_stubborn. */
! 186: # ifdef __STDC__
! 187: GC_PTR GC_malloc_stubborn(size_t lb)
! 188: # else
! 189: GC_PTR GC_malloc_stubborn(lb)
! 190: size_t lb;
! 191: # endif
! 192: {
! 193: register ptr_t op;
! 194: register ptr_t *opp;
! 195: register word lw;
! 196: ptr_t result;
! 197: DCL_LOCK_STATE;
! 198:
! 199: if( SMALL_OBJ(lb) ) {
! 200: # ifdef MERGE_SIZES
! 201: lw = GC_size_map[lb];
! 202: # else
! 203: lw = ALIGNED_WORDS(lb);
! 204: # endif
! 205: opp = &(GC_sobjfreelist[lw]);
! 206: FASTLOCK();
! 207: if( !FASTLOCK_SUCCEEDED() || (op = *opp) == 0 ) {
! 208: FASTUNLOCK();
! 209: result = GC_generic_malloc((word)lb, STUBBORN);
! 210: goto record;
! 211: }
! 212: *opp = obj_link(op);
! 213: obj_link(op) = 0;
! 214: GC_words_allocd += lw;
! 215: result = (GC_PTR) op;
! 216: ADD_CHANGING(result);
! 217: FASTUNLOCK();
! 218: return((GC_PTR)result);
! 219: } else {
! 220: result = (GC_PTR)
! 221: GC_generic_malloc((word)lb, STUBBORN);
! 222: }
! 223: record:
! 224: DISABLE_SIGNALS();
! 225: LOCK();
! 226: ADD_CHANGING(result);
! 227: UNLOCK();
! 228: ENABLE_SIGNALS();
! 229: return((GC_PTR)GC_clear_stack(result));
! 230: }
! 231:
! 232:
! 233: /* Functions analogous to GC_read_dirty and GC_page_was_dirty. */
! 234: /* Report pages on which stubborn objects were changed. */
! 235: void GC_read_changed()
! 236: {
! 237: register GC_PTR * p = GC_changing_list_start;
! 238: register GC_PTR q;
! 239: register struct hblk * h;
! 240: register word index;
! 241:
! 242: if (p == 0) /* initializing */ return;
! 243: BCOPY(GC_changed_pages, GC_prev_changed_pages,
! 244: (sizeof GC_changed_pages));
! 245: BZERO(GC_changed_pages, (sizeof GC_changed_pages));
! 246: for (; p <= GC_changing_list_current; p++) {
! 247: if ((q = *p) != 0) {
! 248: h = HBLKPTR(q);
! 249: index = PHT_HASH(h);
! 250: set_pht_entry_from_index(GC_changed_pages, index);
! 251: }
! 252: }
! 253: }
! 254:
! 255: GC_bool GC_page_was_changed(h)
! 256: struct hblk * h;
! 257: {
! 258: register word index = PHT_HASH(h);
! 259:
! 260: return(get_pht_entry_from_index(GC_prev_changed_pages, index));
! 261: }
! 262:
! 263: /* Remove unreachable entries from changed list. Should only be */
! 264: /* called with mark bits consistent and lock held. */
! 265: void GC_clean_changing_list()
! 266: {
! 267: register GC_PTR * p = GC_changing_list_start;
! 268: register GC_PTR q;
! 269: register ptr_t r;
! 270: register unsigned long count = 0;
! 271: register unsigned long dropped_count = 0;
! 272:
! 273: if (p == 0) /* initializing */ return;
! 274: for (; p <= GC_changing_list_current; p++) {
! 275: if ((q = *p) != 0) {
! 276: count++;
! 277: r = (ptr_t)GC_base(q);
! 278: if (r == 0 || !GC_is_marked(r)) {
! 279: *p = 0;
! 280: dropped_count++;
! 281: }
! 282: }
! 283: }
! 284: # ifdef PRINTSTATS
! 285: if (count > 0) {
! 286: GC_printf2("%lu entries in changing list: reclaimed %lu\n",
! 287: (unsigned long)count, (unsigned long)dropped_count);
! 288: }
! 289: # endif
! 290: }
! 291:
! 292: #else /* !STUBBORN_ALLOC */
! 293:
! 294: # ifdef __STDC__
! 295: GC_PTR GC_malloc_stubborn(size_t lb)
! 296: # else
! 297: GC_PTR GC_malloc_stubborn(lb)
! 298: size_t lb;
! 299: # endif
! 300: {
! 301: return(GC_malloc(lb));
! 302: }
! 303:
! 304: /*ARGSUSED*/
! 305: void GC_end_stubborn_change(p)
! 306: GC_PTR p;
! 307: {
! 308: }
! 309:
! 310: /*ARGSUSED*/
! 311: void GC_change_stubborn(p)
! 312: GC_PTR p;
! 313: {
! 314: }
! 315:
! 316:
! 317: #endif
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>