Branch: Tag:

2003-02-01

2003-02-01 15:43:51 by Martin Stjernholm <mast@lysator.liu.se>

Enabled some consistency checks in the gc when compiled without rtldebug
(only activated on debug level 1 or higher). Always define _verify_internals
to be able to use this.

Made it possible to turn on trace messages for the gc only with
trace(1,"gc"). This is the embryo of a facility based trace system. Still to
do: Raise all the global trace levels to make room for gc only trace at
level 1, and fix a framework for trace facilities.

Rev: src/array.c:1.137
Rev: src/builtin.cmod:1.113
Rev: src/builtin_functions.c:1.466
Rev: src/gc.c:1.199
Rev: src/gc.h:1.97
Rev: src/mapping.c:1.162
Rev: src/multiset.c:1.68
Rev: src/object.c:1.218
Rev: src/program.c:1.477

2:   || This file is part of Pike. For copyright information see COPYRIGHT.   || Pike is distributed under GPL, LGPL and MPL. See the file COPYING   || for more information. - || $Id: gc.c,v 1.198 2003/01/15 21:41:28 mast Exp $ + || $Id: gc.c,v 1.199 2003/02/01 15:43:50 mast Exp $   */      #include "global.h"
32:      #include "block_alloc.h"    - RCSID("$Id: gc.c,v 1.198 2003/01/15 21:41:28 mast Exp $"); + RCSID("$Id: gc.c,v 1.199 2003/02/01 15:43:50 mast Exp $");      int gc_enabled = 1;   
105:   int gc_generation = 0;   struct pike_queue gc_mark_queue;   time_t last_gc; + int gc_trace = 0, gc_debug = 0;      struct gc_frame   {
314:   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
618:    fprintf(stderr, "no marker\n");   }    + #endif /* PIKE_DEBUG */ +    void debug_gc_fatal(void *a, int flags, const char *fmt, ...)   {    struct marker *m;
631:       va_end(args);    + #ifdef PIKE_DEBUG    if (a) {    /* Temporarily jumping out of gc to avoid being catched in debug    * checks in describe(). */
653:    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)   {   #if 0
1108:    fprintf(stderr, "## Already watching thing %p.\n", a);   }    + #endif /* PIKE_DEBUG */ +    void debug_gc_touch(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_touch() in pass %d.\n", a, Pike_in_gc);    } -  + #endif       if (!a) Pike_fatal("Got null pointer.\n");       switch (Pike_in_gc) {    case GC_PASS_PRETOUCH:    m = find_marker(a); -  if (m && !(m->flags & (GC_PRETOUCHED|GC_WATCHED))) +  if (m && !(m->flags & (GC_PRETOUCHED + #ifdef PIKE_DEBUG +  |GC_WATCHED + #endif +  )))    gc_fatal(a, 1, "Thing got an existing but untouched marker.\n");    m = get_marker(a);    m->flags |= GC_PRETOUCHED; -  + #ifdef PIKE_DEBUG    m->saved_refs = *(INT32 *) a; -  + #endif    break;       case GC_PASS_MIDDLETOUCH: {
1137:    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"); + #ifdef PIKE_DEBUG    extra_ref = (m->flags & GC_GOT_EXTRA_REF) == GC_GOT_EXTRA_REF;    if (m->saved_refs + extra_ref < *(INT32 *) a)    if (m->flags & GC_WEAK_FREED)
1144:    "or it has gotten more references since gc start.\n");    else    gc_fatal(a, 1, "Thing has gotten more references since gc start.\n"); -  else if (m->weak_refs > m->saved_refs) +  else +  if (m->weak_refs > m->saved_refs)    gc_fatal(a, 0, "A thing got more weak references than references.\n"); -  + #endif    m->flags |= GC_MIDDLETOUCHED;    break;    }
1161:    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)
1186:    else    gc_fatal(a, 3, "A thing to garb is still around.\n");    } + #endif    }    break;   
1194:    }   }    + #ifdef PIKE_DEBUG +    static INLINE struct marker *gc_check_debug(void *a, int weak)   {    struct marker *m;
2427:    cpu_time_t gc_start_time;    ptrdiff_t objs, pre_kill_objs;   #ifdef PIKE_DEBUG - #ifdef HAVE_GETHRTIME -  hrtime_t gcstarttime = 0; - #endif +     unsigned destroy_count, obj_count;    ONERROR uwp;   #endif
2454:    gc_generation++;    Pike_in_gc=GC_PASS_PREPARE;    gc_start_time = get_cpu_time(); - #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");    if (gc_is_watching)    fprintf(stderr, "## Doing gc while watching for %d things.\n", gc_is_watching);
2472:    objs=num_objects;    last_cycle = 0;    -  if(GC_VERBOSE_DO(1 ||) Pike_interpreter.trace_level) { +  if(GC_VERBOSE_DO(1 ||) gc_trace) {    fprintf(stderr,"Garbage collecting ... ");    GC_VERBOSE_DO(fprintf(stderr, "\n"));    }
2492: Inside #if defined(PIKE_DEBUG)
  #ifdef PIKE_DEBUG    delayed_freed = weak_freed = checked = marked = cycle_checked = live_ref = 0;    live_rec = frame_rot = 0; + #endif    if (gc_debug) {    unsigned n;    Pike_in_gc = GC_PASS_PRETOUCH;
2500: Inside #if defined(PIKE_DEBUG)
   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)    Pike_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;
2639:    delayed_freed - obj_count));    }    - #ifdef PIKE_DEBUG +     if (gc_debug) {    unsigned n;    size_t i;
2650: Inside #if defined(PIKE_DEBUG)
   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)    Pike_fatal("Object count wrong in gc; expected %d, got %d.\n", num_objects, n);    get_marker(rec_list.data)->flags |= GC_MIDDLETOUCHED;   #if 0 /* Temporarily disabled - Hubbe */ -  + #ifdef PIKE_DEBUG   #ifdef DEBUG_MALLOC    PTR_HASH_LOOP(marker, i, m)    if (!(m->flags & (GC_MIDDLETOUCHED|GC_WEAK_FREED)) &&
2671: Inside #if defined(PIKE_DEBUG) and #if 0 /* Temporarily disabled - Hubbe */
   }   #endif   #endif + #endif    GC_VERBOSE_DO(fprintf(stderr, "| middletouch\n"));    } - #endif +        /* Thread switches, object alloc/free and reference changes are    * allowed again now. */
2780:    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;
2794: Inside #if defined(PIKE_DEBUG)
   Pike_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)    Pike_fatal("Lost track of %d extra refs to things in gc.\n", gc_extra_refs);    if(fatal_after_gc) Pike_fatal("%s", fatal_after_gc);
2880:       alloc_threshold = (ptrdiff_t)new_threshold;    -  if(GC_VERBOSE_DO(1 ||) Pike_interpreter.trace_level) +  if(GC_VERBOSE_DO(1 ||) gc_trace)    {    if (last_gc_time)    fprintf(stderr, "done (%"PRINTSIZET"d of %"PRINTSIZET"d "