Annotation of OpenXM_contrib2/asir2000/gc/stubborn.c, Revision 1.1.1.1
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.
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>