Annotation of OpenXM_contrib2/asir2000/gc/finalize.c, Revision 1.7
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.
1.2 noro 4: * Copyright (c) 1996-1999 by Silicon Graphics. All rights reserved.
1.1 noro 5:
6: * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
7: * OR IMPLIED. ANY USE IS AT YOUR OWN RISK.
8: *
9: * Permission is hereby granted to use or copy this program
10: * for any purpose, provided the above notices are retained on all copies.
11: * Permission to modify the code and to distribute modified code is granted,
12: * provided the above notices are retained, and a notice that the code was
13: * modified is included with the above copyright notice.
14: */
15: /* Boehm, February 1, 1996 1:19 pm PST */
16: # define I_HIDE_POINTERS
1.4 noro 17: # include "private/gc_pmark.h"
1.1 noro 18:
1.2 noro 19: # ifdef FINALIZE_ON_DEMAND
20: int GC_finalize_on_demand = 1;
21: # else
22: int GC_finalize_on_demand = 0;
23: # endif
24:
25: # ifdef JAVA_FINALIZATION
26: int GC_java_finalization = 1;
27: # else
28: int GC_java_finalization = 0;
29: # endif
30:
1.1 noro 31: /* Type of mark procedure used for marking from finalizable object. */
32: /* This procedure normally does not mark the object, only its */
33: /* descendents. */
34: typedef void finalization_mark_proc(/* ptr_t finalizable_obj_ptr */);
35:
36: # define HASH3(addr,size,log_size) \
37: ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \
38: & ((size) - 1))
39: #define HASH2(addr,log_size) HASH3(addr, 1 << log_size, log_size)
40:
41: struct hash_chain_entry {
42: word hidden_key;
43: struct hash_chain_entry * next;
44: };
45:
46: unsigned GC_finalization_failures = 0;
47: /* Number of finalization requests that failed for lack of memory. */
48:
49: static struct disappearing_link {
50: struct hash_chain_entry prolog;
51: # define dl_hidden_link prolog.hidden_key
52: /* Field to be cleared. */
53: # define dl_next(x) (struct disappearing_link *)((x) -> prolog.next)
54: # define dl_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
55:
56: word dl_hidden_obj; /* Pointer to object base */
57: } **dl_head = 0;
58:
59: static signed_word log_dl_table_size = -1;
60: /* Binary log of */
61: /* current size of array pointed to by dl_head. */
62: /* -1 ==> size is 0. */
63:
64: word GC_dl_entries = 0; /* Number of entries currently in disappearing */
65: /* link table. */
66:
67: static struct finalizable_object {
68: struct hash_chain_entry prolog;
69: # define fo_hidden_base prolog.hidden_key
70: /* Pointer to object base. */
71: /* No longer hidden once object */
72: /* is on finalize_now queue. */
73: # define fo_next(x) (struct finalizable_object *)((x) -> prolog.next)
74: # define fo_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
75: GC_finalization_proc fo_fn; /* Finalizer. */
76: ptr_t fo_client_data;
77: word fo_object_size; /* In bytes. */
78: finalization_mark_proc * fo_mark_proc; /* Mark-through procedure */
79: } **fo_head = 0;
80:
81: struct finalizable_object * GC_finalize_now = 0;
82: /* LIst of objects that should be finalized now. */
83:
84: static signed_word log_fo_table_size = -1;
85:
86: word GC_fo_entries = 0;
87:
1.4 noro 88: void GC_push_finalizer_structures GC_PROTO((void))
1.1 noro 89: {
90: GC_push_all((ptr_t)(&dl_head), (ptr_t)(&dl_head) + sizeof(word));
91: GC_push_all((ptr_t)(&fo_head), (ptr_t)(&fo_head) + sizeof(word));
1.4 noro 92: GC_push_all((ptr_t)(&GC_finalize_now),
93: (ptr_t)(&GC_finalize_now) + sizeof(word));
1.1 noro 94: }
95:
96: /* Double the size of a hash table. *size_ptr is the log of its current */
97: /* size. May be a noop. */
98: /* *table is a pointer to an array of hash headers. If we succeed, we */
99: /* update both *table and *log_size_ptr. */
100: /* Lock is held. Signals are disabled. */
101: void GC_grow_table(table, log_size_ptr)
102: struct hash_chain_entry ***table;
103: signed_word * log_size_ptr;
104: {
105: register word i;
106: register struct hash_chain_entry *p;
107: int log_old_size = *log_size_ptr;
108: register int log_new_size = log_old_size + 1;
109: word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
110: register word new_size = 1 << log_new_size;
111: struct hash_chain_entry **new_table = (struct hash_chain_entry **)
1.4 noro 112: GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
1.1 noro 113: (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
114:
115: if (new_table == 0) {
116: if (table == 0) {
117: ABORT("Insufficient space for initial table allocation");
118: } else {
119: return;
120: }
121: }
122: for (i = 0; i < old_size; i++) {
123: p = (*table)[i];
124: while (p != 0) {
125: register ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
126: register struct hash_chain_entry *next = p -> next;
127: register int new_hash = HASH3(real_key, new_size, log_new_size);
128:
129: p -> next = new_table[new_hash];
130: new_table[new_hash] = p;
131: p = next;
132: }
133: }
134: *log_size_ptr = log_new_size;
135: *table = new_table;
136: }
137:
138: # if defined(__STDC__) || defined(__cplusplus)
139: int GC_register_disappearing_link(GC_PTR * link)
140: # else
141: int GC_register_disappearing_link(link)
142: GC_PTR * link;
143: # endif
144: {
145: ptr_t base;
146:
147: base = (ptr_t)GC_base((GC_PTR)link);
148: if (base == 0)
149: ABORT("Bad arg to GC_register_disappearing_link");
150: return(GC_general_register_disappearing_link(link, base));
151: }
152:
153: # if defined(__STDC__) || defined(__cplusplus)
154: int GC_general_register_disappearing_link(GC_PTR * link,
155: GC_PTR obj)
156: # else
157: int GC_general_register_disappearing_link(link, obj)
158: GC_PTR * link;
159: GC_PTR obj;
160: # endif
161:
162: {
163: struct disappearing_link *curr_dl;
164: int index;
165: struct disappearing_link * new_dl;
166: DCL_LOCK_STATE;
167:
168: if ((word)link & (ALIGNMENT-1))
169: ABORT("Bad arg to GC_general_register_disappearing_link");
170: # ifdef THREADS
171: DISABLE_SIGNALS();
172: LOCK();
173: # endif
174: if (log_dl_table_size == -1
175: || GC_dl_entries > ((word)1 << log_dl_table_size)) {
176: # ifndef THREADS
177: DISABLE_SIGNALS();
178: # endif
179: GC_grow_table((struct hash_chain_entry ***)(&dl_head),
180: &log_dl_table_size);
1.4 noro 181: # ifdef CONDPRINT
182: if (GC_print_stats) {
1.1 noro 183: GC_printf1("Grew dl table to %lu entries\n",
184: (unsigned long)(1 << log_dl_table_size));
1.4 noro 185: }
1.1 noro 186: # endif
187: # ifndef THREADS
188: ENABLE_SIGNALS();
189: # endif
190: }
191: index = HASH2(link, log_dl_table_size);
192: curr_dl = dl_head[index];
193: for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
194: if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
195: curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
196: # ifdef THREADS
197: UNLOCK();
198: ENABLE_SIGNALS();
199: # endif
200: return(1);
201: }
202: }
1.4 noro 203: new_dl = (struct disappearing_link *)
204: GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL);
1.6 noro 205: if (0 == new_dl) {
206: # ifdef THREADS
207: UNLOCK();
208: ENABLE_SIGNALS();
209: # endif
210: new_dl = (struct disappearing_link *)
211: GC_oom_fn(sizeof(struct disappearing_link));
212: if (0 == new_dl) {
213: GC_finalization_failures++;
214: return(0);
215: }
216: /* It's not likely we'll make it here, but ... */
217: # ifdef THREADS
218: DISABLE_SIGNALS();
219: LOCK();
220: # endif
1.1 noro 221: }
1.6 noro 222: new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
223: new_dl -> dl_hidden_link = HIDE_POINTER(link);
224: dl_set_next(new_dl, dl_head[index]);
225: dl_head[index] = new_dl;
226: GC_dl_entries++;
1.1 noro 227: # ifdef THREADS
228: UNLOCK();
229: ENABLE_SIGNALS();
230: # endif
231: return(0);
232: }
233:
234: # if defined(__STDC__) || defined(__cplusplus)
235: int GC_unregister_disappearing_link(GC_PTR * link)
236: # else
237: int GC_unregister_disappearing_link(link)
238: GC_PTR * link;
239: # endif
240: {
241: struct disappearing_link *curr_dl, *prev_dl;
242: int index;
243: DCL_LOCK_STATE;
244:
245: DISABLE_SIGNALS();
246: LOCK();
247: index = HASH2(link, log_dl_table_size);
248: if (((unsigned long)link & (ALIGNMENT-1))) goto out;
249: prev_dl = 0; curr_dl = dl_head[index];
250: while (curr_dl != 0) {
251: if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
252: if (prev_dl == 0) {
253: dl_head[index] = dl_next(curr_dl);
254: } else {
255: dl_set_next(prev_dl, dl_next(curr_dl));
256: }
257: GC_dl_entries--;
258: UNLOCK();
259: ENABLE_SIGNALS();
1.4 noro 260: # ifdef DBG_HDRS_ALL
1.6 noro 261: dl_set_next(curr_dl, 0);
1.4 noro 262: # else
263: GC_free((GC_PTR)curr_dl);
264: # endif
1.1 noro 265: return(1);
266: }
267: prev_dl = curr_dl;
268: curr_dl = dl_next(curr_dl);
269: }
270: out:
271: UNLOCK();
272: ENABLE_SIGNALS();
273: return(0);
274: }
275:
276: /* Possible finalization_marker procedures. Note that mark stack */
277: /* overflow is handled by the caller, and is not a disaster. */
1.2 noro 278: GC_API void GC_normal_finalize_mark_proc(p)
1.1 noro 279: ptr_t p;
280: {
281: hdr * hhdr = HDR(p);
282:
283: PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
284: &(GC_mark_stack[GC_mark_stack_size]));
285: }
286:
287: /* This only pays very partial attention to the mark descriptor. */
288: /* It does the right thing for normal and atomic objects, and treats */
289: /* most others as normal. */
1.2 noro 290: GC_API void GC_ignore_self_finalize_mark_proc(p)
1.1 noro 291: ptr_t p;
292: {
293: hdr * hhdr = HDR(p);
294: word descr = hhdr -> hb_descr;
295: ptr_t q, r;
296: ptr_t scan_limit;
297: ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
298:
1.4 noro 299: if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
1.1 noro 300: scan_limit = p + descr - sizeof(word);
301: } else {
302: scan_limit = target_limit + 1 - sizeof(word);
303: }
304: for (q = p; q <= scan_limit; q += ALIGNMENT) {
305: r = *(ptr_t *)q;
306: if (r < p || r > target_limit) {
307: GC_PUSH_ONE_HEAP((word)r, q);
308: }
309: }
310: }
311:
312: /*ARGSUSED*/
1.2 noro 313: GC_API void GC_null_finalize_mark_proc(p)
1.1 noro 314: ptr_t p;
315: {
316: }
317:
318:
319:
320: /* Register a finalization function. See gc.h for details. */
321: /* in the nonthreads case, we try to avoid disabling signals, */
322: /* since it can be expensive. Threads packages typically */
323: /* make it cheaper. */
1.2 noro 324: /* The last parameter is a procedure that determines */
325: /* marking for finalization ordering. Any objects marked */
326: /* by that procedure will be guaranteed to not have been */
327: /* finalized when this finalizer is invoked. */
328: GC_API void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
1.1 noro 329: GC_PTR obj;
330: GC_finalization_proc fn;
331: GC_PTR cd;
332: GC_finalization_proc * ofn;
333: GC_PTR * ocd;
334: finalization_mark_proc * mp;
335: {
336: ptr_t base;
337: struct finalizable_object * curr_fo, * prev_fo;
338: int index;
339: struct finalizable_object *new_fo;
1.4 noro 340: hdr *hhdr;
1.1 noro 341: DCL_LOCK_STATE;
342:
343: # ifdef THREADS
344: DISABLE_SIGNALS();
345: LOCK();
346: # endif
347: if (log_fo_table_size == -1
348: || GC_fo_entries > ((word)1 << log_fo_table_size)) {
349: # ifndef THREADS
350: DISABLE_SIGNALS();
351: # endif
352: GC_grow_table((struct hash_chain_entry ***)(&fo_head),
353: &log_fo_table_size);
1.4 noro 354: # ifdef CONDPRINT
355: if (GC_print_stats) {
1.1 noro 356: GC_printf1("Grew fo table to %lu entries\n",
357: (unsigned long)(1 << log_fo_table_size));
1.4 noro 358: }
1.1 noro 359: # endif
360: # ifndef THREADS
361: ENABLE_SIGNALS();
362: # endif
363: }
364: /* in the THREADS case signals are disabled and we hold allocation */
365: /* lock; otherwise neither is true. Proceed carefully. */
366: base = (ptr_t)obj;
367: index = HASH2(base, log_fo_table_size);
368: prev_fo = 0; curr_fo = fo_head[index];
369: while (curr_fo != 0) {
370: if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
371: /* Interruption by a signal in the middle of this */
372: /* should be safe. The client may see only *ocd */
373: /* updated, but we'll declare that to be his */
374: /* problem. */
375: if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
376: if (ofn) *ofn = curr_fo -> fo_fn;
377: /* Delete the structure for base. */
378: if (prev_fo == 0) {
379: fo_head[index] = fo_next(curr_fo);
380: } else {
381: fo_set_next(prev_fo, fo_next(curr_fo));
382: }
383: if (fn == 0) {
384: GC_fo_entries--;
385: /* May not happen if we get a signal. But a high */
386: /* estimate will only make the table larger than */
387: /* necessary. */
1.4 noro 388: # if !defined(THREADS) && !defined(DBG_HDRS_ALL)
1.1 noro 389: GC_free((GC_PTR)curr_fo);
390: # endif
391: } else {
392: curr_fo -> fo_fn = fn;
393: curr_fo -> fo_client_data = (ptr_t)cd;
394: curr_fo -> fo_mark_proc = mp;
395: /* Reinsert it. We deleted it first to maintain */
396: /* consistency in the event of a signal. */
397: if (prev_fo == 0) {
398: fo_head[index] = curr_fo;
399: } else {
400: fo_set_next(prev_fo, curr_fo);
401: }
402: }
403: # ifdef THREADS
404: UNLOCK();
405: ENABLE_SIGNALS();
406: # endif
407: return;
408: }
409: prev_fo = curr_fo;
410: curr_fo = fo_next(curr_fo);
411: }
412: if (ofn) *ofn = 0;
413: if (ocd) *ocd = 0;
414: if (fn == 0) {
415: # ifdef THREADS
416: UNLOCK();
417: ENABLE_SIGNALS();
418: # endif
419: return;
420: }
1.4 noro 421: GET_HDR(base, hhdr);
422: if (0 == hhdr) {
423: /* We won't collect it, hence finalizer wouldn't be run. */
424: # ifdef THREADS
425: UNLOCK();
426: ENABLE_SIGNALS();
427: # endif
428: return;
429: }
430: new_fo = (struct finalizable_object *)
431: GC_INTERNAL_MALLOC(sizeof(struct finalizable_object),NORMAL);
1.6 noro 432: if (0 == new_fo) {
433: # ifdef THREADS
434: UNLOCK();
435: ENABLE_SIGNALS();
436: # endif
437: new_fo = (struct finalizable_object *)
438: GC_oom_fn(sizeof(struct finalizable_object));
439: if (0 == new_fo) {
440: GC_finalization_failures++;
441: return;
442: }
443: /* It's not likely we'll make it here, but ... */
444: # ifdef THREADS
445: DISABLE_SIGNALS();
446: LOCK();
447: # endif
1.1 noro 448: }
1.6 noro 449: new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
450: new_fo -> fo_fn = fn;
451: new_fo -> fo_client_data = (ptr_t)cd;
452: new_fo -> fo_object_size = hhdr -> hb_sz;
453: new_fo -> fo_mark_proc = mp;
454: fo_set_next(new_fo, fo_head[index]);
455: GC_fo_entries++;
456: fo_head[index] = new_fo;
1.1 noro 457: # ifdef THREADS
458: UNLOCK();
459: ENABLE_SIGNALS();
460: # endif
461: }
462:
463: # if defined(__STDC__)
464: void GC_register_finalizer(void * obj,
465: GC_finalization_proc fn, void * cd,
466: GC_finalization_proc *ofn, void ** ocd)
467: # else
468: void GC_register_finalizer(obj, fn, cd, ofn, ocd)
469: GC_PTR obj;
470: GC_finalization_proc fn;
471: GC_PTR cd;
472: GC_finalization_proc * ofn;
473: GC_PTR * ocd;
474: # endif
475: {
476: GC_register_finalizer_inner(obj, fn, cd, ofn,
477: ocd, GC_normal_finalize_mark_proc);
478: }
479:
480: # if defined(__STDC__)
481: void GC_register_finalizer_ignore_self(void * obj,
482: GC_finalization_proc fn, void * cd,
483: GC_finalization_proc *ofn, void ** ocd)
484: # else
485: void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
486: GC_PTR obj;
487: GC_finalization_proc fn;
488: GC_PTR cd;
489: GC_finalization_proc * ofn;
490: GC_PTR * ocd;
491: # endif
492: {
493: GC_register_finalizer_inner(obj, fn, cd, ofn,
494: ocd, GC_ignore_self_finalize_mark_proc);
495: }
496:
497: # if defined(__STDC__)
498: void GC_register_finalizer_no_order(void * obj,
499: GC_finalization_proc fn, void * cd,
500: GC_finalization_proc *ofn, void ** ocd)
501: # else
502: void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
503: GC_PTR obj;
504: GC_finalization_proc fn;
505: GC_PTR cd;
506: GC_finalization_proc * ofn;
507: GC_PTR * ocd;
508: # endif
509: {
510: GC_register_finalizer_inner(obj, fn, cd, ofn,
511: ocd, GC_null_finalize_mark_proc);
512: }
513:
1.4 noro 514: #ifndef NO_DEBUGGING
515: void GC_dump_finalization()
516: {
517: struct disappearing_link * curr_dl;
518: struct finalizable_object * curr_fo;
519: ptr_t real_ptr, real_link;
520: int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
521: int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
522: int i;
523:
524: GC_printf0("Disappearing links:\n");
525: for (i = 0; i < dl_size; i++) {
526: for (curr_dl = dl_head[i]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
527: real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
528: real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
529: GC_printf2("Object: 0x%lx, Link:0x%lx\n", real_ptr, real_link);
530: }
531: }
532: GC_printf0("Finalizers:\n");
533: for (i = 0; i < fo_size; i++) {
534: for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
535: real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
536: GC_printf1("Finalizable object: 0x%lx\n", real_ptr);
537: }
538: }
539: }
540: #endif
541:
1.1 noro 542: /* Called with world stopped. Cause disappearing links to disappear, */
543: /* and invoke finalizers. */
544: void GC_finalize()
545: {
546: struct disappearing_link * curr_dl, * prev_dl, * next_dl;
547: struct finalizable_object * curr_fo, * prev_fo, * next_fo;
548: ptr_t real_ptr, real_link;
549: register int i;
550: int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
551: int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
552:
553: /* Make disappearing links disappear */
554: for (i = 0; i < dl_size; i++) {
555: curr_dl = dl_head[i];
556: prev_dl = 0;
557: while (curr_dl != 0) {
558: real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
559: real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
560: if (!GC_is_marked(real_ptr)) {
561: *(word *)real_link = 0;
562: next_dl = dl_next(curr_dl);
563: if (prev_dl == 0) {
564: dl_head[i] = next_dl;
565: } else {
566: dl_set_next(prev_dl, next_dl);
567: }
568: GC_clear_mark_bit((ptr_t)curr_dl);
569: GC_dl_entries--;
570: curr_dl = next_dl;
571: } else {
572: prev_dl = curr_dl;
573: curr_dl = dl_next(curr_dl);
574: }
575: }
576: }
577: /* Mark all objects reachable via chains of 1 or more pointers */
578: /* from finalizable objects. */
1.4 noro 579: GC_ASSERT(GC_mark_state == MS_NONE);
1.1 noro 580: for (i = 0; i < fo_size; i++) {
581: for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
582: real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
583: if (!GC_is_marked(real_ptr)) {
584: GC_MARKED_FOR_FINALIZATION(real_ptr);
585: GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
586: if (GC_is_marked(real_ptr)) {
587: WARN("Finalization cycle involving %lx\n", real_ptr);
588: }
589: }
590: }
591: }
592: /* Enqueue for finalization all objects that are still */
593: /* unreachable. */
594: GC_words_finalized = 0;
595: for (i = 0; i < fo_size; i++) {
596: curr_fo = fo_head[i];
597: prev_fo = 0;
598: while (curr_fo != 0) {
599: real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
600: if (!GC_is_marked(real_ptr)) {
1.2 noro 601: if (!GC_java_finalization) {
602: GC_set_mark_bit(real_ptr);
603: }
1.1 noro 604: /* Delete from hash table */
605: next_fo = fo_next(curr_fo);
606: if (prev_fo == 0) {
607: fo_head[i] = next_fo;
608: } else {
609: fo_set_next(prev_fo, next_fo);
610: }
611: GC_fo_entries--;
612: /* Add to list of objects awaiting finalization. */
613: fo_set_next(curr_fo, GC_finalize_now);
614: GC_finalize_now = curr_fo;
615: /* unhide object pointer so any future collections will */
616: /* see it. */
617: curr_fo -> fo_hidden_base =
618: (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
619: GC_words_finalized +=
620: ALIGNED_WORDS(curr_fo -> fo_object_size)
621: + ALIGNED_WORDS(sizeof(struct finalizable_object));
1.6 noro 622: GC_ASSERT(GC_is_marked(GC_base((ptr_t)curr_fo)));
1.1 noro 623: curr_fo = next_fo;
624: } else {
625: prev_fo = curr_fo;
626: curr_fo = fo_next(curr_fo);
627: }
628: }
629: }
630:
1.2 noro 631: if (GC_java_finalization) {
632: /* make sure we mark everything reachable from objects finalized
633: using the no_order mark_proc */
634: for (curr_fo = GC_finalize_now;
635: curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
636: real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
637: if (!GC_is_marked(real_ptr)) {
638: if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
639: GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
640: }
641: GC_set_mark_bit(real_ptr);
642: }
643: }
644: }
1.1 noro 645:
646: /* Remove dangling disappearing links. */
647: for (i = 0; i < dl_size; i++) {
648: curr_dl = dl_head[i];
649: prev_dl = 0;
650: while (curr_dl != 0) {
651: real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
652: if (real_link != 0 && !GC_is_marked(real_link)) {
653: next_dl = dl_next(curr_dl);
654: if (prev_dl == 0) {
655: dl_head[i] = next_dl;
656: } else {
657: dl_set_next(prev_dl, next_dl);
658: }
659: GC_clear_mark_bit((ptr_t)curr_dl);
660: GC_dl_entries--;
661: curr_dl = next_dl;
662: } else {
663: prev_dl = curr_dl;
664: curr_dl = dl_next(curr_dl);
665: }
666: }
667: }
668: }
669:
1.2 noro 670: #ifndef JAVA_FINALIZATION_NOT_NEEDED
1.1 noro 671:
672: /* Enqueue all remaining finalizers to be run - Assumes lock is
673: * held, and signals are disabled */
674: void GC_enqueue_all_finalizers()
675: {
676: struct finalizable_object * curr_fo, * prev_fo, * next_fo;
1.3 noro 677: ptr_t real_ptr;
1.1 noro 678: register int i;
679: int fo_size;
680:
681: fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
682: GC_words_finalized = 0;
683: for (i = 0; i < fo_size; i++) {
684: curr_fo = fo_head[i];
685: prev_fo = 0;
686: while (curr_fo != 0) {
687: real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
688: GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
689: GC_set_mark_bit(real_ptr);
690:
691: /* Delete from hash table */
692: next_fo = fo_next(curr_fo);
693: if (prev_fo == 0) {
694: fo_head[i] = next_fo;
695: } else {
696: fo_set_next(prev_fo, next_fo);
697: }
698: GC_fo_entries--;
699:
700: /* Add to list of objects awaiting finalization. */
701: fo_set_next(curr_fo, GC_finalize_now);
702: GC_finalize_now = curr_fo;
703:
704: /* unhide object pointer so any future collections will */
705: /* see it. */
706: curr_fo -> fo_hidden_base =
707: (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
708:
709: GC_words_finalized +=
710: ALIGNED_WORDS(curr_fo -> fo_object_size)
711: + ALIGNED_WORDS(sizeof(struct finalizable_object));
712: curr_fo = next_fo;
713: }
714: }
715:
716: return;
717: }
718:
719: /* Invoke all remaining finalizers that haven't yet been run.
720: * This is needed for strict compliance with the Java standard,
721: * which can make the runtime guarantee that all finalizers are run.
722: * Unfortunately, the Java standard implies we have to keep running
723: * finalizers until there are no more left, a potential infinite loop.
724: * YUCK.
1.2 noro 725: * Note that this is even more dangerous than the usual Java
726: * finalizers, in that objects reachable from static variables
727: * may have been finalized when these finalizers are run.
728: * Finalizers run at this point must be prepared to deal with a
729: * mostly broken world.
1.1 noro 730: * This routine is externally callable, so is called without
731: * the allocation lock.
732: */
1.2 noro 733: GC_API void GC_finalize_all()
1.1 noro 734: {
735: DCL_LOCK_STATE;
736:
737: DISABLE_SIGNALS();
738: LOCK();
739: while (GC_fo_entries > 0) {
740: GC_enqueue_all_finalizers();
741: UNLOCK();
742: ENABLE_SIGNALS();
743: GC_INVOKE_FINALIZERS();
744: DISABLE_SIGNALS();
745: LOCK();
746: }
747: UNLOCK();
748: ENABLE_SIGNALS();
749: }
750: #endif
1.3 noro 751:
752: /* Returns true if it is worth calling GC_invoke_finalizers. (Useful if */
753: /* finalizers can only be called from some kind of `safe state' and */
754: /* getting into that safe state is expensive.) */
755: int GC_should_invoke_finalizers GC_PROTO((void))
756: {
757: return GC_finalize_now != 0;
758: }
1.1 noro 759:
760: /* Invoke finalizers for all objects that are ready to be finalized. */
761: /* Should be called without allocation lock. */
762: int GC_invoke_finalizers()
763: {
1.6 noro 764: struct finalizable_object * curr_fo;
765: int count = 0;
766: word mem_freed_before;
1.1 noro 767: DCL_LOCK_STATE;
768:
769: while (GC_finalize_now != 0) {
770: # ifdef THREADS
771: DISABLE_SIGNALS();
772: LOCK();
773: # endif
1.7 ! noro 774: if (count == 0) {
1.6 noro 775: mem_freed_before = GC_mem_freed;
776: }
1.1 noro 777: curr_fo = GC_finalize_now;
778: # ifdef THREADS
779: if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
780: UNLOCK();
781: ENABLE_SIGNALS();
782: if (curr_fo == 0) break;
783: # else
784: GC_finalize_now = fo_next(curr_fo);
785: # endif
786: fo_set_next(curr_fo, 0);
787: (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
788: curr_fo -> fo_client_data);
789: curr_fo -> fo_client_data = 0;
790: ++count;
791: # ifdef UNDEFINED
792: /* This is probably a bad idea. It throws off accounting if */
793: /* nearly all objects are finalizable. O.w. it shouldn't */
794: /* matter. */
795: GC_free((GC_PTR)curr_fo);
796: # endif
797: }
1.7 ! noro 798: if (count != 0 && mem_freed_before != GC_mem_freed) {
1.6 noro 799: LOCK();
800: GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
801: UNLOCK();
802: }
1.1 noro 803: return count;
804: }
805:
1.4 noro 806: void (* GC_finalizer_notifier)() = (void (*) GC_PROTO((void)))0;
807:
808: static GC_word last_finalizer_notification = 0;
809:
810: void GC_notify_or_invoke_finalizers GC_PROTO((void))
811: {
812: if (GC_finalize_now == 0) return;
813: if (!GC_finalize_on_demand) {
814: (void) GC_invoke_finalizers();
1.7 ! noro 815: # ifndef THREADS
! 816: GC_ASSERT(GC_finalize_now == 0);
! 817: # endif /* Otherwise GC can run concurrently and add more */
1.4 noro 818: return;
819: }
820: if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
821: && last_finalizer_notification != GC_gc_no) {
822: last_finalizer_notification = GC_gc_no;
823: GC_finalizer_notifier();
824: }
825: }
826:
1.1 noro 827: # ifdef __STDC__
828: GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
829: GC_PTR client_data)
830: # else
831: GC_PTR GC_call_with_alloc_lock(fn, client_data)
832: GC_fn_type fn;
833: GC_PTR client_data;
834: # endif
835: {
836: GC_PTR result;
837: DCL_LOCK_STATE;
838:
839: # ifdef THREADS
840: DISABLE_SIGNALS();
841: LOCK();
842: SET_LOCK_HOLDER();
843: # endif
844: result = (*fn)(client_data);
845: # ifdef THREADS
1.4 noro 846: # ifndef GC_ASSERTIONS
847: UNSET_LOCK_HOLDER();
848: # endif /* o.w. UNLOCK() does it implicitly */
1.1 noro 849: UNLOCK();
850: ENABLE_SIGNALS();
851: # endif
852: return(result);
853: }
1.6 noro 854:
1.7 ! noro 855: #if !defined(NO_DEBUGGING)
! 856:
! 857: void GC_print_finalization_stats()
! 858: {
! 859: struct finalizable_object *fo = GC_finalize_now;
! 860: size_t ready = 0;
! 861:
! 862: GC_printf2("%lu finalization table entries; %lu disappearing links\n",
! 863: GC_fo_entries, GC_dl_entries);
! 864: for (; 0 != fo; fo = fo_next(fo)) ++ready;
! 865: GC_printf1("%lu objects are eligible for immediate finalization\n", ready);
! 866: }
! 867:
! 868: #endif /* NO_DEBUGGING */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>