Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Functions | Variables
finalize.c File Reference
#include "gc_priv.h"
#include "gc_mark.h"

Go to the source code of this file.

Classes

struct  hash_chain_entry
struct  finalizable_object

Defines

#define I_HIDE_POINTERS
#define HASH3(addr, size, log_size)
#define HASH2(addr, log_size)   HASH3(addr, 1 << log_size, log_size)
#define dl_hidden_link   prolog.hidden_key
#define dl_next(x)   (struct disappearing_link *)((x) -> prolog.next)
#define dl_set_next(x, y)   (x) -> prolog.next = (struct hash_chain_entry *)(y)
#define fo_hidden_base   prolog.hidden_key
#define fo_next(x)   (struct finalizable_object *)((x) -> prolog.next)
#define fo_set_next(x, y)   (x) -> prolog.next = (struct hash_chain_entry *)(y)

Typedefs

typedef void finalization_mark_proc ()

Functions

void GC_grow_table (struct hash_chain_entry ***table, signed_word *log_size_ptr)
int GC_register_disappearing_link (GC_PTR *link)
int GC_general_register_disappearing_link (GC_PTR *link, GC_PTR obj)
int GC_unregister_disappearing_link (GC_PTR *link)
void GC_normal_finalize_mark_proc (ptr_t p)
void GC_ignore_self_finalize_mark_proc (ptr_t p)
void GC_null_finalize_mark_proc (ptr_t p)
void GC_register_finalizer_inner (GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, GC_finalization_proc *ofn, GC_PTR *ocd, finalization_mark_proc *mp)
void GC_register_finalizer (GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, GC_finalization_proc *ofn, GC_PTR *ocd)
void GC_register_finalizer_ignore_self (GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, GC_finalization_proc *ofn, GC_PTR *ocd)
void GC_register_finalizer_no_order (GC_PTR obj, GC_finalization_proc fn, GC_PTR cd, GC_finalization_proc *ofn, GC_PTR *ocd)
void GC_finalize ()
int GC_invoke_finalizers ()
GC_PTR GC_call_with_alloc_lock (GC_fn_type fn, GC_PTR client_data)

Variables

unsigned GC_finalization_failures = 0
static struct disappearing_link ** dl_head
static signed_word log_dl_table_size = -1
word GC_dl_entries = 0
static struct finalizable_object ** fo_head
struct finalizable_objectGC_finalize_now = 0
static signed_word log_fo_table_size = -1
word GC_fo_entries = 0

Class Documentation

struct hash_chain_entry

Definition at line 29 of file finalize.c.

Collaboration diagram for hash_chain_entry:
Class Members
word hidden_key
struct hash_chain_entry * next
struct disappearing_link

Definition at line 37 of file finalize.c.

Class Members
word dl_hidden_obj
struct finalizable_object

Definition at line 55 of file finalize.c.

Class Members
ptr_t fo_client_data
GC_finalization_proc fo_fn
finalization_mark_proc * fo_mark_proc
word fo_object_size

Define Documentation

#define dl_hidden_link   prolog.hidden_key

Definition at line 39 of file finalize.c.

#define dl_next (   x)    (struct disappearing_link *)((x) -> prolog.next)

Definition at line 41 of file finalize.c.

#define dl_set_next (   x,
  y 
)    (x) -> prolog.next = (struct hash_chain_entry *)(y)

Definition at line 42 of file finalize.c.

#define fo_hidden_base   prolog.hidden_key

Definition at line 57 of file finalize.c.

#define fo_next (   x)    (struct finalizable_object *)((x) -> prolog.next)

Definition at line 61 of file finalize.c.

#define fo_set_next (   x,
  y 
)    (x) -> prolog.next = (struct hash_chain_entry *)(y)

Definition at line 62 of file finalize.c.

#define HASH2 (   addr,
  log_size 
)    HASH3(addr, 1 << log_size, log_size)

Definition at line 27 of file finalize.c.

#define HASH3 (   addr,
  size,
  log_size 
)
Value:
((((word)(addr) >> 3) ^ ((word)(addr) >> (3+(log_size)))) \
    & ((size) - 1))

Definition at line 24 of file finalize.c.

Definition at line 15 of file finalize.c.


Typedef Documentation

Definition at line 22 of file finalize.c.


Function Documentation

GC_PTR GC_call_with_alloc_lock ( GC_fn_type  fn,
GC_PTR  client_data 
)

Definition at line 715 of file finalize.c.

