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.165 2001/07/02 01:02:56 mast Exp $"); + RCSID("$Id: gc.c,v 1.166 2001/07/05 00:09:41 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:191:      struct callback_list gc_callbacks;      struct callback *debug_add_gc_callback(callback_func call,    void *arg,    callback_func free_func)   {    return add_to_callback(&gc_callbacks, call, arg, free_func);   }    + static void init_gc(void);   static void gc_cycle_pop(void *a);         #undef BLOCK_ALLOC_NEXT   #define BLOCK_ALLOC_NEXT next      #undef INIT_BLOCK   #ifdef PIKE_DEBUG   #define INIT_BLOCK(X) \    (X)->flags=(X)->refs=(X)->weak_refs=(X)->xrefs=0; \
pike.git/src/gc.c:233:   #define find_marker(X) ((struct marker *) debug_malloc_pass(debug_find_marker(X)))      int gc_in_cycle_check = 0;   static unsigned delayed_freed, weak_freed, checked, marked, cycle_checked, live_ref;   static unsigned max_gc_frames, num_gc_frames = 0, live_rec, frame_rot;   static unsigned gc_extra_refs = 0;      static unsigned max_tot_gc_frames = 0;   static unsigned tot_cycle_checked = 0, tot_live_rec = 0, tot_frame_rot = 0;    + static int gc_is_watching = 0; +    void dump_gc_info(void)   {    fprintf(stderr,"Current number of objects: %d\n",num_objects);    fprintf(stderr,"Objects allocated total : %d\n",num_allocs);    fprintf(stderr," threshold for next gc() : %"PRINTPTRDIFFT"d\n",alloc_threshold);    fprintf(stderr,"Average allocs per gc() : %f\n",objects_alloced);    fprintf(stderr,"Average frees per gc() : %f\n",objects_freed);    fprintf(stderr,"Second since last gc() : %ld\n",    DO_NOT_WARN((long)TIME(0) - (long)last_gc));    fprintf(stderr,"Projected garbage : %f\n", objects_freed * (double) num_allocs / (double) alloc_threshold);
pike.git/src/gc.c:537:    fprintf(stderr, "back=%p, prev=%p, next=%p, data=%p, cycle=%u, flags=0x%02x",    l->back, PREV(l), NEXT(l), l->data, CYCLE(l), l->frameflags);    else    fprintf(stderr, "LINK back=%p, data=%p, weak=%d, flags=0x%02x",    l->back, l->data, l->u.link.weak, l->frameflags);   }      static void describe_marker(struct marker *m)   {    if (m) { -  fprintf(stderr, "marker at %p: flags=0x%04x, refs=%d, weak=%d, " +  fprintf(stderr, "marker at %p: flags=0x%05lx, refs=%d, weak=%d, "    "xrefs=%d, saved=%d, frame=%p", -  m, m->flags, m->refs, m->weak_refs, +  m, (long) m->flags, m->refs, m->weak_refs,    m->xrefs, m->saved_refs, m->frame);   #ifdef PIKE_DEBUG    if (m->frame) {    fputs(" [", stderr);    describe_gc_frame(m->frame);    putc(']', stderr);    }   #endif    putc('\n', stderr);    }
pike.git/src/gc.c:950:    fprintf(stderr," Function in destructed object.\n");    }    }else{    fprintf(stderr," Function name: %s\n",ID_FROM_INT(s->u.object->prog,s->subtype)->name->str);    }    }    }    describe_something(s->u.refs,s->type,0,2,0);   }    + void gc_watch(void *a) + { +  struct marker *m; +  init_gc(); +  m = get_marker(a); +  if (!(m->flags & GC_WATCHED)) { +  m->flags |= GC_WATCHED; +  fprintf(stderr, "## Watching thing %p.\n", a); +  gc_is_watching++; +  } +  else +  fprintf(stderr, "## Already watching thing %p.\n", a); + } +    void debug_gc_touch(void *a)   {    struct marker *m; -  +  +  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_touch() in pass %d.\n", a, Pike_in_gc); +  } +     if (!a) fatal("Got null pointer.\n");       switch (Pike_in_gc) {    case GC_PASS_PRETOUCH:    m = find_marker(a); -  if (m && !(m->flags & GC_PRETOUCHED)) +  if (m && !(m->flags & (GC_PRETOUCHED|GC_WATCHED)))    gc_fatal(a, 1, "Thing got an existing but untouched marker.\n");    m = get_marker(a);    m->flags |= GC_PRETOUCHED;    m->saved_refs = *(INT32 *) a;    break;       case GC_PASS_MIDDLETOUCH: {    int extra_ref;    m = find_marker(a);    if (!m)
pike.git/src/gc.c:1069:   }      #endif /* PIKE_DEBUG */      PMOD_EXPORT INT32 real_gc_check(void *a)   {    struct marker *m;    INT32 ret;      #ifdef PIKE_DEBUG +  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_check() in pass %d.\n", a, Pike_in_gc); +  }    if (!(m = gc_check_debug(a, 0))) return 0;   #else    m = get_marker(a);   #endif       ret=m->refs;    add_ref(m);    if (m->refs == *(INT32 *) a)    m->flags |= GC_NOT_REFERENCED;    return ret;   }      INT32 real_gc_check_weak(void *a)   {    struct marker *m;    INT32 ret;      #ifdef PIKE_DEBUG -  +  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_check_weak() in pass %d.\n", a, Pike_in_gc); +  }    if (!(m = gc_check_debug(a, 1))) return 0;    if (m->weak_refs < 0)    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
pike.git/src/gc.c:1112:       ret=m->refs;    add_ref(m);    if (m->refs == *(INT32 *) a)    m->flags |= GC_NOT_REFERENCED;    return ret;   }      static void init_gc(void)   { + #ifdef PIKE_DEBUG +  if (!gc_is_watching) { + #endif    init_marker_hash();    get_marker(rec_list.data); /* Used to simplify fencepost conditions. */ -  + #ifdef PIKE_DEBUG    } -  + #endif + }      static void exit_gc(void)   {   #ifdef DO_PIKE_CLEANUP    int e=0;    struct marker *h;    for(e=0;e<marker_hash_table_size;e++)    while(marker_hash_table[e])    remove_marker(marker_hash_table[e]->data);   #endif -  + #ifdef PIKE_DEBUG +  if (gc_is_watching) { +  fprintf(stderr, "## Exiting gc and resetting watches for %d things.\n", +  gc_is_watching); +  gc_is_watching = 0; +  } + #endif    exit_marker_hash();    free_all_gc_frame_blocks();   #ifdef GC_VERBOSE    num_gc_frames = 0;   #endif   }      #ifdef PIKE_DEBUG   void locate_references(void *a)   {
pike.git/src/gc.c:1207: Inside #if defined(PIKE_DEBUG)
   d_flag=tmp;   }   #endif      #ifdef PIKE_DEBUG      void debug_gc_add_extra_ref(void *a)   {    struct marker *m;    +  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_add_extra_ref() in pass %d.\n", a, Pike_in_gc); +  } +     if (gc_debug) {    m = find_marker(a);    if ((!m || !(m->flags & GC_PRETOUCHED)) &&    !safe_debug_findstring((struct pike_string *) a))    gc_fatal(a, 0, "Doing gc_add_extra_ref() on invalid object.\n");    if (!m) m = get_marker(a);    }    else m = get_marker(a);       if (m->flags & GC_GOT_EXTRA_REF)    gc_fatal(a, 0, "Thing already got an extra gc ref.\n");    m->flags |= GC_GOT_EXTRA_REF;    gc_extra_refs++;    add_ref( (struct ref_dummy *)a);   }      void debug_gc_free_extra_ref(void *a)   {    struct marker *m;    -  +  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_free_extra_ref() in pass %d.\n", a, Pike_in_gc); +  } +     if (gc_debug) {    m = find_marker(a);    if ((!m || !(m->flags & GC_PRETOUCHED)) &&    !safe_debug_findstring((struct pike_string *) a))    gc_fatal(a, 0, "Doing gc_add_extra_ref() on invalid object.\n");    if (!m) m = get_marker(a);    }    else m = get_marker(a);       if (!(m->flags & GC_GOT_EXTRA_REF))    gc_fatal(a, 0, "Thing haven't got an extra gc ref.\n");    m->flags &= ~GC_GOT_EXTRA_REF;    gc_extra_refs--;   }         int debug_gc_is_referenced(void *a)   {    struct marker *m; -  +  +  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_is_referenced() in pass %d.\n", a, Pike_in_gc); +  } +     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_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);
