pike.git / src / gc.c

version» Context lines:

pike.git/src/gc.c:23:   #include "constants.h"   #include "interpret.h"   #include "bignum.h"      #include "gc.h"   #include "main.h"   #include <math.h>      #include "block_alloc.h"    - RCSID("$Id: gc.c,v 1.127 2000/08/27 15:21:50 mast Exp $"); + RCSID("$Id: gc.c,v 1.128 2000/09/03 23:09:38 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:55:    * o If an object A references B single way, then A is destructed    * before B.    * o If A and B are in a cycle, and there is a reference somewhere    * from B to A that is weaker than any reference from A to B, then    * A is destructed before B.    * o Weak references are considered weaker than normal ones, and both    * are considered weaker than strong references.    * o Strong references are used in special cases like parent object    * references. There can never be a cycle consisting only of strong    * references. (This means the gc will never destruct a parent -  * object before all childs has been destructed.) +  * object before all children have been destructed.)    *    * The gc tries to detect and warn about cases where there are live    * objects with no well defined order between them. There are cases    * that are missed by this detection, though.    *    * Things that aren't live objects but are referenced from them are    * still intact during this destruct pass, so it's entirely possible -  * to save these things by adding external references to them. -  * However, it's not possible for live objects to save themselves or -  * other live objects; all live objects that didn't have external -  * references at the start of the gc pass will be destructed -  * regardless of added references. +  * to save them by adding external references to them. However, it's +  * not possible for live objects to save themselves or other live +  * objects; all live objects that didn't have external references at +  * the start of the gc pass will be destructed regardless of added +  * references.    *    * Things that have only weak external references at the start of the    * gc pass will be freed. That's done before the live object destruct    * pass. Internal weak references are however still intact.    */      /* #define GC_VERBOSE */   /* #define GC_CYCLE_DEBUG */      /* #define GC_STACK_DEBUG */
pike.git/src/gc.c:218:   #define INIT_BLOCK(X) \    (X)->flags=(X)->refs=(X)->weak_refs=(X)->xrefs=0; \    (X)->saved_refs=-1; \    (X)->frame = 0;   #else   #define INIT_BLOCK(X) \    (X)->flags=(X)->refs=(X)->weak_refs=0; \    (X)->frame = 0;   #endif    + #ifdef PIKE_DEBUG + #undef get_marker + #define get_marker debug_get_marker + #undef find_marker + #define find_marker debug_find_marker + #endif +    PTR_HASH_ALLOC(marker,MARKER_CHUNK_SIZE)      #ifdef PIKE_DEBUG    -  + #undef get_marker + #define get_marker(X) ((struct marker *) debug_malloc_pass(debug_get_marker(X))) + #undef find_marker + #define find_marker(X) ((struct marker *) debug_malloc_pass(debug_find_marker(X))) +    int gc_in_cycle_check = 0;   static unsigned weak_freed, checked, marked, cycle_checked, live_ref;   static unsigned max_gc_frames, num_gc_frames = 0;   static unsigned gc_extra_refs = 0;      void dump_gc_info(void)   {    fprintf(stderr,"Current number of objects: %ld\n",(long)num_objects);    fprintf(stderr,"Objects allocated total : %ld\n",(long)num_allocs);    fprintf(stderr," threshold for next gc() : %ld\n",(long)alloc_threshold);
pike.git/src/gc.c:266: Inside #if defined(PIKE_DEBUG)
   if(o==(struct object *)something)    return T_OBJECT;       for(p=first_program;p;p=p->next)    if(p==(struct program *)something)    return T_PROGRAM;       for(m=first_mapping;m;m=m->next)    if(m==(struct mapping *)something)    return T_MAPPING; +  else if (m->data == (struct mapping_data *) something) +  return T_MAPPING_DATA;       for(mu=first_multiset;mu;mu=mu->next)    if(mu==(struct multiset *)something)    return T_MULTISET;       if(safe_debug_findstring((struct pike_string *)something))    return T_STRING;       return T_UNKNOWN;   }
