Annotation of OpenXM_contrib2/asir2000/gc/finalize.c, Revision 1.1.1.1
1.1 noro 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_MARKED_FOR_FINALIZATION(real_ptr);
509: GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
510: if (GC_is_marked(real_ptr)) {
511: WARN("Finalization cycle involving %lx\n", real_ptr);
512: }
513: }
514: }
515: }
516: /* Enqueue for finalization all objects that are still */
517: /* unreachable. */
518: GC_words_finalized = 0;
519: for (i = 0; i < fo_size; i++) {
520: curr_fo = fo_head[i];
521: prev_fo = 0;
522: while (curr_fo != 0) {
523: real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
524: if (!GC_is_marked(real_ptr)) {
525: # ifndef JAVA_FINALIZATION
526: GC_set_mark_bit(real_ptr);
527: # endif
528: /* Delete from hash table */
529: next_fo = fo_next(curr_fo);
530: if (prev_fo == 0) {
531: fo_head[i] = next_fo;
532: } else {
533: fo_set_next(prev_fo, next_fo);
534: }
535: GC_fo_entries--;
536: /* Add to list of objects awaiting finalization. */
537: fo_set_next(curr_fo, GC_finalize_now);
538: GC_finalize_now = curr_fo;
539: /* unhide object pointer so any future collections will */
540: /* see it. */
541: curr_fo -> fo_hidden_base =
542: (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
543: GC_words_finalized +=
544: ALIGNED_WORDS(curr_fo -> fo_object_size)
545: + ALIGNED_WORDS(sizeof(struct finalizable_object));
546: # ifdef PRINTSTATS
547: if (!GC_is_marked((ptr_t)curr_fo)) {
548: ABORT("GC_finalize: found accessible unmarked object\n");
549: }
550: # endif
551: curr_fo = next_fo;
552: } else {
553: prev_fo = curr_fo;
554: curr_fo = fo_next(curr_fo);
555: }
556: }
557: }
558:
559: # ifdef JAVA_FINALIZATION
560: /* make sure we mark everything reachable from objects finalized
561: using the no_order mark_proc */
562: for (curr_fo = GC_finalize_now;
563: curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
564: real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
565: if (!GC_is_marked(real_ptr)) {
566: if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
567: GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
568: }
569: GC_set_mark_bit(real_ptr);
570: }
571: }
572: # endif
573:
574: /* Remove dangling disappearing links. */
575: for (i = 0; i < dl_size; i++) {
576: curr_dl = dl_head[i];
577: prev_dl = 0;
578: while (curr_dl != 0) {
579: real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
580: if (real_link != 0 && !GC_is_marked(real_link)) {
581: next_dl = dl_next(curr_dl);
582: if (prev_dl == 0) {
583: dl_head[i] = next_dl;
584: } else {
585: dl_set_next(prev_dl, next_dl);
586: }
587: GC_clear_mark_bit((ptr_t)curr_dl);
588: GC_dl_entries--;
589: curr_dl = next_dl;
590: } else {
591: prev_dl = curr_dl;
592: curr_dl = dl_next(curr_dl);
593: }
594: }
595: }
596: }
597:
598: #ifdef JAVA_FINALIZATION
599:
600: /* Enqueue all remaining finalizers to be run - Assumes lock is
601: * held, and signals are disabled */
602: void GC_enqueue_all_finalizers()
603: {
604: struct finalizable_object * curr_fo, * prev_fo, * next_fo;
605: ptr_t real_ptr, real_link;
606: register int i;
607: int fo_size;
608:
609: fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
610: GC_words_finalized = 0;
611: for (i = 0; i < fo_size; i++) {
612: curr_fo = fo_head[i];
613: prev_fo = 0;
614: while (curr_fo != 0) {
615: real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
616: GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
617: GC_set_mark_bit(real_ptr);
618:
619: /* Delete from hash table */
620: next_fo = fo_next(curr_fo);
621: if (prev_fo == 0) {
622: fo_head[i] = next_fo;
623: } else {
624: fo_set_next(prev_fo, next_fo);
625: }
626: GC_fo_entries--;
627:
628: /* Add to list of objects awaiting finalization. */
629: fo_set_next(curr_fo, GC_finalize_now);
630: GC_finalize_now = curr_fo;
631:
632: /* unhide object pointer so any future collections will */
633: /* see it. */
634: curr_fo -> fo_hidden_base =
635: (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
636:
637: GC_words_finalized +=
638: ALIGNED_WORDS(curr_fo -> fo_object_size)
639: + ALIGNED_WORDS(sizeof(struct finalizable_object));
640: curr_fo = next_fo;
641: }
642: }
643:
644: return;
645: }
646:
647: /* Invoke all remaining finalizers that haven't yet been run.
648: * This is needed for strict compliance with the Java standard,
649: * which can make the runtime guarantee that all finalizers are run.
650: * Unfortunately, the Java standard implies we have to keep running
651: * finalizers until there are no more left, a potential infinite loop.
652: * YUCK.
653: * This routine is externally callable, so is called without
654: * the allocation lock.
655: */
656: void GC_finalize_all()
657: {
658: DCL_LOCK_STATE;
659:
660: DISABLE_SIGNALS();
661: LOCK();
662: while (GC_fo_entries > 0) {
663: GC_enqueue_all_finalizers();
664: UNLOCK();
665: ENABLE_SIGNALS();
666: GC_INVOKE_FINALIZERS();
667: DISABLE_SIGNALS();
668: LOCK();
669: }
670: UNLOCK();
671: ENABLE_SIGNALS();
672: }
673: #endif
674:
675: /* Invoke finalizers for all objects that are ready to be finalized. */
676: /* Should be called without allocation lock. */
677: int GC_invoke_finalizers()
678: {
679: register struct finalizable_object * curr_fo;
680: register int count = 0;
681: DCL_LOCK_STATE;
682:
683: while (GC_finalize_now != 0) {
684: # ifdef THREADS
685: DISABLE_SIGNALS();
686: LOCK();
687: # endif
688: curr_fo = GC_finalize_now;
689: # ifdef THREADS
690: if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
691: UNLOCK();
692: ENABLE_SIGNALS();
693: if (curr_fo == 0) break;
694: # else
695: GC_finalize_now = fo_next(curr_fo);
696: # endif
697: fo_set_next(curr_fo, 0);
698: (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
699: curr_fo -> fo_client_data);
700: curr_fo -> fo_client_data = 0;
701: ++count;
702: # ifdef UNDEFINED
703: /* This is probably a bad idea. It throws off accounting if */
704: /* nearly all objects are finalizable. O.w. it shouldn't */
705: /* matter. */
706: GC_free((GC_PTR)curr_fo);
707: # endif
708: }
709: return count;
710: }
711:
712: # ifdef __STDC__
713: GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
714: GC_PTR client_data)
715: # else
716: GC_PTR GC_call_with_alloc_lock(fn, client_data)
717: GC_fn_type fn;
718: GC_PTR client_data;
719: # endif
720: {
721: GC_PTR result;
722: DCL_LOCK_STATE;
723:
724: # ifdef THREADS
725: DISABLE_SIGNALS();
726: LOCK();
727: SET_LOCK_HOLDER();
728: # endif
729: result = (*fn)(client_data);
730: # ifdef THREADS
731: UNSET_LOCK_HOLDER();
732: UNLOCK();
733: ENABLE_SIGNALS();
734: # endif
735: return(result);
736: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>