pike.git/src/gc.c:1269: Inside #if defined(PIKE_DEBUG)
   if (m->flags & GC_IS_REFERENCED)    gc_fatal(a, 0, "gc_is_referenced() called twice for thing.\n");    m->flags |= GC_IS_REFERENCED;       return !(m->flags & GC_NOT_REFERENCED);   }      int gc_external_mark3(void *a, void *in, char *where)   {    struct marker *m; +  +  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_external_mark3() in pass %d.\n", a, Pike_in_gc); +  } +     if (!a) fatal("Got null pointer.\n");       if(Pike_in_gc == GC_PASS_LOCATE)    {    if(a==check_for)    {    char *tmp=found_where;    void *tmp2=found_in;       if(where) found_where=where;
pike.git/src/gc.c:1325:      #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 (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_do_weak_free() in pass %d.\n", a, Pike_in_gc); +  }    if (!a) fatal("Got null pointer.\n");    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);   
pike.git/src/gc.c:1383:    }       return 1;   }      void gc_delayed_free(void *a)   {    struct marker *m;      #ifdef PIKE_DEBUG +  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_delayed_free() in pass %d.\n", a, Pike_in_gc); +  }    if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE &&    Pike_in_gc != GC_PASS_ZAP_WEAK)    fatal("gc_delayed_free() called in invalid gc pass.\n");    if (gc_debug) {    if (!(m = find_marker(a)))    gc_fatal(a, 0, "gc_delayed_free() got unknown object (missed by pretouch pass).\n");    }    else m = get_marker(a);    if (*(INT32 *) a != 1)    fatal("gc_delayed_free() called for thing that haven't got a single ref.\n");
pike.git/src/gc.c:1405: Inside #if defined(PIKE_DEBUG)
   debug_malloc_touch(a);    delayed_freed++;   #else    m = get_marker(a);   #endif       gc_add_extra_ref(a);    m->flags |= GC_GOT_DEAD_REF;   }    + #ifdef PIKE_DEBUG + void gc_mark_enqueue(queue_call call, void *data) + { +  struct marker *m; +  if (gc_is_watching && (m = find_marker(data)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_mark_enqueue() in pass %d.\n", data, Pike_in_gc); +  } +  enqueue(&gc_mark_queue, call, data); + } + #endif +    int gc_mark(void *a)   {    struct marker *m = get_marker(debug_malloc_pass(a));      #ifdef PIKE_DEBUG -  +  if (gc_is_watching && m && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_mark() in pass %d.\n", a, Pike_in_gc); +  }    if (!a) fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)    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 < 0)    gc_fatal(a, 0, "Marking thing scheduled for weak free.\n");   #endif       if (Pike_in_gc == GC_PASS_ZAP_WEAK) {
pike.git/src/gc.c:1459:    m->flags = (m->flags & ~GC_NOT_REFERENCED) | GC_MARKED;    DO_IF_DEBUG(marked++);    return 1;    }   }      PMOD_EXPORT void gc_cycle_enqueue(gc_cycle_check_cb *checkfn, void *data, int weak)   {    struct gc_frame *l = alloc_gc_frame();   #ifdef PIKE_DEBUG +  { +  struct marker *m; +  if (gc_is_watching && (m = find_marker(data)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_cycle_enqueue() in pass %d.\n", data, Pike_in_gc); +  } +  }    if (Pike_in_gc != GC_PASS_CYCLE)    gc_fatal(data, 0, "Use of the gc frame stack outside the cycle check pass.\n");   #endif   #ifdef GC_VERBOSE    if (++num_gc_frames > max_gc_frames) max_gc_frames = num_gc_frames;   #endif    l->data = data;    l->u.link.checkfn = checkfn;    l->u.link.weak = weak;    l->frameflags = 0;
pike.git/src/gc.c:1642: Inside #if defined(GC_STACK_DEBUG)
   fputc('\n', stderr);    }   #endif   }      int gc_cycle_push(void *x, struct marker *m, int weak)   {    struct marker *last = find_marker(gc_rec_last->data);      #ifdef PIKE_DEBUG +  if (gc_is_watching && m && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_cycle_push() in pass %d.\n", x, Pike_in_gc); +  }       debug_malloc_touch(x);       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_PRETOUCHED))    gc_fatal(x, 0, "gc_cycle_push() called for untouched thing.\n");    if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) &&