pike.git/src/gc.c:582:      void debug_gc_check_weak_short_svalue(union anything *u, TYPE_T type, TYPE_T t, void *data)   {    found_in=data;    found_in_type=t;    gc_check_weak_short_svalue(u,type);    found_in_type=T_UNKNOWN;    found_in=0;   }    - int debug_gc_check(void *x, TYPE_T t, void *data) + int debug_low_gc_check(void *x, TYPE_T t, void *data)   {    int ret;    found_in=data;    found_in_type=t;    ret=gc_check(x);    found_in_type=T_UNKNOWN;    found_in=0;    return ret;   }   
pike.git/src/gc.c:840:    }    }    }    describe_something(s->u.refs,s->type,0,2,0);   }      void debug_gc_touch(void *a)   {    struct marker *m;    if (!a) fatal("Got null pointer.\n"); -  +     m = find_marker(a); -  if (Pike_in_gc == GC_PASS_PRETOUCH) { -  if (m) gc_fatal(a, 0, "Object touched twice.\n"); -  get_marker(a)->flags |= GC_TOUCHED; -  } -  else if (Pike_in_gc == GC_PASS_POSTTOUCH) { +  +  switch (Pike_in_gc) { +  case GC_PASS_PRETOUCH: +  if (m && !(m->flags & GC_PRETOUCHED)) +  gc_fatal(a, 1, "Thing got an existing but untouched marker.\n"); +  get_marker(a)->flags |= GC_PRETOUCHED; +  break; +  +  case GC_PASS_MIDDLETOUCH: +  if (!m) +  gc_fatal(a, 1, "Found a thing without marker.\n"); +  else if (!(m->flags & GC_PRETOUCHED)) +  gc_fatal(a, 1, "Thing got an existing but untouched marker.\n"); +  m->flags |= GC_MIDDLETOUCHED; +  break; +  +  case GC_PASS_POSTTOUCH:    if (!*(INT32 *) a)    gc_fatal(a, 1, "Found a thing without refs.\n");    if (m) { -  if (!(m->flags & GC_TOUCHED)) +  if (!(m->flags & (GC_PRETOUCHED|GC_MIDDLETOUCHED)))    gc_fatal(a, 2, "An existing but untouched marker found "    "for object in linked lists.\n");    else if (m->flags & GC_LIVE_RECURSE ||    (m->frame && m->frame->frameflags & (GC_WEAK_REF|GC_STRONG_REF)))    gc_fatal(a, 2, "Thing still got flag from recurse list.\n");    else if (m->flags & GC_MARKED)    return;    else if (!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_XREFERENCED)    gc_fatal(a, 3, "A thing with external references "    "got missed by mark pass.\n");
pike.git/src/gc.c:883:    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 if (m->weak_refs < 0)    gc_fatal(a, 3, "A thing which had only weak references is "    "still around after gc.\n");    else    gc_fatal(a, 3, "A thing to garb is still around.\n");    }    } -  } -  else +  break; +  +  default:    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)    {    if(check_for == a)    {
pike.git/src/gc.c:1083: Inside #if defined(PIKE_DEBUG)
     int debug_gc_is_referenced(void *a)   {    struct marker *m;    if (!a) fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_MARK)    fatal("gc_is_referenced() called in invalid gc pass.\n");       if (gc_debug) {    m = find_marker(a); -  if ((!m || !(m->flags & GC_TOUCHED)) && +  if ((!m || !(m->flags & GC_PRETOUCHED)) &&    !safe_debug_findstring((struct pike_string *) a))    gc_fatal(a, 0, "Doing gc_is_referenced() on invalid object.\n");    if (!m) m = get_marker(a);    }    else m = get_marker(a);       if (m->flags & GC_IS_REFERENCED)    gc_fatal(a, 0, "gc_is_referenced() called twice for thing.\n");    m->flags |= GC_IS_REFERENCED;   
pike.git/src/gc.c:1157:   #define debug_really_free_gc_frame(l) really_free_gc_frame(l)      #endif /* PIKE_DEBUG */      int gc_do_weak_free(void *a)   {    struct marker *m;      #ifdef PIKE_DEBUG    if (!a) fatal("Got null pointer.\n"); -  if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE && -  Pike_in_gc != GC_PASS_ZAP_WEAK) +  if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)    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");   #else    m = get_marker(a);   #endif       if (Pike_in_gc != GC_PASS_ZAP_WEAK) {    if (m->weak_refs < 0) {    gc_ext_weak_refs--; -  + #ifdef PIKE_DEBUG +  m->flags |= GC_WEAK_FREED; + #endif    return 1;    }    }    else    if (!(m->flags & GC_MARKED)) {   #ifdef PIKE_DEBUG    if (m->weak_refs <= 0)    gc_fatal(a, 0, "Too many weak refs cleared to thing with external "    "weak refs.\n");   #endif    m->weak_refs--;    gc_ext_weak_refs--; -  + #ifdef PIKE_DEBUG +  m->flags |= GC_WEAK_FREED; + #endif    return 1;    }    return 0;   }      int gc_mark(void *a)   {    struct marker *m = get_marker(debug_malloc_pass(a));      #ifdef PIKE_DEBUG
pike.git/src/gc.c:1414:      int gc_cycle_push(void *x, struct marker *m, int weak)   {    struct marker *last = find_marker(gc_rec_last->data);      #ifdef PIKE_DEBUG    if (!x) fatal("Got null pointer.\n");    if (m->data != x) fatal("Got wrong marker.\n");    if (Pike_in_gc != GC_PASS_CYCLE)    fatal("GC cycle push attempted in invalid pass.\n"); -  if (gc_debug && !(m->flags & GC_TOUCHED)) +  if (gc_debug && !(m->flags & GC_PRETOUCHED))    gc_fatal(x, 0, "gc_cycle_push() called for untouched thing.\n");    if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) &&    *(INT32 *) x)    gc_fatal(x, 1, "Got a referenced marker to gc_cycle_push.\n");    if (m->flags & GC_XREFERENCED)    gc_fatal(x, 1, "Doing cycle check in externally referenced thing "    "missed in mark pass.\n");    if (gc_debug) {    struct array *a;    struct object *o;
pike.git/src/gc.c:1805:   #endif       m=find_marker(debug_malloc_pass(a));    if (!m) return 0; /* Object created after cycle pass. */      #ifdef PIKE_DEBUG    if (*(INT32 *) a > !!(m->flags & GC_GOT_EXTRA_REF)) {    if (!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED)    gc_fatal(a, 0, "gc_do_free() called for referenced thing.\n");    if (gc_debug && -  (m->flags & (GC_TOUCHED|GC_MARKED|GC_IS_REFERENCED)) == GC_TOUCHED) +  (m->flags & (GC_PRETOUCHED|GC_MARKED|GC_IS_REFERENCED)) == GC_PRETOUCHED)    gc_fatal(a, 0, "gc_do_free() called without prior call to "    "gc_mark() or gc_is_referenced().\n");    }    if((m->flags & (GC_MARKED|GC_XREFERENCED)) == GC_XREFERENCED)    gc_fatal(a, 1, "Thing with external reference missed in gc mark pass.\n");    if ((m->flags & (GC_DO_FREE|GC_LIVE)) == GC_LIVE) live_ref++;    m->flags |= GC_DO_FREE;   #endif       return !(m->flags & GC_LIVE);
pike.git/src/gc.c:1877: Inside #if defined(PIKE_DEBUG)
  #endif    unsigned destroy_count, obj_count;   #endif       if(Pike_in_gc) return 0;    init_gc();    Pike_in_gc=GC_PASS_PREPARE;   #ifdef PIKE_DEBUG    gc_debug = d_flag;   #endif +  gc_debug = 1;       destruct_objects_to_destruct();       if(gc_evaluator_callback)    {    remove_callback(gc_evaluator_callback);    gc_evaluator_callback=0;    }       objs=num_objects;
pike.git/src/gc.c:1922: Inside #if defined(PIKE_DEBUG)
  #ifdef PIKE_DEBUG    weak_freed = checked = marked = cycle_checked = live_ref = 0;    if (gc_debug) {    unsigned n;    Pike_in_gc = GC_PASS_PRETOUCH;    n = gc_touch_all_arrays();    n += gc_touch_all_multisets();    n += gc_touch_all_mappings();    n += gc_touch_all_programs();    n += gc_touch_all_objects(); +  gc_touch_all_strings();    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();
pike.git/src/gc.c:1977:    gc_mark_all_arrays();    run_queue(&gc_mark_queue);    gc_mark_all_multisets();    run_queue(&gc_mark_queue);    gc_mark_all_mappings();    run_queue(&gc_mark_queue);    gc_mark_all_programs();    run_queue(&gc_mark_queue);    gc_mark_all_objects();    run_queue(&gc_mark_queue); - /* if(gc_debug) */ - /* gc_mark_all_strings(); */ +  if(gc_debug) gc_mark_all_strings();       GC_VERBOSE_DO(fprintf(stderr,    "| mark: %u markers referenced,\n"    "| %u weak references freed, %d things really freed\n",    marked, weak_freed, objs - num_objects));       Pike_in_gc=GC_PASS_CYCLE;   #ifdef PIKE_DEBUG    obj_count = num_objects;    max_gc_frames = 0;
pike.git/src/gc.c:2008:    gc_cycle_check_all_mappings();    gc_cycle_check_all_programs();      #ifdef PIKE_DEBUG    if (gc_rec_top)    fatal("gc_rec_top not empty at end of cycle check pass.\n");    if (NEXT(&rec_list) || gc_rec_last != &rec_list || gc_rec_top)    fatal("Recurse list not empty or inconsistent after cycle check pass.\n");   #endif    + #ifdef PIKE_DEBUG +  if (gc_debug) { +  unsigned n; +  size_t i; +  struct marker *m; +  Pike_in_gc=GC_PASS_MIDDLETOUCH; +  n = gc_touch_all_arrays(); +  n += gc_touch_all_multisets(); +  n += gc_touch_all_mappings(); +  n += gc_touch_all_programs(); +  n += gc_touch_all_objects(); +  gc_touch_all_strings(); +  if (n != (unsigned) num_objects) +  fatal("Object count wrong in gc; expected %d, got %d.\n", num_objects, n); +  get_marker(rec_list.data)->flags |= GC_MIDDLETOUCHED; + #ifdef DEBUG_MALLOC +  PTR_HASH_LOOP(marker, i, m) +  if (!(m->flags & (GC_MIDDLETOUCHED|GC_WEAK_FREED)) && +  dmalloc_is_invalid_memory_block(m->data)) { +  fprintf(stderr, "Found a stray marker after middletouch pass: "); +  describe_marker(m); +  fprintf(stderr, "Describing marker location(s):\n"); +  debug_malloc_dump_references(m, 2, 1, 0); +  fprintf(stderr, "Describing thing for marker:\n"); +  describe(m->data); +  fatal("Fatal in garbage collector.\n"); +  } + #endif +  GC_VERBOSE_DO(fprintf(stderr, "| middletouch\n")); +  } + #endif +     GC_VERBOSE_DO(fprintf(stderr,    "| cycle: %u internal things visited, %u cycle ids used,\n"    "| %u weak references freed, %d things really freed,\n"    "| space for %u gc frames used\n",    cycle_checked, last_cycle, weak_freed, obj_count - num_objects,    max_gc_frames));       if (gc_ext_weak_refs) {    size_t to_free = gc_ext_weak_refs;   #ifdef PIKE_DEBUG
pike.git/src/gc.c:2126: Inside #if defined(PIKE_DEBUG)
     #ifdef PIKE_DEBUG    if (gc_debug) {    unsigned n;    Pike_in_gc=GC_PASS_POSTTOUCH;    n = gc_touch_all_arrays();    n += gc_touch_all_multisets();    n += gc_touch_all_mappings();    n += gc_touch_all_programs();    n += gc_touch_all_objects(); +  // gc_touch_all_strings();    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("%s", 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 %lu external weak references to internal things in gc.\n",    (unsigned long)PTRDIFF_T_TO_LONG(gc_ext_weak_refs));