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.151 2003/01/12 17:25:31 mast Exp $"); + RCSID("$Id: gc.c,v 1.152 2003/01/29 15:55:25 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:94:   #else   #define GC_VERBOSE_DO(X)   #endif      INT32 num_objects = 3; /* Account for *_empty_array. */   INT32 num_allocs =0;   ptrdiff_t alloc_threshold = MIN_ALLOC_THRESHOLD;   PMOD_EXPORT int Pike_in_gc = 0;   struct pike_queue gc_mark_queue;   time_t last_gc; + int gc_trace = 0, gc_debug = 0;      struct gc_frame   {    struct gc_frame *back; /* Previous stack frame. */    void *data;    union {    struct { /* Pop frame. */    struct gc_frame *prev; /* Previous frame in rec_list. */    struct gc_frame *next; /* Next pointer in rec_list and kill_list. */    unsigned INT16 cycle; /* Cycle id number. */
pike.git/src/gc.c:289:       return PIKE_T_UNKNOWN;   }      void *check_for =0;   static char *found_where="";   static void *found_in=0;   static int found_in_type=0;   void *gc_svalue_location=0;   char *fatal_after_gc=0; - int gc_debug = 0; +       #define DESCRIBE_MEM 1   #define DESCRIBE_NO_REFS 2   #define DESCRIBE_SHORT 4   #define DESCRIBE_NO_DMALLOC 8      /* type == -1 means that memblock is a char* and should be    * really be printed..    */   void describe_location(void *real_memblock,
pike.git/src/gc.c:516: Inside #if defined(PIKE_DEBUG)
   describe_gc_frame(m->frame);    putc(']', stderr);    }   #endif    putc('\n', stderr);    }    else    fprintf(stderr, "no marker\n");   }    + #endif /* PIKE_DEBUG */ +    void debug_gc_fatal(void *a, int flags, const char *fmt, ...)   {    va_list args;       va_start(args, fmt);       fprintf(stderr, "**");    (void) VFPRINTF(stderr, fmt, args);       va_end(args);    -  + #ifdef PIKE_DEBUG    describe(a);    if (flags & 1) locate_references(a);    if (flags & 2)    fatal_after_gc = "Fatal in garbage collector.\n";    else -  + #endif    debug_fatal("Fatal in garbage collector.\n");   }    -  + #ifdef PIKE_DEBUG +    static void gdb_gc_stop_here(void *a, int weak)   {    fprintf(stderr,"***One %sref found%s. ",    weak ? "weak " : "",    found_where?found_where:"");    describe_location(found_in , found_in_type, gc_svalue_location,0,1,0);    fprintf(stderr,"----------end------------\n");   }      void debug_gc_xmark_svalues(struct svalue *s, ptrdiff_t num, char *fromwhere)