{
    GC_PTR result;
    DCL_LOCK_STATE;
    
#   ifdef THREADS
      DISABLE_SIGNALS();
      LOCK();
      SET_LOCK_HOLDER();
#   endif
    result = (*fn)(client_data);
#   ifdef THREADS
      UNSET_LOCK_HOLDER();
      UNLOCK();
      ENABLE_SIGNALS();
#   endif
    return(result);
}

Here is the caller graph for this function:

Definition at line 466 of file finalize.c.

{
    struct disappearing_link * curr_dl, * prev_dl, * next_dl;
    struct finalizable_object * curr_fo, * prev_fo, * next_fo;
    ptr_t real_ptr, real_link;
    register int i;
    int dl_size = (log_dl_table_size == -1 ) ? 0 : (1 << log_dl_table_size);
    int fo_size = (log_fo_table_size == -1 ) ? 0 : (1 << log_fo_table_size);
    
  /* Make disappearing links disappear */
    for (i = 0; i < dl_size; i++) {
      curr_dl = dl_head[i];
      prev_dl = 0;
      while (curr_dl != 0) {
        real_ptr = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_obj);
        real_link = (ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link);
        if (!GC_is_marked(real_ptr)) {
            *(word *)real_link = 0;
            next_dl = dl_next(curr_dl);
            if (prev_dl == 0) {
                dl_head[i] = next_dl;
            } else {
                dl_set_next(prev_dl, next_dl);
            }
            GC_clear_mark_bit((ptr_t)curr_dl);
            GC_dl_entries--;
            curr_dl = next_dl;
        } else {
            prev_dl = curr_dl;
            curr_dl = dl_next(curr_dl);
        }
      }
    }
  /* Mark all objects reachable via chains of 1 or more pointers      */
  /* from finalizable objects.                                        */
#   ifdef PRINTSTATS
        if (GC_mark_state != MS_NONE) ABORT("Bad mark state");
#   endif
    for (i = 0; i < fo_size; i++) {
      for (curr_fo = fo_head[i]; curr_fo != 0; curr_fo = fo_next(curr_fo)) {
        real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
        if (!GC_is_marked(real_ptr)) {
            GC_MARK_FO(real_ptr, curr_fo -> fo_mark_proc);
            if (GC_is_marked(real_ptr)) {
                WARN("Finalization cycle involving %lx\n", real_ptr);
            }
        }
      }
    }
  /* Enqueue for finalization all objects that are still              */
  /* unreachable.                                              */
    GC_words_finalized = 0;
    for (i = 0; i < fo_size; i++) {
      curr_fo = fo_head[i];
      prev_fo = 0;
      while (curr_fo != 0) {
        real_ptr = (ptr_t)REVEAL_POINTER(curr_fo -> fo_hidden_base);
        if (!GC_is_marked(real_ptr)) {
#         ifndef JAVA_FINALIZATION
            GC_set_mark_bit(real_ptr);
#         endif
            /* Delete from hash table */
              next_fo = fo_next(curr_fo);
              if (prev_fo == 0) {
                fo_head[i] = next_fo;
              } else {
                fo_set_next(prev_fo, next_fo);
              }
              GC_fo_entries--;
            /* Add to list of objects awaiting finalization.   */
              fo_set_next(curr_fo, GC_finalize_now);
              GC_finalize_now = curr_fo;
              /* unhide object pointer so any future collections will */
              /* see it.                                       */
              curr_fo -> fo_hidden_base = 
                            (word) REVEAL_POINTER(curr_fo -> fo_hidden_base);
              GC_words_finalized +=
                     ALIGNED_WORDS(curr_fo -> fo_object_size)
                            + ALIGNED_WORDS(sizeof(struct finalizable_object));
#          ifdef PRINTSTATS
              if (!GC_is_marked((ptr_t)curr_fo)) {
                ABORT("GC_finalize: found accessible unmarked object\n");
              }
#          endif
            curr_fo = next_fo;
        } else {
            prev_fo = curr_fo;
            curr_fo = fo_next(curr_fo);
        }
      }
    }

# ifdef JAVA_FINALIZATION
  /* make sure we mark everything reachable from objects finalized
     using the no_order mark_proc */
    for (curr_fo = GC_finalize_now; 
        curr_fo != NULL; curr_fo = fo_next(curr_fo)) {
       real_ptr = (ptr_t)curr_fo -> fo_hidden_base;
       if (!GC_is_marked(real_ptr)) {
           if (curr_fo -> fo_mark_proc == GC_null_finalize_mark_proc) {
               GC_MARK_FO(real_ptr, GC_normal_finalize_mark_proc);
           }
           GC_set_mark_bit(real_ptr);
       }
    }
