pike.git / src / gc.c

version» Context lines:

pike.git/src/gc.c:22:   #include "time_stuff.h"   #include "constants.h"   #include "interpret.h"      #include "gc.h"   #include "main.h"   #include <math.h>      #include "block_alloc.h"    - RCSID("$Id: gc.c,v 1.104 2000/07/07 15:33:29 mast Exp $"); + RCSID("$Id: gc.c,v 1.105 2000/07/11 03:45:09 mast Exp $");      /* Run garbage collect approximately every time    * 20 percent of all arrays, objects and programs is    * garbage.    */      #define GC_CONST 20   #define MIN_ALLOC_THRESHOLD 1000   #define MAX_ALLOC_THRESHOLD 10000000   #define MULTIPLIER 0.9
pike.git/src/gc.c:95:   INT32 num_allocs =0;   INT32 alloc_threshold = MIN_ALLOC_THRESHOLD;   int Pike_in_gc = 0;   struct pike_queue gc_mark_queue;   time_t last_gc;      static struct marker rec_list = {0, 0, 0};   struct marker *gc_rec_last = &rec_list;   static struct marker *kill_list = 0;   static unsigned last_cycle; + size_t gc_ext_weak_refs;      /* rec_list is a linked list of the markers currently being recursed    * through in the cycle check pass. gc_rec_last points at the    * innermost marker being visited. A new marker is linked in after    * gc_rec_last, except when that's inside a cycle, in which case it's    * linked in after that cycle. A cycle is always treated as one atomic    * unit, e.g. it's either popped whole or not at all.    *    * Two ranges of markers next to each other may swap places to break a    * cyclic reference at a chosen point. Some markers thus get a place
pike.git/src/gc.c:763:    gc_fatal(a, 2, "An unreferenced thing "    "got missed by gc_is_referenced().\n");    else if (!(m->flags & GC_DO_FREE))    gc_fatal(a, 2, "An unreferenced thing "    "got missed by gc_do_free().\n");    else if (m->flags & GC_GOT_EXTRA_REF)    gc_fatal(a, 2, "A thing still got an extra ref.\n");    else if (m->weak_refs == -1)    gc_fatal(a, 3, "A thing which had only weak references is "    "still around after gc.\n"); -  else if (!(m->flags & GC_LIVE)) +  else if (!(m->flags & GC_LIVE)) { +  if (m->weak_refs > 0) +  gc_fatal(a, 3, "A thing to garb is still around. " +  "It's probably one with only external weak refs.\n"); +  else    gc_fatal(a, 3, "A thing to garb is still around.\n");    }    } -  +  }    else    fatal("debug_gc_touch() used in invalid gc pass.\n");   }      static INLINE struct marker *gc_check_debug(void *a, int weak)   {    struct marker *m;       if (!a) fatal("Got null pointer.\n");    if(check_for)
pike.git/src/gc.c:840: Inside #if defined(PIKE_DEBUG)
   gc_fatal(a, 1, "Thing has already reached threshold for weak free.\n");    if (m->weak_refs >= *(INT32 *) a)    gc_fatal(a, 1, "Thing has gotten more weak refs than refs.\n");    if (m->weak_refs > m->refs + 1)    gc_fatal(a, 1, "Thing has gotten more weak refs than internal refs.\n");   #else    m = get_marker(a);   #endif       m->weak_refs++; +  gc_ext_weak_refs++;    if (m->weak_refs >= *(INT32 *) a)    m->weak_refs = -1;       ret = add_ref(m);    if (m->refs >= *(INT32 *) a)    m->flags |= GC_NOT_REFERENCED;    return ret;   }      static void init_gc(void)
pike.git/src/gc.c:1015: Inside #if defined(PIKE_DEBUG)
   (m->saved_refs != -1 && m->saved_refs != *(INT32 *)a)))    gc_fatal(a, 1, "Ref counts are wrong.\n");    return 0;   }      int gc_do_weak_free(void *a)   {    struct marker *m;       if (!a) fatal("Got null pointer.\n"); -  if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE) +  if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE && +  !(Pike_in_gc == GC_PASS_FREE && gc_ext_weak_refs))    fatal("gc_do_weak_free() called in invalid gc pass.\n");    if (gc_debug) {    if (!(m = find_marker(a)))    gc_fatal(a, 0, "gc_do_weak_free() got unknown object.\n");    }    else m = get_marker(a);    debug_malloc_touch(a);       if (m->weak_refs > m->refs)    gc_fatal(a, 0, "More weak references than internal references.\n");    -  return m->weak_refs == -1; +  if (Pike_in_gc != GC_PASS_FREE) { +  if (m->weak_refs == -1) { +  gc_ext_weak_refs--; +  return 1;    } -  +  } +  else +  if (!(m->flags & GC_MARKED)) { +  if (m->weak_refs <= 0) +  gc_fatal(a, 0, "Too many weak refs cleared to thing with external " +  "weak refs.\n"); +  m->weak_refs--; +  gc_ext_weak_refs--; +  return 1; +  } +  return 0; + }      #endif /* PIKE_DEBUG */      int gc_mark(void *a)   {    struct marker *m = get_marker(debug_malloc_pass(a));      #ifdef PIKE_DEBUG    if (!a) fatal("Got null pointer.\n"); -  if (Pike_in_gc != GC_PASS_MARK) +  if (Pike_in_gc != GC_PASS_MARK && +  !(Pike_in_gc == GC_PASS_FREE && gc_ext_weak_refs))    fatal("gc mark attempted in invalid pass.\n");    if (!*(INT32 *) a)    gc_fatal(a, 0, "Marked a thing without refs.\n"); -  +  if (m->weak_refs == -1) +  gc_fatal(a, 0, "Marking thing scheduled for weak free.\n"); +  if (Pike_in_gc == GC_PASS_FREE && !(m->flags & GC_MARKED)) +  gc_fatal(a, 0, "gc_mark() called for thing in free pass " +  "that wasn't marked before.\n");   #endif    -  if(m->flags & GC_MARKED) -  { +  if (Pike_in_gc == GC_PASS_FREE) +  /* Things are visited in the free pass through the mark functions +  * to free refs to internal things that only got weak external +  * references. That happens only when a thing also have internal +  * cyclic non-weak refs. */ +  if (m->flags & GC_FREE_VISITED)    return 0; -  }else{ +  else { +  m->flags |= GC_FREE_VISITED; +  return 1; +  } +  +  else if (m->flags & GC_MARKED) { + #ifdef PIKE_DEBUG +  if (m->weak_refs != 0) +  gc_fatal(a, 0, "weak_refs changed in marker already visited by gc_mark().\n"); + #endif +  return 0; +  } +  else { +  if (m->weak_refs) { +  gc_ext_weak_refs -= m->weak_refs; +  m->weak_refs = 0; +  }    m->flags = (m->flags & ~GC_NOT_REFERENCED) | GC_MARKED;    DO_IF_DEBUG(marked++);    return 1;    }   }      #ifdef GC_CYCLE_DEBUG   static int gc_cycle_indent = 0;   #define CYCLE_DEBUG_MSG(M, TXT) do { \    fprintf(stderr, "%*s%-33s %p [%p] ", gc_cycle_indent, "", \
pike.git/src/gc.c:1205:       return 0;    }      #ifdef PIKE_DEBUG    if (weak >= 0 && gc_rec_last->flags & GC_FOLLOWED_STRONG)    gc_fatal(x, 0, "Followed strong link too early.\n");    if (weak < 0) gc_rec_last->flags |= GC_FOLLOWED_STRONG;   #endif    +  if (weak > 0) { + #ifdef PIKE_DEBUG +  if (m->weak_refs <= 0) +  gc_fatal(x, 0, "Followed weak ref to thing that should have none left.\n"); +  m->weak_refs--; + #endif +  gc_ext_weak_refs--; +  } +     if (m->flags & GC_IN_REC_LIST) { /* A cyclic reference is found. */   #ifdef PIKE_DEBUG    if (m == &rec_list || gc_rec_last == &rec_list)    gc_fatal(x, 0, "Cyclic ref involves dummy rec_list marker.\n");   #endif       if (m != gc_rec_last) {    struct marker *p, *weak_ref = 0, *nonstrong_ref = 0;    if (!weak) {    struct marker *q;
pike.git/src/gc.c:1663: Inside #if defined(PIKE_DEBUG)
   n += gc_touch_all_mappings();    n += gc_touch_all_programs();    n += gc_touch_all_objects();    if (n != (unsigned) num_objects)    fatal("Object count wrong before gc; expected %d, got %d.\n", num_objects, n);    GC_VERBOSE_DO(fprintf(stderr, "| pretouch: %u things\n", n));    }   #endif       Pike_in_gc=GC_PASS_CHECK; +  gc_ext_weak_refs = 0;    /* First we count internal references */    gc_check_all_arrays();    gc_check_all_multisets();    gc_check_all_mappings();    gc_check_all_programs();    gc_check_all_objects();      #ifdef PIKE_DEBUG    if(master_object)    gc_external_mark2(master_object,0," &master_object");
pike.git/src/gc.c:1828: Inside #if defined(PIKE_DEBUG)
   n += gc_touch_all_mappings();    n += gc_touch_all_programs();    n += gc_touch_all_objects();    if (n != (unsigned) num_objects)    fatal("Object count wrong after gc; expected %d, got %d.\n", num_objects, n);    GC_VERBOSE_DO(fprintf(stderr, "| posttouch: %u things\n", n));    if(fatal_after_gc) fatal(fatal_after_gc);    }    if (gc_extra_refs)    fatal("Lost track of %d extra refs to things in gc.\n", gc_extra_refs); +  if (gc_ext_weak_refs) +  fatal("Still got %u external weak references to internal things in gc.\n", +  gc_ext_weak_refs);   #endif       Pike_in_gc=0;    exit_gc();       /* It's possible that more things got allocated in the kill pass    * than were freed. The count before that is a better measurement    * then. */    if (pre_kill_objs < num_objects) objs -= pre_kill_objs;    else objs -= num_objects;