Annotation of OpenXM_contrib/gc/finalize.c, Revision 1.1.1.1
1.1 maekawa 1: /*
2: * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
3: * Copyright (c) 1991-1996 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, February 1, 1996 1:19 pm PST */
15: # define I_HIDE_POINTERS
16: # include "gc_priv.h"
17: # include "gc_mark.h"
18:
19: /* Type of mark procedure used for marking from finalizable object. */
20: /* This procedure normally does not mark the object, only its */
21: /* descendents. */
22: typedef void finalization_mark_proc(/* ptr_t finalizable_obj_ptr */);
23:
24: # define HASH3(addr,size,log_size) \
25: ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \
26: & ((size) - 1))
27: #define HASH2(addr,log_size) HASH3(addr, 1 << log_size, log_size)
28:
29: struct hash_chain_entry {
30: word hidden_key;
31: struct hash_chain_entry * next;
32: };
33:
34: unsigned GC_finalization_failures = 0;
35: /* Number of finalization requests that failed for lack of memory. */
36:
37: static struct disappearing_link {
38: struct hash_chain_entry prolog;
39: # define dl_hidden_link prolog.hidden_key
40: /* Field to be cleared. */
41: # define dl_next(x) (struct disappearing_link *)((x) -> prolog.next)
42: # define dl_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
43:
44: word dl_hidden_obj; /* Pointer to object base */
45: } **dl_head = 0;
46:
47: static signed_word log_dl_table_size = -1;
48: /* Binary log of */
49: /* current size of array pointed to by dl_head. */
50: /* -1 ==> size is 0. */
51:
52: word GC_dl_entries = 0; /* Number of entries currently in disappearing */
53: /* link table. */
54:
55: static struct finalizable_object {
56: struct hash_chain_entry prolog;
57: # define fo_hidden_base prolog.hidden_key
58: /* Pointer to object base. */
59: /* No longer hidden once object */
60: /* is on finalize_now queue. */
61: # define fo_next(x) (struct finalizable_object *)((x) -> prolog.next)
62: # define fo_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
63: GC_finalization_proc fo_fn; /* Finalizer. */
64: ptr_t fo_client_data;
65: word fo_object_size; /* In bytes. */
66: finalization_mark_proc * fo_mark_proc; /* Mark-through procedure */
67: } **fo_head = 0;
68:
69: struct finalizable_object * GC_finalize_now = 0;
70: /* LIst of objects that should be finalized now. */
71:
72: static signed_word log_fo_table_size = -1;
73:
74: word GC_fo_entries = 0;
75:
76: # ifdef SRC_M3
77: void GC_push_finalizer_structures()
78: {
79: GC_push_all((ptr_t)(&dl_head), (ptr_t)(&dl_head) + sizeof(word));
80: GC_push_all((ptr_t)(&fo_head), (ptr_t)(&fo_head) + sizeof(word));
81: }
82: # endif
83:
84: /* Double the size of a hash table. *size_ptr is the log of its current */
85: /* size. May be a noop. */
86: /* *table is a pointer to an array of hash headers. If we succeed, we */
87: /* update both *table and *log_size_ptr. */
88: /* Lock is held. Signals are disabled. */
89: void GC_grow_table(table, log_size_ptr)
90: struct hash_chain_entry ***table;
91: signed_word * log_size_ptr;
92: {
93: register word i;
94: register struct hash_chain_entry *p;
95: int log_old_size = *log_size_ptr;
96: register int log_new_size = log_old_size + 1;
97: word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
98: register word new_size = 1 << log_new_size;
99: struct hash_chain_entry **new_table = (struct hash_chain_entry **)
100: GC_generic_malloc_inner_ignore_off_page(
101: (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
102:
103: if (new_table == 0) {
104: if (table == 0) {
105: ABORT("Insufficient space for initial table allocation");
106: } else {
107: return;
108: }
109: }
110: for (i = 0; i < old_size; i++) {
111: p = (*table)[i];
112: while (p != 0) {
113: register ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
114: register struct hash_chain_entry *next = p -> next;
115: register int new_hash = HASH3(real_key, new_size, log_new_size);
116:
117: p -> next = new_table[new_hash];
118: new_table[new_hash] = p;
119: p = next;
120: }
121: }
122: *log_size_ptr = log_new_size;
123: *table = new_table;
124: }
125:
126: # if defined(__STDC__) || defined(__cplusplus)
127: int GC_register_disappearing_link(GC_PTR * link)
128: # else
129: int GC_register_disappearing_link(link)
130: GC_PTR * link;
131: # endif
132: {
133: ptr_t base;
134:
135: base = (ptr_t)GC_base((GC_PTR)link);
136: if (base == 0)
137: ABORT("Bad arg to GC_register_disappearing_link");
138: return(GC_general_register_disappearing_link(link, base));
139: }
140:
141: # if defined(__STDC__) || defined(__cplusplus)
142: int GC_general_register_disappearing_link(GC_PTR * link,
143: GC_PTR obj)
144: # else
145: int GC_general_register_disappearing_link(link, obj)
146: GC_PTR * link;
147: GC_PTR obj;
148: # endif
149:
150: {
151: struct disappearing_link *curr_dl;
152: int index;
153: struct disappearing_link * new_dl;
154: DCL_LOCK_STATE;
155:
156: if ((word)link & (ALIGNMENT-1))
157: ABORT("Bad arg to GC_general_register_disappearing_link");
158: # ifdef THREADS
159: DISABLE_SIGNALS();
160: LOCK();
161: # endif
162: if (log_dl_table_size == -1
163: || GC_dl_entries > ((word)1 << log_dl_table_size)) {
164: # ifndef THREADS
165: DISABLE_SIGNALS();
166: # endif
167: GC_grow_table((struct hash_chain_entry ***)(&dl_head),
168: &log_dl_table_size);
169: # ifdef PRINTSTATS
170: GC_printf1("Grew dl table to %lu entries\n",
171: (unsigned long)(1 << log_dl_table_size));
172: # endif
173: # ifndef THREADS
174: ENABLE_SIGNALS();
175: # endif
176: }
177: index = HASH2(link, log_dl_table_size);
178: curr_dl = dl_head[index];
179: for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
180: if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
181: curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
182: # ifdef THREADS
183: UNLOCK();
184: ENABLE_SIGNALS();
185: # endif
186: return(1);
187: }
188: }
189: # ifdef THREADS
190: new_dl = (struct disappearing_link *)
191: GC_generic_malloc_inner(sizeof(struct disappearing_link),NORMAL);
192: # else
193: new_dl = (struct disappearing_link *)
194: GC_malloc(sizeof(struct disappearing_link));
195: # endif
196: if (new_dl != 0) {
197: new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
198: new_dl -> dl_hidden_link = HIDE_POINTER(link);
199: dl_set_next(new_dl, dl_head[index]);
200: dl_head[index] = new_dl;
201: GC_dl_entries++;
202: } else {
203: GC_finalization_failures++;
204: }
205: # ifdef THREADS
206: UNLOCK();
207: ENABLE_SIGNALS();
208: # endif
209: return(0);
210: }
211:
212: # if defined(__STDC__) || defined(__cplusplus)
213: int GC_unregister_disappearing_link(GC_PTR * link)
214: # else
215: int GC_unregister_disappearing_link(link)
216: GC_PTR * link;
217: # endif
218: {
219: struct disappearing_link *curr_dl, *prev_dl;
220: int index;
221: DCL_LOCK_STATE;
222:
223: DISABLE_SIGNALS();
224: LOCK();
225: index = HASH2(link, log_dl_table_size);
226: if (((unsigned long)link & (ALIGNMENT-1))) goto out;
227: prev_dl = 0; curr_dl = dl_head[index];
228: while (curr_dl != 0) {
229: if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
230: if (prev_dl == 0) {
231: dl_head[index] = dl_next(curr_dl);
232: } else {
233: dl_set_next(prev_dl, dl_next(curr_dl));
234: }
235: GC_dl_entries--;
236: UNLOCK();
237: ENABLE_SIGNALS();
238: GC_free((GC_PTR)curr_dl);
239: return(1);
240: }
241: prev_dl = curr_dl;
242: curr_dl = dl_next(curr_dl);
243: }
244: out:
245: UNLOCK();
246: ENABLE_SIGNALS();
247: return(0);
248: }
249:
250: /* Possible finalization_marker procedures. Note that mark stack */
251: /* overflow is handled by the caller, and is not a disaster. */
252: void GC_normal_finalize_mark_proc(p)
253: ptr_t p;
254: {
255: hdr * hhdr = HDR(p);
256:
257: PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
258: &(GC_mark_stack[GC_mark_stack_size]));
259: }
260:
261: /* This only pays very partial attention to the mark descriptor. */
262: /* It does the right thing for normal and atomic objects, and treats */
263: /* most others as normal. */
264: void GC_ignore_self_finalize_mark_proc(p)
265: ptr_t p;
266: {
267: hdr * hhdr = HDR(p);
268: word descr = hhdr -> hb_descr;
269: ptr_t q, r;
270: ptr_t scan_limit;
271: ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
272:
273: if ((descr & DS_TAGS) == DS_LENGTH) {
274: scan_limit = p + descr - sizeof(word);
275: } else {
276: scan_limit = target_limit + 1 - sizeof(word);
277: }
278: for (q = p; q <= scan_limit; q += ALIGNMENT) {
279: r = *(ptr_t *)q;
280: if (r < p || r > target_limit) {
281: GC_PUSH_ONE_HEAP((word)r, q);
282: }
283: }
284: }
285:
286: /*ARGSUSED*/
287: void GC_null_finalize_mark_proc(p)
288: ptr_t p;
289: {
290: }
291:
292:
293:
294: /* Register a finalization function. See gc.h for details. */
295: /* in the nonthreads case, we try to avoid disabling signals, */
296: /* since it can be expensive. Threads packages typically */
297: /* make it cheaper. */
298: void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
299: GC_PTR obj;
300: GC_finalization_proc fn;
301: GC_PTR cd;
302: GC_finalization_proc * ofn;
303: GC_PTR * ocd;
304: finalization_mark_proc * mp;
305: {
306: ptr_t base;
307: struct finalizable_object * curr_fo, * prev_fo;
308: int index;
309: struct finalizable_object *new_fo;
310: DCL_LOCK_STATE;
311:
312: # ifdef THREADS
313: DISABLE_SIGNALS();
314: LOCK();
315: # endif
316: if (log_fo_table_size == -1
317: || GC_fo_entries > ((word)1 << log_fo_table_size)) {
318: # ifndef THREADS
319: DISABLE_SIGNALS();
320: # endif
321: GC_grow_table((struct hash_chain_entry ***)(&fo_head),
322: &log_fo_table_size);
323: # ifdef PRINTSTATS
324: GC_printf1("Grew fo table to %lu entries\n",
325: (unsigned long)(1 << log_fo_table_size));
326: # endif
327: # ifndef THREADS
328: ENABLE_SIGNALS();
329: # endif
330: }
331: /* in the THREADS case signals are disabled and we hold allocation */
332: /* lock; otherwise neither is true. Proceed carefully. */
333: base = (ptr_t)obj;
334: index = HASH2(base, log_fo_table_size);
335: prev_fo = 0; curr_fo = fo_head[index];
336: while (curr_fo != 0) {
337: if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
338: /* Interruption by a signal in the middle of this */
339: /* should be safe. The client may see only *ocd */
340: /* updated, but we'll declare that to be his */
341: /* problem. */
342: if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
343: if (ofn) *ofn = curr_fo -> fo_fn;
344: /* Delete the structure for base. */
345: if (prev_fo == 0) {
346: fo_head[index] = fo_next(curr_fo);
347: } else {
348: fo_set_next(prev_fo, fo_next(curr_fo));
349: }
350: if (fn == 0) {
351: GC_fo_entries--;
352: /* May not happen if we get a signal. But a high */
353: /* estimate will only make the table larger than */
354: /* necessary. */
355: # ifndef THREADS
356: GC_free((GC_PTR)curr_fo);
357: # endif
358: } else {
359: curr_fo -> fo_fn = fn;
360: curr_fo -> fo_client_data = (ptr_t)cd;
361: curr_fo -> fo_mark_proc = mp;
362: /* Reinsert it. We deleted it first to maintain */
363: /* consistency in the event of a signal. */
364: if (prev_fo == 0) {
365: fo_head[index] = curr_fo;
366: } else {
367: fo_set_next(prev_fo, curr_fo);
368: }
369: }
370: # ifdef THREADS
371: UNLOCK();
372: ENABLE_SIGNALS();
373: # endif
374: return;
375: }
376: prev_fo = curr_fo;
377: curr_fo = fo_next(curr_fo);
378: }
379: if (ofn) *ofn = 0;
380: if (ocd) *ocd = 0;
381: if (fn == 0) {
382: # ifdef THREADS
383: UNLOCK();
384: ENABLE_SIGNALS();
385: # endif
386: return;
387: }
388: # ifdef THREADS
389: new_fo = (struct finalizable_object *)
390: GC_generic_malloc_inner(sizeof(struct finalizable_object),NORMAL);
391: # else
392: new_fo = (struct finalizable_object *)
393: GC_malloc(sizeof(struct finalizable_object));
394: # endif
395: if (new_fo != 0) {
396: new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
397: new_fo -> fo_fn = fn;
398: new_fo -> fo_client_data = (ptr_t)cd;
399: new_fo -> fo_object_size = GC_size(base);
400: new_fo -> fo_mark_proc = mp;
401: fo_set_next(new_fo, fo_head[index]);
402: GC_fo_entries++;
403: fo_head[index] = new_fo;
404: } else {
405: GC_finalization_failures++;
406: }
407: # ifdef THREADS
408: UNLOCK();
409: ENABLE_SIGNALS();
410: # endif
411: }
412:
413: # if defined(__STDC__)
414: void GC_register_finalizer(void * obj,
415: GC_finalization_proc fn, void * cd,
416: GC_finalization_proc *ofn, void ** ocd)
417: # else
418: void GC_register_finalizer(obj, fn, cd, ofn, ocd)
419: GC_PTR obj;
420: GC_finalization_proc fn;
421: GC_PTR cd;
422: GC_finalization_proc * ofn;
423: GC_PTR * ocd;
424: # endif
425: {
426: GC_register_finalizer_inner(obj, fn, cd, ofn,
427: ocd, GC_normal_finalize_mark_proc);
428: }
429:
430: # if defined(__STDC__)
431: void GC_register_finalizer_ignore_self(void * obj,
432: GC_finalization_proc fn, void * cd,
433: GC_finalization_proc *ofn, void ** ocd)
434: # else
435: void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
436: GC_PTR obj;
437: GC_finalization_proc fn;
438: GC_PTR cd;
439: GC_finalization_proc * ofn;
440: GC_PTR * ocd;
441: # endif
442: {
443: GC_register_finalizer_inner(obj, fn, cd, ofn,
444: ocd, GC_ignore_self_finalize_mark_proc);
445: }
446:
447: # if defined(__STDC__)
448: void GC_register_finalizer_no_order(void * obj,
449: GC_finalization_proc fn, void * cd,
450: GC_finalization_proc *ofn, void ** ocd)
451: # else
452: void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
453: GC_PTR obj;
454: GC_finalization_proc fn;
455: GC_PTR cd;
456: GC_finalization_proc * ofn;
457: GC_PTR * ocd;
458: # endif
459: {
460: GC_register_finalizer_inner(obj, fn, cd, ofn,
461: ocd, GC_null_finalize_mark_proc);
462: }
463:
464: /* Called with world stopped. Cause disappearing links to disappear, */
465: /* and invoke finalizers. */
466: void GC_finalize()
467: {
468: struct disappearing_link * curr_dl, * prev_dl, * next_dl;
469: struct finalizable_object * curr_fo, * prev_fo, * next_fo;
470: ptr_t real_ptr, real_link;
471: register int i;
472: int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
473: int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
474:
475: /* Make disappearing links disappear */
476: for (i = 0; i < dl_size; i++) {
477: curr_dl = dl_head[i];
478: prev_dl = 0;
479: while (curr_dl != 0) {
480: real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
481: real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
482: if (!GC_is_marked(real_ptr)) {
483: *(word *)real_link = 0;
484: next_dl = dl_next(curr_dl);
485: if (prev_dl == 0) {
486: dl_head[i] = next_dl;
487: } else {
488: dl_set_next(prev_dl, next_dl);
489: }
490: GC_clear_mark_bit((ptr_t)curr_dl);
491: GC_dl_entries--;
492: curr_dl = next_dl;
493: } else {
494: prev_dl = curr_dl;
495: curr_dl = dl_next(curr_dl);
496: }
497: }
498: }
499: /* Mark all objects reachable via chains of 1 or more pointers */
500: /* from finalizable objects. */
501: # ifdef PRINTSTATS
502: if (GC_mark_state != MS_NONE) ABORT("Bad mark state");
503: # endif
504: for (i = 0; i < fo_size; i++) {
505: for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
506: real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
507: if (!GC_is_marked(real_ptr)) {
508: GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
509: if (GC_is_marked(real_ptr)) {
510: WARN("Finalization cycle involving %lx\n", real_ptr);
511: }
512: }
513: }
514: }
515: /* Enqueue for finalization all objects that are still */
516: /* unreachable. */
517: GC_words_finalized = 0;
518: for (i = 0; i < fo_size; i++) {
519: curr_fo = fo_head[i];
520: prev_fo = 0;
521: while (curr_fo != 0) {
522: real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
523: if (!GC_is_marked(real_ptr)) {
524: # ifndef JAVA_FINALIZATION
525: GC_set_mark_bit(real_ptr);
526: # endif
527: /* Delete from hash table */
528: next_fo = fo_next(curr_fo);
529: if (prev_fo == 0) {
530: fo_head[i] = next_fo;
531: } else {
532: fo_set_next(prev_fo, next_fo);
533: }
534: GC_fo_entries--;
535: /* Add to list of objects awaiting finalization. */
536: fo_set_next(curr_fo, GC_finalize_now);
537: GC_finalize_now = curr_fo;
538: /* unhide object pointer so any future collections will */
539: /* see it. */
540: curr_fo -> fo_hidden_base =
541: (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
542: GC_words_finalized +=
543: ALIGNED_WORDS(curr_fo -> fo_object_size)
544: + ALIGNED_WORDS(sizeof(struct finalizable_object));
545: # ifdef PRINTSTATS
546: if (!GC_is_marked((ptr_t)curr_fo)) {
547: ABORT("GC_finalize: found accessible unmarked object\n");
548: }
549: # endif
550: curr_fo = next_fo;
551: } else {
552: prev_fo = curr_fo;
553: curr_fo = fo_next(curr_fo);
554: }
555: }
556: }
557:
558: # ifdef JAVA_FINALIZATION
559: /* make sure we mark everything reachable from objects finalized
560: using the no_order mark_proc */
561: for (curr_fo = GC_finalize_now;
562: curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
563: real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
564: if (!GC_is_marked(real_ptr)) {
565: if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
566: GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
567: }
568: GC_set_mark_bit(real_ptr);
569: }
570: }
571: # endif
572:
573: /* Remove dangling disappearing links. */
574: for (i = 0; i < dl_size; i++) {
575: curr_dl = dl_head[i];
576: prev_dl = 0;
577: while (curr_dl != 0) {
578: real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
579: if (real_link != 0 && !GC_is_marked(real_link)) {
580: next_dl = dl_next(curr_dl);
581: if (prev_dl == 0) {
582: dl_head[i] = next_dl;
583: } else {
584: dl_set_next(prev_dl, next_dl);
585: }
586: GC_clear_mark_bit((ptr_t)curr_dl);
587: GC_dl_entries--;
588: curr_dl = next_dl;
589: } else {
590: prev_dl = curr_dl;
591: curr_dl = dl_next(curr_dl);
592: }
593: }
594: }
595: }
596:
597: #ifdef JAVA_FINALIZATION
598:
599: /* Enqueue all remaining finalizers to be run - Assumes lock is
600: * held, and signals are disabled */
601: void GC_enqueue_all_finalizers()
602: {
603: struct finalizable_object * curr_fo, * prev_fo, * next_fo;
604: ptr_t real_ptr, real_link;
605: register int i;
606: int fo_size;
607:
608: fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
609: GC_words_finalized = 0;
610: for (i = 0; i < fo_size; i++) {
611: curr_fo = fo_head[i];
612: prev_fo = 0;
613: while (curr_fo != 0) {
614: real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
615: GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
616: GC_set_mark_bit(real_ptr);
617:
618: /* Delete from hash table */
619: next_fo = fo_next(curr_fo);
620: if (prev_fo == 0) {
621: fo_head[i] = next_fo;
622: } else {
623: fo_set_next(prev_fo, next_fo);
624: }
625: GC_fo_entries--;
626:
627: /* Add to list of objects awaiting finalization. */
628: fo_set_next(curr_fo, GC_finalize_now);
629: GC_finalize_now = curr_fo;
630:
631: /* unhide object pointer so any future collections will */
632: /* see it. */
633: curr_fo -> fo_hidden_base =
634: (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
635:
636: GC_words_finalized +=
637: ALIGNED_WORDS(curr_fo -> fo_object_size)
638: + ALIGNED_WORDS(sizeof(struct finalizable_object));
639: curr_fo = next_fo;
640: }
641: }
642:
643: return;
644: }
645:
646: /* Invoke all remaining finalizers that haven't yet been run.
647: * This is needed for strict compliance with the Java standard,
648: * which can make the runtime guarantee that all finalizers are run.
649: * Unfortunately, the Java standard implies we have to keep running
650: * finalizers until there are no more left, a potential infinite loop.
651: * YUCK.
652: * This routine is externally callable, so is called without
653: * the allocation lock.
654: */
655: void GC_finalize_all()
656: {
657: DCL_LOCK_STATE;
658:
659: DISABLE_SIGNALS();
660: LOCK();
661: while (GC_fo_entries > 0) {
662: GC_enqueue_all_finalizers();
663: UNLOCK();
664: ENABLE_SIGNALS();
665: GC_INVOKE_FINALIZERS();
666: DISABLE_SIGNALS();
667: LOCK();
668: }
669: UNLOCK();
670: ENABLE_SIGNALS();
671: }
672: #endif
673:
674: /* Invoke finalizers for all objects that are ready to be finalized. */
675: /* Should be called without allocation lock. */
676: int GC_invoke_finalizers()
677: {
678: register struct finalizable_object * curr_fo;
679: register int count = 0;
680: DCL_LOCK_STATE;
681:
682: while (GC_finalize_now != 0) {
683: # ifdef THREADS
684: DISABLE_SIGNALS();
685: LOCK();
686: # endif
687: curr_fo = GC_finalize_now;
688: # ifdef THREADS
689: if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
690: UNLOCK();
691: ENABLE_SIGNALS();
692: if (curr_fo == 0) break;
693: # else
694: GC_finalize_now = fo_next(curr_fo);
695: # endif
696: fo_set_next(curr_fo, 0);
697: (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
698: curr_fo -> fo_client_data);
699: curr_fo -> fo_client_data = 0;
700: ++count;
701: # ifdef UNDEFINED
702: /* This is probably a bad idea. It throws off accounting if */
703: /* nearly all objects are finalizable. O.w. it shouldn't */
704: /* matter. */
705: GC_free((GC_PTR)curr_fo);
706: # endif
707: }
708: return count;
709: }
710:
711: # ifdef __STDC__
712: GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
713: GC_PTR client_data)
714: # else
715: GC_PTR GC_call_with_alloc_lock(fn, client_data)
716: GC_fn_type fn;
717: GC_PTR client_data;
718: # endif
719: {
720: GC_PTR result;
721: DCL_LOCK_STATE;
722:
723: # ifdef THREADS
724: DISABLE_SIGNALS();
725: LOCK();
726: SET_LOCK_HOLDER();
727: # endif
728: result = (*fn)(client_data);
729: # ifdef THREADS
730: UNSET_LOCK_HOLDER();
731: UNLOCK();
732: ENABLE_SIGNALS();
733: # endif
734: return(result);
735: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>