Back to index

lightning-sunbird  0.9+nobinonly
finalize.c
Go to the documentation of this file.
00001 /*
00002  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
00003  * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
00004 
00005  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00006  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00007  *
00008  * Permission is hereby granted to use or copy this program
00009  * for any purpose,  provided the above notices are retained on all copies.
00010  * Permission to modify the code and to distribute modified code is granted,
00011  * provided the above notices are retained, and a notice that the code was
00012  * modified is included with the above copyright notice.
00013  */
00014 /* Boehm, February 1, 1996 1:19 pm PST */
00015 # define I_HIDE_POINTERS
00016 # include "gc_priv.h"
00017 # include "gc_mark.h"
00018 
00019 /* Type of mark procedure used for marking from finalizable object.   */
00020 /* This procedure normally does not mark the object, only its         */
00021 /* descendents.                                                       */
00022 typedef void finalization_mark_proc(/* ptr_t finalizable_obj_ptr */); 
00023 
00024 # define HASH3(addr,size,log_size) \
00025     ((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \
00026     & ((size) - 1))
00027 #define HASH2(addr,log_size) HASH3(addr, 1 << log_size, log_size)
00028 
00029 struct hash_chain_entry {
00030     word hidden_key;
00031     struct hash_chain_entry * next;
00032 };
00033 
00034 unsigned GC_finalization_failures = 0;
00035        /* Number of finalization requests that failed for lack of memory. */
00036 
00037 static struct disappearing_link {
00038     struct hash_chain_entry prolog;
00039 #   define dl_hidden_link prolog.hidden_key
00040                             /* Field to be cleared.            */
00041 #   define dl_next(x) (struct disappearing_link *)((x) -> prolog.next)
00042 #   define dl_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
00043 
00044     word dl_hidden_obj;            /* Pointer to object base   */
00045 } **dl_head = 0;
00046 
00047 static signed_word log_dl_table_size = -1;
00048                      /* Binary log of                          */
00049                      /* current size of array pointed to by dl_head.  */
00050                      /* -1 ==> size is 0.                      */
00051 
00052 word GC_dl_entries = 0;     /* Number of entries currently in disappearing   */
00053                      /* link table.                                   */
00054 
00055 static struct finalizable_object {
00056     struct hash_chain_entry prolog;
00057 #   define fo_hidden_base prolog.hidden_key
00058                             /* Pointer to object base.  */
00059                             /* No longer hidden once object */
00060                             /* is on finalize_now queue.       */
00061 #   define fo_next(x) (struct finalizable_object *)((x) -> prolog.next)
00062 #   define fo_set_next(x,y) (x) -> prolog.next = (struct hash_chain_entry *)(y)
00063     GC_finalization_proc fo_fn;    /* Finalizer.               */
00064     ptr_t fo_client_data;
00065     word fo_object_size;    /* In bytes.                */
00066     finalization_mark_proc * fo_mark_proc;       /* Mark-through procedure */
00067 } **fo_head = 0;
00068 
00069 struct finalizable_object * GC_finalize_now = 0;
00070        /* LIst of objects that should be finalized now. */
00071 
00072 static signed_word log_fo_table_size = -1;
00073 
00074 word GC_fo_entries = 0;
00075 
00076 # ifdef SRC_M3
00077 void GC_push_finalizer_structures()
00078 {
00079     GC_push_all((ptr_t)(&dl_head), (ptr_t)(&dl_head) + sizeof(word));
00080     GC_push_all((ptr_t)(&fo_head), (ptr_t)(&fo_head) + sizeof(word));
00081 }
00082 # endif
00083 
00084 /* Double the size of a hash table. *size_ptr is the log of its current      */
00085 /* size.  May be a noop.                                       */
00086 /* *table is a pointer to an array of hash headers.  If we succeed, we       */
00087 /* update both *table and *log_size_ptr.                       */
00088 /* Lock is held.  Signals are disabled.                               */
00089 void GC_grow_table(table, log_size_ptr)
00090 struct hash_chain_entry ***table;
00091 signed_word * log_size_ptr;
00092 {
00093     register word i;
00094     register struct hash_chain_entry *p;
00095     int log_old_size = *log_size_ptr;
00096     register int log_new_size = log_old_size + 1;
00097     word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
00098     register word new_size = 1 << log_new_size;
00099     struct hash_chain_entry **new_table = (struct hash_chain_entry **)
00100        GC_generic_malloc_inner_ignore_off_page(
00101               (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
00102     
00103     if (new_table == 0) {
00104        if (table == 0) {
00105            ABORT("Insufficient space for initial table allocation");
00106        } else {
00107            return;
00108        }
00109     }
00110     for (i = 0; i < old_size; i++) {
00111       p = (*table)[i];
00112       while (p != 0) {
00113         register ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
00114         register struct hash_chain_entry *next = p -> next;
00115         register int new_hash = HASH3(real_key, new_size, log_new_size);
00116         
00117         p -> next = new_table[new_hash];
00118         new_table[new_hash] = p;
00119         p = next;
00120       }
00121     }
00122     *log_size_ptr = log_new_size;
00123     *table = new_table;
00124 }
00125 
00126 # if defined(__STDC__) || defined(__cplusplus)
00127     int GC_register_disappearing_link(GC_PTR * link)
00128 # else
00129     int GC_register_disappearing_link(link)
00130     GC_PTR * link;
00131 # endif
00132 {
00133     ptr_t base;
00134     
00135     base = (ptr_t)GC_base((GC_PTR)link);
00136     if (base == 0)
00137        ABORT("Bad arg to GC_register_disappearing_link");
00138     return(GC_general_register_disappearing_link(link, base));
00139 }
00140 
00141 # if defined(__STDC__) || defined(__cplusplus)
00142     int GC_general_register_disappearing_link(GC_PTR * link,
00143                                          GC_PTR obj)
00144 # else
00145     int GC_general_register_disappearing_link(link, obj)
00146     GC_PTR * link;
00147     GC_PTR obj;
00148 # endif
00149 
00150 {
00151     struct disappearing_link *curr_dl;
00152     int index;
00153     struct disappearing_link * new_dl;
00154     DCL_LOCK_STATE;
00155     
00156     if ((word)link & (ALIGNMENT-1))
00157        ABORT("Bad arg to GC_general_register_disappearing_link");
00158 #   ifdef THREADS
00159        DISABLE_SIGNALS();
00160        LOCK();
00161 #   endif
00162     if (log_dl_table_size == -1
00163         || GC_dl_entries > ((word)1 << log_dl_table_size)) {
00164 #      ifndef THREADS
00165            DISABLE_SIGNALS();
00166 #      endif
00167        GC_grow_table((struct hash_chain_entry ***)(&dl_head),
00168                     &log_dl_table_size);
00169 #      ifdef PRINTSTATS
00170            GC_printf1("Grew dl table to %lu entries\n",
00171                      (unsigned long)(1 << log_dl_table_size));
00172 #      endif
00173 #      ifndef THREADS
00174            ENABLE_SIGNALS();
00175 #      endif
00176     }
00177     index = HASH2(link, log_dl_table_size);
00178     curr_dl = dl_head[index];
00179     for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
00180         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
00181             curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
00182 #          ifdef THREADS
00183                 UNLOCK();
00184                ENABLE_SIGNALS();
00185 #          endif
00186             return(1);
00187         }
00188     }
00189 #   ifdef THREADS
00190       new_dl = (struct disappearing_link *)
00191        GC_generic_malloc_inner(sizeof(struct disappearing_link),NORMAL);
00192 #   else
00193       new_dl = (struct disappearing_link *)
00194        GC_malloc(sizeof(struct disappearing_link));
00195 #   endif
00196     if (new_dl != 0) {
00197         new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
00198         new_dl -> dl_hidden_link = HIDE_POINTER(link);
00199         dl_set_next(new_dl, dl_head[index]);
00200         dl_head[index] = new_dl;
00201         GC_dl_entries++;
00202     } else {
00203         GC_finalization_failures++;
00204     }
00205 #   ifdef THREADS
00206         UNLOCK();
00207         ENABLE_SIGNALS();
00208 #   endif
00209     return(0);
00210 }
00211 
00212 # if defined(__STDC__) || defined(__cplusplus)
00213     int GC_unregister_disappearing_link(GC_PTR * link)
00214 # else
00215     int GC_unregister_disappearing_link(link)
00216     GC_PTR * link;
00217 # endif
00218 {
00219     struct disappearing_link *curr_dl, *prev_dl;
00220     int index;
00221     DCL_LOCK_STATE;
00222     
00223     DISABLE_SIGNALS();
00224     LOCK();
00225     index = HASH2(link, log_dl_table_size);
00226     if (((unsigned long)link & (ALIGNMENT-1))) goto out;
00227     prev_dl = 0; curr_dl = dl_head[index];
00228     while (curr_dl != 0) {
00229         if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
00230             if (prev_dl == 0) {
00231                 dl_head[index] = dl_next(curr_dl);
00232             } else {
00233                 dl_set_next(prev_dl, dl_next(curr_dl));
00234             }
00235             GC_dl_entries--;
00236             UNLOCK();
00237            ENABLE_SIGNALS();
00238             GC_free((GC_PTR)curr_dl);
00239             return(1);
00240         }
00241         prev_dl = curr_dl;
00242         curr_dl = dl_next(curr_dl);
00243     }
00244 out:
00245     UNLOCK();
00246     ENABLE_SIGNALS();
00247     return(0);
00248 }
00249 
00250 /* Possible finalization_marker procedures.  Note that mark stack     */
00251 /* overflow is handled by the caller, and is not a disaster.          */
00252 void GC_normal_finalize_mark_proc(p)
00253 ptr_t p;
00254 {
00255     hdr * hhdr = HDR(p);
00256     
00257     PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top,
00258             &(GC_mark_stack[GC_mark_stack_size]));
00259 }
00260 
00261 /* This only pays very partial attention to the mark descriptor.      */
00262 /* It does the right thing for normal and atomic objects, and treats  */
00263 /* most others as normal.                                      */
00264 void GC_ignore_self_finalize_mark_proc(p)
00265 ptr_t p;
00266 {
00267     hdr * hhdr = HDR(p);
00268     word descr = hhdr -> hb_descr;
00269     ptr_t q, r;
00270     ptr_t scan_limit;
00271     ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
00272     
00273     if ((descr & DS_TAGS) == DS_LENGTH) {
00274        scan_limit = p + descr - sizeof(word);
00275     } else {
00276        scan_limit = target_limit + 1 - sizeof(word);
00277     }
00278     for (q = p; q <= scan_limit; q += ALIGNMENT) {
00279        r = *(ptr_t *)q;
00280        if (r < p || r > target_limit) {
00281            GC_PUSH_ONE_HEAP((word)r, q);
00282        }
00283     }
00284 }
00285 
00286 /*ARGSUSED*/
00287 void GC_null_finalize_mark_proc(p)
00288 ptr_t p;
00289 {
00290 }
00291 
00292 
00293 
00294 /* Register a finalization function.  See gc.h for details.    */
00295 /* in the nonthreads case, we try to avoid disabling signals,  */
00296 /* since it can be expensive.  Threads packages typically      */
00297 /* make it cheaper.                                     */
00298 void GC_register_finalizer_inner(obj, fn, cd, ofn, ocd, mp)
00299 GC_PTR obj;
00300 GC_finalization_proc fn;
00301 GC_PTR cd;
00302 GC_finalization_proc * ofn;
00303 GC_PTR * ocd;
00304 finalization_mark_proc * mp;
00305 {
00306     ptr_t base;
00307     struct finalizable_object * curr_fo, * prev_fo;
00308     int index;
00309     struct finalizable_object *new_fo;
00310     DCL_LOCK_STATE;
00311 
00312 #   ifdef THREADS
00313        DISABLE_SIGNALS();
00314        LOCK();
00315 #   endif
00316     if (log_fo_table_size == -1
00317         || GC_fo_entries > ((word)1 << log_fo_table_size)) {
00318 #      ifndef THREADS
00319            DISABLE_SIGNALS();
00320 #      endif
00321        GC_grow_table((struct hash_chain_entry ***)(&fo_head),
00322                     &log_fo_table_size);
00323 #      ifdef PRINTSTATS
00324            GC_printf1("Grew fo table to %lu entries\n",
00325                      (unsigned long)(1 << log_fo_table_size));
00326 #      endif
00327 #      ifndef THREADS
00328            ENABLE_SIGNALS();
00329 #      endif
00330     }
00331     /* in the THREADS case signals are disabled and we hold allocation       */
00332     /* lock; otherwise neither is true.  Proceed carefully.           */
00333     base = (ptr_t)obj;
00334     index = HASH2(base, log_fo_table_size);
00335     prev_fo = 0; curr_fo = fo_head[index];
00336     while (curr_fo != 0) {
00337         if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
00338             /* Interruption by a signal in the middle of this  */
00339             /* should be safe.  The client may see only *ocd   */
00340             /* updated, but we'll declare that to be his       */
00341             /* problem.                                        */
00342             if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
00343             if (ofn) *ofn = curr_fo -> fo_fn;
00344             /* Delete the structure for base. */
00345                 if (prev_fo == 0) {
00346                   fo_head[index] = fo_next(curr_fo);
00347                 } else {
00348                   fo_set_next(prev_fo, fo_next(curr_fo));
00349                 }
00350             if (fn == 0) {
00351                 GC_fo_entries--;
00352                   /* May not happen if we get a signal.  But a high   */
00353                   /* estimate will only make the table larger than    */
00354                   /* necessary.                                       */
00355 #             ifndef THREADS
00356                   GC_free((GC_PTR)curr_fo);
00357 #             endif
00358             } else {
00359                 curr_fo -> fo_fn = fn;
00360                 curr_fo -> fo_client_data = (ptr_t)cd;
00361                 curr_fo -> fo_mark_proc = mp;
00362               /* Reinsert it.  We deleted it first to maintain */
00363               /* consistency in the event of a signal.         */
00364               if (prev_fo == 0) {
00365                   fo_head[index] = curr_fo;
00366                 } else {
00367                   fo_set_next(prev_fo, curr_fo);
00368                 }
00369             }
00370 #          ifdef THREADS
00371                 UNLOCK();
00372               ENABLE_SIGNALS();
00373 #          endif
00374             return;
00375         }
00376         prev_fo = curr_fo;
00377         curr_fo = fo_next(curr_fo);
00378     }
00379     if (ofn) *ofn = 0;
00380     if (ocd) *ocd = 0;
00381     if (fn == 0) {
00382 #      ifdef THREADS
00383             UNLOCK();
00384            ENABLE_SIGNALS();
00385 #      endif
00386         return;
00387     }
00388 #   ifdef THREADS
00389       new_fo = (struct finalizable_object *)
00390        GC_generic_malloc_inner(sizeof(struct finalizable_object),NORMAL);
00391 #   else
00392       new_fo = (struct finalizable_object *)
00393        GC_malloc(sizeof(struct finalizable_object));
00394 #   endif
00395     if (new_fo != 0) {
00396         new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
00397        new_fo -> fo_fn = fn;
00398        new_fo -> fo_client_data = (ptr_t)cd;
00399        new_fo -> fo_object_size = GC_size(base);
00400        new_fo -> fo_mark_proc = mp;
00401        fo_set_next(new_fo, fo_head[index]);
00402        GC_fo_entries++;
00403        fo_head[index] = new_fo;
00404     } else {
00405        GC_finalization_failures++;
00406     }
00407 #   ifdef THREADS
00408         UNLOCK();
00409        ENABLE_SIGNALS();
00410 #   endif
00411 }
00412 
00413 # if defined(__STDC__)
00414     void GC_register_finalizer(void * obj,
00415                             GC_finalization_proc fn, void * cd,
00416                             GC_finalization_proc *ofn, void ** ocd)
00417 # else
00418     void GC_register_finalizer(obj, fn, cd, ofn, ocd)
00419     GC_PTR obj;
00420     GC_finalization_proc fn;
00421     GC_PTR cd;
00422     GC_finalization_proc * ofn;
00423     GC_PTR * ocd;
00424 # endif
00425 {
00426     GC_register_finalizer_inner(obj, fn, cd, ofn,
00427                             ocd, GC_normal_finalize_mark_proc);
00428 }
00429 
00430 # if defined(__STDC__)
00431     void GC_register_finalizer_ignore_self(void * obj,
00432                             GC_finalization_proc fn, void * cd,
00433                             GC_finalization_proc *ofn, void ** ocd)
00434 # else
00435     void GC_register_finalizer_ignore_self(obj, fn, cd, ofn, ocd)
00436     GC_PTR obj;
00437     GC_finalization_proc fn;
00438     GC_PTR cd;
00439     GC_finalization_proc * ofn;
00440     GC_PTR * ocd;
00441 # endif
00442 {
00443     GC_register_finalizer_inner(obj, fn, cd, ofn,
00444                             ocd, GC_ignore_self_finalize_mark_proc);
00445 }
00446 
00447 # if defined(__STDC__)
00448     void GC_register_finalizer_no_order(void * obj,
00449                             GC_finalization_proc fn, void * cd,
00450                             GC_finalization_proc *ofn, void ** ocd)
00451 # else
00452     void GC_register_finalizer_no_order(obj, fn, cd, ofn, ocd)
00453     GC_PTR obj;
00454     GC_finalization_proc fn;
00455     GC_PTR cd;
00456     GC_finalization_proc * ofn;
00457     GC_PTR * ocd;
00458 # endif
00459 {
00460     GC_register_finalizer_inner(obj, fn, cd, ofn,
00461                             ocd, GC_null_finalize_mark_proc);
00462 }
00463 
00464 /* Called with world stopped.  Cause disappearing links to disappear, */
00465 /* and invoke finalizers.                                      */
00466 void GC_finalize()
00467 {
00468     struct disappearing_link * curr_dl, * prev_dl, * next_dl;
00469     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
00470     ptr_t real_ptr, real_link;
00471     register int i;
00472     int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
00473     int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
00474     
00475   /* Make disappearing links disappear */
00476     for (i = 0; i < dl_size; i++) {
00477       curr_dl = dl_head[i];
00478       prev_dl = 0;
00479       while (curr_dl != 0) {
00480         real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
00481         real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
00482         if (!GC_is_marked(real_ptr)) {
00483             *(word *)real_link = 0;
00484             next_dl = dl_next(curr_dl);
00485             if (prev_dl == 0) {
00486                 dl_head[i] = next_dl;
00487             } else {
00488                 dl_set_next(prev_dl, next_dl);
00489             }
00490             GC_clear_mark_bit((ptr_t)curr_dl);
00491             GC_dl_entries--;
00492             curr_dl = next_dl;
00493         } else {
00494             prev_dl = curr_dl;
00495             curr_dl = dl_next(curr_dl);
00496         }
00497       }
00498     }
00499   /* Mark all objects reachable via chains of 1 or more pointers      */
00500   /* from finalizable objects.                                        */
00501 #   ifdef PRINTSTATS
00502         if (GC_mark_state != MS_NONE) ABORT("Bad mark state");
00503 #   endif
00504     for (i = 0; i < fo_size; i++) {
00505       for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
00506         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
00507         if (!GC_is_marked(real_ptr)) {
00508             GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
00509             if (GC_is_marked(real_ptr)) {
00510                 WARN("Finalization cycle involving %lx\n", real_ptr);
00511             }
00512         }
00513       }
00514     }
00515   /* Enqueue for finalization all objects that are still              */
00516   /* unreachable.                                              */
00517     GC_words_finalized = 0;
00518     for (i = 0; i < fo_size; i++) {
00519       curr_fo = fo_head[i];
00520       prev_fo = 0;
00521       while (curr_fo != 0) {
00522         real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
00523         if (!GC_is_marked(real_ptr)) {
00524 #         ifndef JAVA_FINALIZATION
00525             GC_set_mark_bit(real_ptr);
00526 #         endif
00527             /* Delete from hash table */
00528               next_fo = fo_next(curr_fo);
00529               if (prev_fo == 0) {
00530                 fo_head[i] = next_fo;
00531               } else {
00532                 fo_set_next(prev_fo, next_fo);
00533               }
00534               GC_fo_entries--;
00535             /* Add to list of objects awaiting finalization.   */
00536               fo_set_next(curr_fo, GC_finalize_now);
00537               GC_finalize_now = curr_fo;
00538               /* unhide object pointer so any future collections will */
00539               /* see it.                                       */
00540               curr_fo -> fo_hidden_base = 
00541                             (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
00542               GC_words_finalized +=
00543                      ALIGNED_WORDS(curr_fo -> fo_object_size)
00544                             + ALIGNED_WORDS(sizeof(struct finalizable_object));
00545 #          ifdef PRINTSTATS
00546               if (!GC_is_marked((ptr_t)curr_fo)) {
00547                 ABORT("GC_finalize: found accessible unmarked object\n");
00548               }
00549 #          endif
00550             curr_fo = next_fo;
00551         } else {
00552             prev_fo = curr_fo;
00553             curr_fo = fo_next(curr_fo);
00554         }
00555       }
00556     }
00557 
00558 # ifdef JAVA_FINALIZATION
00559   /* make sure we mark everything reachable from objects finalized
00560      using the no_order mark_proc */
00561     for (curr_fo = GC_finalize_now; 
00562         curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
00563        real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
00564        if (!GC_is_marked(real_ptr)) {
00565            if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
00566                GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
00567            }
00568            GC_set_mark_bit(real_ptr);
00569        }
00570     }
00571 # endif
00572 
00573   /* Remove dangling disappearing links. */
00574     for (i = 0; i < dl_size; i++) {
00575       curr_dl = dl_head[i];
00576       prev_dl = 0;
00577       while (curr_dl != 0) {
00578         real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
00579         if (real_link != 0 && !GC_is_marked(real_link)) {
00580             next_dl = dl_next(curr_dl);
00581             if (prev_dl == 0) {
00582                 dl_head[i] = next_dl;
00583             } else {
00584                 dl_set_next(prev_dl, next_dl);
00585             }
00586             GC_clear_mark_bit((ptr_t)curr_dl);
00587             GC_dl_entries--;
00588             curr_dl = next_dl;
00589         } else {
00590             prev_dl = curr_dl;
00591             curr_dl = dl_next(curr_dl);
00592         }
00593       }
00594     }
00595 }
00596 
00597 #ifdef JAVA_FINALIZATION
00598 
00599 /* Enqueue all remaining finalizers to be run - Assumes lock is
00600  * held, and signals are disabled */
00601 void GC_enqueue_all_finalizers()
00602 {
00603     struct finalizable_object * curr_fo, * prev_fo, * next_fo;
00604     ptr_t real_ptr, real_link;
00605     register int i;
00606     int fo_size;
00607     
00608     fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
00609     GC_words_finalized = 0;
00610     for (i = 0; i < fo_size; i++) {
00611         curr_fo = fo_head[i];
00612         prev_fo = 0;
00613       while (curr_fo != 0) {
00614           real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
00615           GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
00616           GC_set_mark_bit(real_ptr);
00617  
00618           /* Delete from hash table */
00619           next_fo = fo_next(curr_fo);
00620           if (prev_fo == 0) {
00621               fo_head[i] = next_fo;
00622           } else {
00623               fo_set_next(prev_fo, next_fo);
00624           }
00625           GC_fo_entries--;
00626 
00627           /* Add to list of objects awaiting finalization.     */
00628           fo_set_next(curr_fo, GC_finalize_now);
00629           GC_finalize_now = curr_fo;
00630 
00631           /* unhide object pointer so any future collections will     */
00632           /* see it.                                    */
00633           curr_fo -> fo_hidden_base = 
00634                      (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
00635 
00636           GC_words_finalized +=
00637               ALIGNED_WORDS(curr_fo -> fo_object_size)
00638                      + ALIGNED_WORDS(sizeof(struct finalizable_object));
00639           curr_fo = next_fo;
00640         }
00641     }
00642 
00643     return;
00644 }
00645 
00646 /* Invoke all remaining finalizers that haven't yet been run. 
00647  * This is needed for strict compliance with the Java standard, 
00648  * which can make the runtime guarantee that all finalizers are run.
00649  * Unfortunately, the Java standard implies we have to keep running
00650  * finalizers until there are no more left, a potential infinite loop.
00651  * YUCK.
00652  * This routine is externally callable, so is called without 
00653  * the allocation lock. 
00654  */
00655 void GC_finalize_all()
00656 {
00657     DCL_LOCK_STATE;
00658 
00659     DISABLE_SIGNALS();
00660     LOCK();
00661     while (GC_fo_entries > 0) {
00662       GC_enqueue_all_finalizers();
00663       UNLOCK();
00664       ENABLE_SIGNALS();
00665       GC_INVOKE_FINALIZERS();
00666       DISABLE_SIGNALS();
00667       LOCK();
00668     }
00669     UNLOCK();
00670     ENABLE_SIGNALS();
00671 }
00672 #endif
00673 
00674 /* Invoke finalizers for all objects that are ready to be finalized.  */
00675 /* Should be called without allocation lock.                          */
00676 int GC_invoke_finalizers()
00677 {
00678     register struct finalizable_object * curr_fo;
00679     register int count = 0;
00680     DCL_LOCK_STATE;
00681     
00682     while (GC_finalize_now != 0) {
00683 #      ifdef THREADS
00684            DISABLE_SIGNALS();
00685            LOCK();
00686 #      endif
00687        curr_fo = GC_finalize_now;
00688 #      ifdef THREADS
00689            if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
00690            UNLOCK();
00691            ENABLE_SIGNALS();
00692            if (curr_fo == 0) break;
00693 #      else
00694            GC_finalize_now = fo_next(curr_fo);
00695 #      endif
00696        fo_set_next(curr_fo, 0);
00697        (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
00698                            curr_fo -> fo_client_data);
00699        curr_fo -> fo_client_data = 0;
00700        ++count;
00701 #      ifdef UNDEFINED
00702            /* This is probably a bad idea.  It throws off accounting if */
00703            /* nearly all objects are finalizable.  O.w. it shouldn't   */
00704            /* matter.                                                  */
00705            GC_free((GC_PTR)curr_fo);
00706 #      endif
00707     }
00708     return count;
00709 }
00710 
00711 # ifdef __STDC__
00712     GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
00713                                     GC_PTR client_data)
00714 # else
00715     GC_PTR GC_call_with_alloc_lock(fn, client_data)
00716     GC_fn_type fn;
00717     GC_PTR client_data;
00718 # endif
00719 {
00720     GC_PTR result;
00721     DCL_LOCK_STATE;
00722     
00723 #   ifdef THREADS
00724       DISABLE_SIGNALS();
00725       LOCK();
00726       SET_LOCK_HOLDER();
00727 #   endif
00728     result = (*fn)(client_data);
00729 #   ifdef THREADS
00730       UNSET_LOCK_HOLDER();
00731       UNLOCK();
00732       ENABLE_SIGNALS();
00733 #   endif
00734     return(result);
00735 }