pike.git/src/gc.c:1917:   #endif    return 1;   }      static void gc_cycle_pop(void *a)   {    struct marker *m = find_marker(a);    struct gc_frame *here, *base, *p;      #ifdef PIKE_DEBUG +  if (gc_is_watching && m && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_cycle_pop() in pass %d.\n", a, Pike_in_gc); +  }    if (!a) fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_CYCLE)    fatal("GC cycle pop attempted in invalid pass.\n");    if (!(m->flags & GC_CYCLE_CHECKED))    gc_fatal(a, 0, "Marker being popped doesn't have GC_CYCLE_CHECKED.\n");    if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) &&    *(INT32 *) a)    gc_fatal(a, 1, "Got a referenced marker to gc_cycle_pop.\n");    if (m->flags & GC_XREFERENCED)    gc_fatal(a, 1, "Doing cycle check in externally referenced thing "
pike.git/src/gc.c:2027:      void do_gc_recurse_short_svalue(union anything *u, TYPE_T type)   {    gc_recurse_short_svalue(u, type);   }      int gc_do_free(void *a)   {    struct marker *m;   #ifdef PIKE_DEBUG +  if (gc_is_watching && (m = find_marker(a)) && m->flags & GC_WATCHED) { +  /* This is useful to set breakpoints on. */ +  fprintf(stderr, "## Watched thing %p found in " +  "gc_do_free() in pass %d.\n", a, Pike_in_gc); +  }    if (!a) fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_FREE)    fatal("gc free attempted in invalid pass.\n");   #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)) {
pike.git/src/gc.c:2134: Inside #if defined(DEBUG_MALLOC)
  #ifdef DEBUG_MALLOC    if(debug_options & GC_RESET_DMALLOC)    reset_debug_malloc();   #endif    init_gc();    gc_generation++;    Pike_in_gc=GC_PASS_PREPARE;   #ifdef PIKE_DEBUG    gc_debug = d_flag;    SET_ONERROR(uwp, fatal_on_error, "Shouldn't get an exception inside the gc.\n"); +  if (gc_is_watching) +  fprintf(stderr, "## Doing gc while watching for %d things.\n", gc_is_watching);   #endif       destruct_objects_to_destruct();       if(gc_evaluator_callback)    {    remove_callback(gc_evaluator_callback);    gc_evaluator_callback=0;    }