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