root/gc/finalize.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GC_PROTO
  2. GC_grow_table
  3. GC_register_disappearing_link
  4. GC_general_register_disappearing_link
  5. GC_unregister_disappearing_link
  6. GC_normal_finalize_mark_proc
  7. GC_ignore_self_finalize_mark_proc
  8. GC_null_finalize_mark_proc
  9. GC_register_finalizer_inner
  10. GC_register_finalizer
  11. GC_register_finalizer_ignore_self
  12. GC_register_finalizer_no_order
  13. GC_dump_finalization
  14. GC_finalize
  15. GC_enqueue_all_finalizers
  16. GC_finalize_all
  17. GC_PROTO
  18. GC_invoke_finalizers
  19. GC_PROTO
  20. GC_call_with_alloc_lock
  21. GC_print_finalization_stats

   1 /*
   2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
   3  * Copyright (c) 1991-1996 by Xerox Corporation.  All rights reserved.
   4  * Copyright (c) 1996-1999 by Silicon Graphics.  All rights reserved.
   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
  17 # include "private/gc_pmark.h"
  18 
  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 
  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 
  88 void GC_push_finalizer_structures GC_PROTO((void))
  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));
  92     GC_push_all((ptr_t)(&GC_finalize_now),
  93                 (ptr_t)(&GC_finalize_now) + sizeof(word));
  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 **)
 112         GC_INTERNAL_MALLOC_IGNORE_OFF_PAGE(
 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);
 181 #       ifdef CONDPRINT
 182           if (GC_print_stats) {
 183             GC_printf1("Grew dl table to %lu entries\n",
 184                         (unsigned long)(1 << log_dl_table_size));
 185           }
 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     }
 203     new_dl = (struct disappearing_link *)
 204         GC_INTERNAL_MALLOC(sizeof(struct disappearing_link),NORMAL);
 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
 221     }
 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++;
 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();
 260 #           ifdef DBG_HDRS_ALL
 261               dl_set_next(curr_dl, 0);
 262 #           else
 263               GC_free((GC_PTR)curr_dl);
 264 #           endif
 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.            */
 278 GC_API void GC_normal_finalize_mark_proc(p)
 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.                                               */
 290 GC_API void GC_ignore_self_finalize_mark_proc(p)
 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     
 299     if ((descr & GC_DS_TAGS) == GC_DS_LENGTH) {
 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*/
 313 GC_API void GC_null_finalize_mark_proc(p)
 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.                                             */
 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)
 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;
 340     hdr *hhdr;
 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);
 354 #       ifdef CONDPRINT
 355           if (GC_print_stats) {
 356             GC_printf1("Grew fo table to %lu entries\n",
 357                         (unsigned long)(1 << log_fo_table_size));
 358           }
 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.                                         */
 388 #               if !defined(THREADS) && !defined(DBG_HDRS_ALL)
 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     }
 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);
 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
 448     }
 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;
 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 
 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 
 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.                                          */
 579     GC_ASSERT(GC_mark_state == MS_NONE);
 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)) {
 601             if (!GC_java_finalization) {
 602               GC_set_mark_bit(real_ptr);
 603             }
 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));
 622             GC_ASSERT(GC_is_marked(GC_base((ptr_t)curr_fo)));
 623             curr_fo = next_fo;
 624         } else {
 625             prev_fo = curr_fo;
 626             curr_fo = fo_next(curr_fo);
 627         }
 628       }
 629     }
 630 
 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   }
 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 
 670 #ifndef JAVA_FINALIZATION_NOT_NEEDED
 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;
 677     ptr_t real_ptr;
 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.
 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.
 730  * This routine is externally callable, so is called without 
 731  * the allocation lock. 
 732  */
 733 GC_API void GC_finalize_all()
 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
 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 }
 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 {
 764     struct finalizable_object * curr_fo;
 765     int count = 0;
 766     word mem_freed_before;
 767     DCL_LOCK_STATE;
 768     
 769     while (GC_finalize_now != 0) {
 770 #       ifdef THREADS
 771             DISABLE_SIGNALS();
 772             LOCK();
 773 #       endif
 774         if (count == 0) {
 775             mem_freed_before = GC_mem_freed;
 776         }
 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     }
 798     if (count != 0 && mem_freed_before != GC_mem_freed) {
 799         LOCK();
 800         GC_finalizer_mem_freed += (GC_mem_freed - mem_freed_before);
 801         UNLOCK();
 802     }
 803     return count;
 804 }
 805 
 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     /* This is a convenient place to generate backtraces if appropriate, */
 813     /* since that code is not callable with the allocation lock.         */
 814 #   if defined(KEEP_BACK_PTRS) || defined(MAKE_BACK_GRAPH)
 815       static word last_back_trace_gc_no = 1;    /* Skip first one. */
 816 
 817       if (GC_gc_no > last_back_trace_gc_no) {
 818         word i;
 819 
 820 #       ifdef KEEP_BACK_PTRS
 821           LOCK();
 822           /* Stops when GC_gc_no wraps; that's OK.      */
 823           last_back_trace_gc_no = (word)(-1);  /* disable others. */
 824           for (i = 0; i < GC_backtraces; ++i) {
 825               /* FIXME: This tolerates concurrent heap mutation,        */
 826               /* which may cause occasional mysterious results.         */
 827               /* We need to release the GC lock, since GC_print_callers */
 828               /* acquires it.  It probably shouldn't.                   */
 829               UNLOCK();
 830               GC_generate_random_backtrace_no_gc();
 831               LOCK();
 832           }
 833           last_back_trace_gc_no = GC_gc_no;
 834           UNLOCK();
 835 #       endif
 836 #       ifdef MAKE_BACK_GRAPH
 837           if (GC_print_back_height)
 838             GC_print_back_graph_stats();
 839 #       endif
 840       }
 841 #   endif
 842     if (GC_finalize_now == 0) return;
 843     if (!GC_finalize_on_demand) {
 844         (void) GC_invoke_finalizers();
 845 #       ifndef THREADS
 846           GC_ASSERT(GC_finalize_now == 0);
 847 #       endif   /* Otherwise GC can run concurrently and add more */
 848         return;
 849     }
 850     if (GC_finalizer_notifier != (void (*) GC_PROTO((void)))0
 851         && last_finalizer_notification != GC_gc_no) {
 852         last_finalizer_notification = GC_gc_no;
 853         GC_finalizer_notifier();
 854     }
 855 }
 856 
 857 # ifdef __STDC__
 858     GC_PTR GC_call_with_alloc_lock(GC_fn_type fn,
 859                                          GC_PTR client_data)
 860 # else
 861     GC_PTR GC_call_with_alloc_lock(fn, client_data)
 862     GC_fn_type fn;
 863     GC_PTR client_data;
 864 # endif
 865 {
 866     GC_PTR result;
 867     DCL_LOCK_STATE;
 868     
 869 #   ifdef THREADS
 870       DISABLE_SIGNALS();
 871       LOCK();
 872       SET_LOCK_HOLDER();
 873 #   endif
 874     result = (*fn)(client_data);
 875 #   ifdef THREADS
 876 #     ifndef GC_ASSERTIONS
 877         UNSET_LOCK_HOLDER();
 878 #     endif /* o.w. UNLOCK() does it implicitly */
 879       UNLOCK();
 880       ENABLE_SIGNALS();
 881 #   endif
 882     return(result);
 883 }
 884 
 885 #if !defined(NO_DEBUGGING)
 886 
 887 void GC_print_finalization_stats()
 888 {
 889     struct finalizable_object *fo = GC_finalize_now;
 890     size_t ready = 0;
 891 
 892     GC_printf2("%lu finalization table entries; %lu disappearing links\n",
 893                GC_fo_entries, GC_dl_entries);
 894     for (; 0 != fo; fo = fo_next(fo)) ++ready;
 895     GC_printf1("%lu objects are eligible for immediate finalization\n", ready);
 896 }
 897 
 898 #endif /* NO_DEBUGGING */

/* [<][>][^][v][top][bottom][index][help] */