# endif

  /* Remove dangling disappearing links. */
    for (i = 0; i < dl_size; i++) {
      curr_dl = dl_head[i];
      prev_dl = 0;
      while (curr_dl != 0) {
        real_link = GC_base((ptr_t)REVEAL_POINTER(curr_dl -> dl_hidden_link));
        if (real_link != 0 && !GC_is_marked(real_link)) {
            next_dl = dl_next(curr_dl);
            if (prev_dl == 0) {
                dl_head[i] = next_dl;
            } else {
                dl_set_next(prev_dl, next_dl);
            }
            GC_clear_mark_bit((ptr_t)curr_dl);
            GC_dl_entries--;
            curr_dl = next_dl;
        } else {
            prev_dl = curr_dl;
            curr_dl = dl_next(curr_dl);
        }
      }
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 145 of file finalize.c.

{
    struct disappearing_link *curr_dl;
    int index;
    struct disappearing_link * new_dl;
    DCL_LOCK_STATE;
    
    if ((word)link & (ALIGNMENT-1))
       ABORT("Bad arg to GC_general_register_disappearing_link");
#   ifdef THREADS
       DISABLE_SIGNALS();
       LOCK();
#   endif
    if (log_dl_table_size == -1
        || GC_dl_entries > ((word)1 << log_dl_table_size)) {
#      ifndef THREADS
           DISABLE_SIGNALS();
#      endif
       GC_grow_table((struct hash_chain_entry ***)(&dl_head),
                    &log_dl_table_size);
#      ifdef PRINTSTATS
           GC_printf1("Grew dl table to %lu entries\n",
                     (unsigned long)(1 << log_dl_table_size));
#      endif
#      ifndef THREADS
           ENABLE_SIGNALS();
#      endif
    }
    index = HASH2(link, log_dl_table_size);
    curr_dl = dl_head[index];
    for (curr_dl = dl_head[index]; curr_dl != 0; curr_dl = dl_next(curr_dl)) {
        if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
            curr_dl -> dl_hidden_obj = HIDE_POINTER(obj);
#          ifdef THREADS
                UNLOCK();
               ENABLE_SIGNALS();
#          endif
            return(1);
        }
    }
#   ifdef THREADS
      new_dl = (struct disappearing_link *)
       GC_generic_malloc_inner(sizeof(struct disappearing_link),NORMAL);
#   else
      new_dl = (struct disappearing_link *)
       GC_malloc(sizeof(struct disappearing_link));
#   endif
    if (new_dl != 0) {
        new_dl -> dl_hidden_obj = HIDE_POINTER(obj);
        new_dl -> dl_hidden_link = HIDE_POINTER(link);
        dl_set_next(new_dl, dl_head[index]);
        dl_head[index] = new_dl;
        GC_dl_entries++;
    } else {
        GC_finalization_failures++;
    }
#   ifdef THREADS
        UNLOCK();
        ENABLE_SIGNALS();
#   endif
    return(0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

void GC_grow_table ( struct hash_chain_entry ***  table,
signed_word log_size_ptr 
)

Definition at line 89 of file finalize.c.

{
    register word i;
    register struct hash_chain_entry *p;
    int log_old_size = *log_size_ptr;
    register int log_new_size = log_old_size + 1;
    word old_size = ((log_old_size == -1)? 0: (1 << log_old_size));
    register word new_size = 1 << log_new_size;
    struct hash_chain_entry **new_table = (struct hash_chain_entry **)
       GC_generic_malloc_inner_ignore_off_page(
              (size_t)new_size * sizeof(struct hash_chain_entry *), NORMAL);
    
    if (new_table == 0) {
       if (table == 0) {
           ABORT("Insufficient space for initial table allocation");
       } else {
           return;
       }
    }
    for (i = 0; i < old_size; i++) {
      p = (*table)[i];
      while (p != 0) {
        register ptr_t real_key = (ptr_t)REVEAL_POINTER(p -> hidden_key);
        register struct hash_chain_entry *next = p -> next;
        register int new_hash = HASH3(real_key, new_size, log_new_size);
        
        p -> next = new_table[new_hash];
        new_table[new_hash] = p;
        p = next;
      }
    }
    *log_size_ptr = log_new_size;
    *table = new_table;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 264 of file finalize.c.

{
    hdr * hhdr = HDR(p);
    word descr = hhdr -> hb_descr;
    ptr_t q, r;
    ptr_t scan_limit;
    ptr_t target_limit = p + WORDS_TO_BYTES(hhdr -> hb_sz) - 1;
    
    if ((descr & DS_TAGS) == DS_LENGTH) {
       scan_limit = p + descr - sizeof(word);
    } else {
       scan_limit = target_limit + 1 - sizeof(word);
    }
    for (q = p; q <= scan_limit; q += ALIGNMENT) {
       r = *(ptr_t *)q;
       if (r < p || r > target_limit) {
           GC_PUSH_ONE_HEAP((word)r, q);
       }
    }
}

Here is the caller graph for this function:

Definition at line 676 of file finalize.c.

{
    register struct finalizable_object * curr_fo;
    register int count = 0;
    DCL_LOCK_STATE;
    
    while (GC_finalize_now != 0) {
#      ifdef THREADS
           DISABLE_SIGNALS();
           LOCK();
#      endif
       curr_fo = GC_finalize_now;
#      ifdef THREADS
           if (curr_fo != 0) GC_finalize_now = fo_next(curr_fo);
           UNLOCK();
           ENABLE_SIGNALS();
           if (curr_fo == 0) break;
#      else
           GC_finalize_now = fo_next(curr_fo);
#      endif
       fo_set_next(curr_fo, 0);
       (*(curr_fo -> fo_fn))((ptr_t)(curr_fo -> fo_hidden_base),
                           curr_fo -> fo_client_data);
       curr_fo -> fo_client_data = 0;
       ++count;
#      ifdef UNDEFINED
           /* This is probably a bad idea.  It throws off accounting if */
           /* nearly all objects are finalizable.  O.w. it shouldn't   */
           /* matter.                                                  */
           GC_free((GC_PTR)curr_fo);
#      endif
    }
    return count;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 252 of file finalize.c.

Here is the caller graph for this function:

Definition at line 287 of file finalize.c.

{
}

Here is the caller graph for this function:

Definition at line 129 of file finalize.c.

{
    ptr_t base;
    
    base = (ptr_t)GC_base((GC_PTR)link);
    if (base == 0)
       ABORT("Bad arg to GC_register_disappearing_link");
    return(GC_general_register_disappearing_link(link, base));
}

Here is the call graph for this function:

Here is the caller graph for this function:

void GC_register_finalizer ( GC_PTR  obj,
GC_finalization_proc  fn,
GC_PTR  cd,
GC_finalization_proc *  ofn,
GC_PTR ocd 
)

Definition at line 418 of file finalize.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void GC_register_finalizer_ignore_self ( GC_PTR  obj,
GC_finalization_proc  fn,
GC_PTR  cd,
GC_finalization_proc *  ofn,
GC_PTR ocd 
)

Definition at line 435 of file finalize.c.

Here is the call graph for this function:

Here is the caller graph for this function:

void GC_register_finalizer_inner ( GC_PTR  obj,
GC_finalization_proc  fn,
GC_PTR  cd,
GC_finalization_proc *  ofn,
GC_PTR ocd,
finalization_mark_proc mp 
)

Definition at line 298 of file finalize.c.

{
    ptr_t base;
    struct finalizable_object * curr_fo, * prev_fo;
    int index;
    struct finalizable_object *new_fo;
    DCL_LOCK_STATE;

#   ifdef THREADS
       DISABLE_SIGNALS();
       LOCK();
#   endif
    if (log_fo_table_size == -1
        || GC_fo_entries > ((word)1 << log_fo_table_size)) {
#      ifndef THREADS
           DISABLE_SIGNALS();
#      endif
       GC_grow_table((struct hash_chain_entry ***)(&fo_head),
                    &log_fo_table_size);
#      ifdef PRINTSTATS
           GC_printf1("Grew fo table to %lu entries\n",
                     (unsigned long)(1 << log_fo_table_size));
#      endif
#      ifndef THREADS
           ENABLE_SIGNALS();
#      endif
    }
    /* in the THREADS case signals are disabled and we hold allocation       */
    /* lock; otherwise neither is true.  Proceed carefully.           */
    base = (ptr_t)obj;
    index = HASH2(base, log_fo_table_size);
    prev_fo = 0; curr_fo = fo_head[index];
    while (curr_fo != 0) {
        if (curr_fo -> fo_hidden_base == HIDE_POINTER(base)) {
            /* Interruption by a signal in the middle of this  */
            /* should be safe.  The client may see only *ocd   */
            /* updated, but we'll declare that to be his       */
            /* problem.                                        */
            if (ocd) *ocd = (GC_PTR) curr_fo -> fo_client_data;
            if (ofn) *ofn = curr_fo -> fo_fn;
            /* Delete the structure for base. */
                if (prev_fo == 0) {
                  fo_head[index] = fo_next(curr_fo);
                } else {
                  fo_set_next(prev_fo, fo_next(curr_fo));
                }
            if (fn == 0) {
                GC_fo_entries--;
                  /* May not happen if we get a signal.  But a high   */
                  /* estimate will only make the table larger than    */
                  /* necessary.                                       */
#             ifndef THREADS
                  GC_free((GC_PTR)curr_fo);
#             endif
            } else {
                curr_fo -> fo_fn = fn;
                curr_fo -> fo_client_data = (ptr_t)cd;
                curr_fo -> fo_mark_proc = mp;
              /* Reinsert it.  We deleted it first to maintain */
              /* consistency in the event of a signal.         */
              if (prev_fo == 0) {
                  fo_head[index] = curr_fo;
                } else {
                  fo_set_next(prev_fo, curr_fo);
                }
            }
#          ifdef THREADS
                UNLOCK();
              ENABLE_SIGNALS();
#          endif
            return;
        }
        prev_fo = curr_fo;
        curr_fo = fo_next(curr_fo);
    }
    if (ofn) *ofn = 0;
    if (ocd) *ocd = 0;
    if (fn == 0) {
#      ifdef THREADS
            UNLOCK();
           ENABLE_SIGNALS();
#      endif
        return;
    }
#   ifdef THREADS
      new_fo = (struct finalizable_object *)
       GC_generic_malloc_inner(sizeof(struct finalizable_object),NORMAL);
#   else
      new_fo = (struct finalizable_object *)
       GC_malloc(sizeof(struct finalizable_object));
#   endif
    if (new_fo != 0) {
        new_fo -> fo_hidden_base = (word)HIDE_POINTER(base);
       new_fo -> fo_fn = fn;
       new_fo -> fo_client_data = (ptr_t)cd;
       new_fo -> fo_object_size = GC_size(base);
       new_fo -> fo_mark_proc = mp;
       fo_set_next(new_fo, fo_head[index]);
       GC_fo_entries++;
       fo_head[index] = new_fo;
    } else {
       GC_finalization_failures++;
    }
#   ifdef THREADS
        UNLOCK();
       ENABLE_SIGNALS();
#   endif
}

Here is the call graph for this function:

Here is the caller graph for this function:

void GC_register_finalizer_no_order ( GC_PTR  obj,
GC_finalization_proc  fn,
GC_PTR  cd,
GC_finalization_proc *  ofn,
GC_PTR ocd 
)

Definition at line 452 of file finalize.c.

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 215 of file finalize.c.

{
    struct disappearing_link *curr_dl, *prev_dl;
    int index;
    DCL_LOCK_STATE;
    
    DISABLE_SIGNALS();
    LOCK();
    index = HASH2(link, log_dl_table_size);
    if (((unsigned long)link & (ALIGNMENT-1))) goto out;
    prev_dl = 0; curr_dl = dl_head[index];
    while (curr_dl != 0) {
        if (curr_dl -> dl_hidden_link == HIDE_POINTER(link)) {
            if (prev_dl == 0) {
                dl_head[index] = dl_next(curr_dl);
            } else {
                dl_set_next(prev_dl, dl_next(curr_dl));
            }
            GC_dl_entries--;
            UNLOCK();
           ENABLE_SIGNALS();
            GC_free((GC_PTR)curr_dl);
            return(1);
        }
        prev_dl = curr_dl;
        curr_dl = dl_next(curr_dl);
    }
out:
    UNLOCK();
    ENABLE_SIGNALS();
    return(0);
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

struct disappearing_link ** dl_head [static]
struct finalizable_object ** fo_head [static]

Definition at line 52 of file finalize.c.

Definition at line 34 of file finalize.c.

Definition at line 69 of file finalize.c.

Definition at line 74 of file finalize.c.

Definition at line 47 of file finalize.c.

Definition at line 72 of file finalize.c.