pike.git/src/gc.c:847:    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);   }    + #endif /* PIKE_DEBUG */ +    void debug_gc_touch(void *a)   {    struct marker *m;    if (!a) fatal("Got null pointer.\n");    m = find_marker(a);       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");
pike.git/src/gc.c:878:    case GC_PASS_POSTTOUCH:    if (!*(INT32 *) a)    gc_fatal(a, 1, "Found a thing without refs.\n");    if (m) {    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"); + #ifdef PIKE_DEBUG    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");    else if (!(m->flags & GC_CYCLE_CHECKED))    gc_fatal(a, 2, "A thing was missed by "    "both mark and cycle check pass.\n");    else if (!(m->flags & GC_IS_REFERENCED))    gc_fatal(a, 2, "An unreferenced thing "
pike.git/src/gc.c:903:    gc_fatal(a, 2, "A thing still got an extra ref.\n");    else if (m->weak_refs > m->saved_refs)    gc_fatal(a, 2, "A thing got more weak references than references.\n");    else if (!(m->flags & GC_LIVE)) {    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");    } + #endif    }    break;       default:    fatal("debug_gc_touch() used in invalid gc pass.\n");    }   }    -  + #ifdef PIKE_DEBUG +    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)    {    gdb_gc_stop_here(a, weak);
pike.git/src/gc.c:1978: Inside #if defined(PIKE_DEBUG) and #if defined(HAVE_GETHRTIME)
  #ifdef HAVE_GETHRTIME    hrtime_t gcstarttime = 0;   #endif    unsigned destroy_count, obj_count;    ONERROR uwp;   #endif       if(Pike_in_gc) return 0;    init_gc();    Pike_in_gc=GC_PASS_PREPARE; - #ifdef PIKE_DEBUG +     gc_debug = d_flag; -  + #ifdef PIKE_DEBUG    SET_ONERROR(uwp, fatal_on_error, "Shouldn't get an exception inside the gc.\n");   #endif       destruct_objects_to_destruct();       if(gc_evaluator_callback)    {    remove_callback(gc_evaluator_callback);    gc_evaluator_callback=0;    }       objs=num_objects;    last_cycle = 0;    - #ifdef PIKE_DEBUG -  if(GC_VERBOSE_DO(1 ||) t_flag) { +  if(GC_VERBOSE_DO(1 ||) gc_trace) {    fprintf(stderr,"Garbage collecting ... ");    GC_VERBOSE_DO(fprintf(stderr, "\n"));   #ifdef HAVE_GETHRTIME    gcstarttime = gethrtime();   #endif    } -  + #ifdef PIKE_DEBUG    if(num_objects < 0)    fatal("Panic, less than zero objects!\n");   #endif       last_gc=TIME(0);       multiplier=pow(MULTIPLIER, (double) num_allocs / (double) alloc_threshold);    objects_alloced*=multiplier;    objects_alloced += (double) num_allocs * (1.0 - multiplier);       objects_freed*=multiplier;       start_num_objs = num_objects;       /* Thread switches, object alloc/free and any reference changes are    * disallowed now. */      #ifdef PIKE_DEBUG    weak_freed = checked = marked = cycle_checked = live_ref = 0; -  + #endif    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(); -  + #ifdef PIKE_DEBUG    gc_touch_all_strings(); -  + #endif    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();   
pike.git/src/gc.c:2136:   #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));    }    - #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(); -  + #ifdef PIKE_DEBUG    gc_touch_all_strings(); -  + #endif    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;   #if 0 -  + #ifdef PIKE_DEBUG   #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   #endif -  + #endif    GC_VERBOSE_DO(fprintf(stderr, "| middletouch\n"));    } - #endif +        if (gc_ext_weak_refs) {    size_t to_free = gc_ext_weak_refs;   #ifdef PIKE_DEBUG    obj_count = num_objects;   #endif    Pike_in_gc = GC_PASS_ZAP_WEAK;    /* Zap weak references from external to internal things. That    * doesn't occur very often; only when something have both    * external weak refs and nonweak cyclic refs from internal
pike.git/src/gc.c:2305:    GC_VERBOSE_DO(fprintf(stderr, "| kill: %u objects killed, %d things really freed\n",    destroy_count, pre_kill_objs - num_objects));       Pike_in_gc=GC_PASS_DESTRUCT;    /* Destruct objects on the destruct queue. */    GC_VERBOSE_DO(obj_count = num_objects);    destruct_objects_to_destruct();    GC_VERBOSE_DO(fprintf(stderr, "| destruct: %d things really freed\n",    obj_count - num_objects));    - #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));    } -  + #ifdef PIKE_DEBUG    if (gc_extra_refs)    fatal("Lost track of %d extra refs to things in gc.\n", gc_extra_refs);    if(fatal_after_gc) fatal("%s", fatal_after_gc);   #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
pike.git/src/gc.c:2352:    tmp = (double)MIN_ALLOC_THRESHOLD;    if(tmp > MAX_ALLOC_THRESHOLD)    tmp = (double)MAX_ALLOC_THRESHOLD;       alloc_threshold = (ptrdiff_t)tmp;       num_allocs=0;      #ifdef PIKE_DEBUG    UNSET_ONERROR (uwp); -  if(GC_VERBOSE_DO(1 ||) t_flag) + #endif +  if(GC_VERBOSE_DO(1 ||) gc_trace)    {   #ifdef HAVE_GETHRTIME    fprintf(stderr,"done (freed %d of %d objects), %ld ms.\n",    (int)objs,start_num_objs,    (long)((gethrtime() - gcstarttime)/1000000));   #else    fprintf(stderr,"done (freed %d of %d objects)\n",    (int)objs,start_num_objs);   #endif    } - #endif +       #ifdef ALWAYS_GC    ADD_GC_CALLBACK();   #else    if(d_flag > 3) ADD_GC_CALLBACK();   #endif       return objs;   }