pike.git / src / gc.c

version» Context lines:

pike.git/src/gc.c:1:   /*   || 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.243 2004/03/16 14:23:20 mast Exp $ + || $Id: gc.c,v 1.244 2004/03/16 18:34:43 mast Exp $   */      #include "global.h"      struct callback *gc_evaluator_callback=0;      #include "array.h"   #include "multiset.h"   #include "mapping.h"   #include "object.h"
pike.git/src/gc.c:26:   #include "interpret.h"   #include "bignum.h"   #include "pike_threadlib.h"      #include "gc.h"   #include "main.h"   #include <math.h>      #include "block_alloc.h"    - RCSID("$Id: gc.c,v 1.243 2004/03/16 14:23:20 mast Exp $"); + RCSID("$Id: gc.c,v 1.244 2004/03/16 18:34:43 mast Exp $");      int gc_enabled = 1;      /* These defaults are only guesses and hardly tested at all. Please improve. */   double gc_garbage_ratio_low = 0.2;   double gc_time_ratio = 0.05;   double gc_garbage_ratio_high = 0.5;      /* This slowness factor approximately corresponds to the average over    * the last ten gc rounds. (0.9 == 1 - 1/10) */
pike.git/src/gc.c:334:       return PIKE_T_UNKNOWN;   }      void *check_for =0;   void *gc_svalue_location=0;   static size_t found_ref_count;      char *fatal_after_gc=0;    - #ifdef DEBUG_MALLOC -  - /* To keep the markers after the gc. Only used for the dmalloc leak -  * report at exit. */ + #ifdef DO_PIKE_CLEANUP + /* To keep the markers after the gc. Only used for the leak report at exit. */   int gc_keep_markers = 0; -  +    int gc_external_refs_zapped = 0; -  +    #endif      #define DESCRIBE_MEM 1   #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:785: Inside #if defined(PIKE_DEBUG)
   for (o = first_object; o && o != (struct object *) a; o = o->next) {}    if (!o)    fprintf(stderr,"%*s**The object is not on the object link list.\n",indent,"");    for (o = objects_to_destruct; o && o != (struct object *) a; o = o->next) {}    if (o)    fprintf(stderr,"%*s**The object is on objects_to_destruct.\n",indent,"");    }       if(!p)    { -  fprintf(stderr,"%*s**The object is destructed.\n",indent,""); +     p=id_to_program(((struct object *)a)->program_id); -  +  if(p) +  fprintf(stderr,"%*s**The object is destructed but program found from id.\n", +  indent,""); +  else +  fprintf(stderr,"%*s**The object is destructed and program not found from id.\n", +  indent,"");    }       if (p) {    size_t inh_idx, var_idx, var_count = 0;       fprintf (stderr, "%*s**Object variables:\n", indent, "");       for (inh_idx = 0; inh_idx < p->num_inherits; inh_idx++) {    struct inherit *inh = p->inherits + inh_idx;    struct program *p2 = inh->prog;
pike.git/src/gc.c:1197:    case T_FUNCTION:    if(s->subtype == FUNCTION_BUILTIN)    {    fprintf(stderr," Builtin function: %s\n",s->u.efun->name->str);    }else{    if(!s->u.object->prog)    {    struct program *p=id_to_program(s->u.object->program_id);    if(p)    { -  fprintf(stderr," Function (destructed) name: %s\n",ID_FROM_INT(p,s->subtype)->name->str); +  fprintf(stderr," Function in destructed object: %s\n", +  ID_FROM_INT(p,s->subtype)->name->str);    }else{    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); +  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,1,0,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);   }    -  + static void gc_watched_found (struct marker *m, const char *found_in) + { +  fprintf(stderr, "## Watched thing %p with %d refs found in " +  "%s in pass %d.\n", m->data, *(INT32 *) m->data, found_in, Pike_in_gc); +  describe_marker (m); + } +    #endif /* PIKE_DEBUG */      #ifndef GC_MARK_DEBUG   struct pike_queue gc_mark_queue;   #else /* !GC_MARK_DEBUG */      /* Cut'n'paste from queue.c. */      struct gc_queue_entry   {
pike.git/src/gc.c:1293:   {    struct gc_queue_block *b;      #ifdef PIKE_DEBUG    if (gc_found_in_type == PIKE_T_UNKNOWN || !gc_found_in)    gc_fatal (data, 0, "gc_mark_enqueue() called outside GC_ENTER.\n");    {    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); +  gc_watched_found (m, "gc_mark_enqueue()");    }    }   #endif       b=gc_mark_last;    if(!b || b->used >= GC_QUEUE_ENTRIES)    {    b = (struct gc_queue_block *) malloc (sizeof (struct gc_queue_block));    if (!b) fatal ("Out of memory in gc.\n");    b->used=0;
pike.git/src/gc.c:1330:      #endif /* GC_MARK_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); +  gc_watched_found (m, "gc_touch()");    }   #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   #ifdef PIKE_DEBUG
pike.git/src/gc.c:1478:   PMOD_EXPORT INT32 real_gc_check(void *a)   {    struct marker *m;    INT32 ret;      #ifdef PIKE_DEBUG    if (gc_found_in_type == PIKE_T_UNKNOWN || !gc_found_in)    gc_fatal (a, 0, "gc_check() called outside GC_ENTER.\n");    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); +  gc_watched_found (m, "gc_check()");    }    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;
pike.git/src/gc.c:1503:   INT32 real_gc_check_weak(void *a)   {    struct marker *m;    INT32 ret;      #ifdef PIKE_DEBUG    if (gc_found_in_type == PIKE_T_UNKNOWN || !gc_found_in)    gc_fatal (a, 0, "gc_check_weak() called outside GC_ENTER.\n");    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); +  gc_watched_found (m, "gc_check_weak()");    }    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);
pike.git/src/gc.c:1546:    remove_marker(marker_hash_table[e]->data);   #endif    exit_marker_hash();   }         static void init_gc(void)   {   #ifdef PIKE_DEBUG    if (!gc_is_watching) { - #endif - #ifdef DEBUG_MALLOC +     /* The marker hash table is left around after a previous gc if    * gc_keep_markers is set. */    if (marker_hash_table) cleanup_markers();   #endif       low_init_marker_hash(num_objects);    get_marker(rec_list.data); /* Used to simplify fencepost conditions. */   #ifdef PIKE_DEBUG    }   #endif   }      static void exit_gc(void)   {    if (gc_evaluator_callback) {    remove_callback(gc_evaluator_callback);    gc_evaluator_callback = NULL;    } - #ifdef DEBUG_MALLOC +     if (!gc_keep_markers) - #endif +     cleanup_markers();       free_all_gc_frame_blocks();      #ifdef GC_VERBOSE    num_gc_frames = 0;   #endif      #ifdef PIKE_DEBUG    if (gc_is_watching) {
pike.git/src/gc.c:1653: Inside #if defined(PIKE_DEBUG)
   if(i) exit_gc();    d_flag=tmp;   }      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); +  gc_watched_found (m, "gc_add_extra_ref()");    }       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);
pike.git/src/gc.c:1679: Inside #if defined(PIKE_DEBUG)
   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); +  gc_watched_found (m, "gc_free_extra_ref()");    }       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);
pike.git/src/gc.c:1705: Inside #if defined(PIKE_DEBUG)
   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); +  gc_watched_found (m, "gc_is_referenced()");    }       if (!a) Pike_fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_MARK)    Pike_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))
pike.git/src/gc.c:1735: Inside #if defined(PIKE_DEBUG)
      return !(m->flags & GC_NOT_REFERENCED);   }      int gc_mark_external (void *a, const char *place)   {    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_mark_external() in pass %d.\n", a, Pike_in_gc); +  gc_watched_found (m, "gc_mark_external()");    }       if (!a) Pike_fatal("Got null pointer.\n");       if(Pike_in_gc == GC_PASS_LOCATE)    {    if(a==check_for) {    const char *orig_gc_found_place = gc_found_place;    gc_found_place = place;    gdb_gc_stop_here(a, 0);
pike.git/src/gc.c:1799:      #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); +  gc_watched_found (m, "gc_do_weak_free()");    }    if (!a) Pike_fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)    Pike_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:1862:    return 1;   }      void gc_delayed_free(void *a, int type)   {    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); +  gc_watched_found (m, "gc_delayed_free()");    }    if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_CYCLE &&    Pike_in_gc != GC_PASS_ZAP_WEAK)    Pike_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)
pike.git/src/gc.c:1910:    m->flags |= GC_GOT_DEAD_REF;   }      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); +  gc_watched_found (m, "gc_mark()");    }    if (!a) Pike_fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_MARK && Pike_in_gc != GC_PASS_ZAP_WEAK)    Pike_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   
pike.git/src/gc.c:1966:   }      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); +  gc_watched_found (m, "gc_cycle_enqueue()");    }    }    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;
pike.git/src/gc.c:2165:   #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); +  gc_watched_found (m, "gc_cycle_push()");    }       debug_malloc_touch(x);       if (!x) Pike_fatal("Got null pointer.\n");    if (m->data != x) Pike_fatal("Got wrong marker.\n");    if (Pike_in_gc != GC_PASS_CYCLE)    Pike_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");
pike.git/src/gc.c:2449:   }      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); +  gc_watched_found (m, "gc_cycle_pop()");    }    if (!a) Pike_fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_CYCLE)    Pike_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 (!gc_destruct_everything) {    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");
pike.git/src/gc.c:2567:   {    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); +  gc_watched_found (m, "gc_do_free()");    }    if (!a) Pike_fatal("Got null pointer.\n");    if (Pike_in_gc != GC_PASS_FREE)    Pike_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. */       if (gc_destruct_everything) {
pike.git/src/gc.c:2705:    }       CALL_AND_UNSET_ONERROR(tmp);   }      size_t do_gc(void *ignored, int explicit_call)   {    size_t start_num_objs, start_allocs, unreferenced;    cpu_time_t gc_start_time;    ptrdiff_t objs, pre_kill_objs; + #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP) +  unsigned destroy_count; + #endif   #ifdef PIKE_DEBUG -  unsigned destroy_count, obj_count; +  unsigned obj_count;    ONERROR uwp;   #endif       if(Pike_in_gc) return 0;       if (gc_enabled <= 0 && (gc_enabled < 0 || !explicit_call)) {    num_allocs = 0;    alloc_threshold = GC_MAX_ALLOC_THRESHOLD;    if (gc_evaluator_callback) {    remove_callback (gc_evaluator_callback);
pike.git/src/gc.c:3018:    Pike_in_gc=GC_PASS_KILL;    /* Destruct the live objects in cycles, but first warn about any bad    * cycles. */    pre_kill_objs = num_objects;    if (last_cycle && Pike_interpreter.evaluator_stack &&    !gc_destruct_everything) {    objs -= num_objects;    warn_bad_cycles();    objs += num_objects;    } - #ifdef PIKE_DEBUG + #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP)    destroy_count = 0;   #endif    while (kill_list) {    struct gc_frame *next = NEXT(kill_list);    struct object *o = (struct object *) kill_list->data;   #ifdef PIKE_DEBUG    if (!(kill_list->frameflags & GC_ON_KILL_LIST))    gc_fatal(o, 0, "Kill list element hasn't got the proper flag.\n");    if ((get_marker(kill_list->data)->flags & (GC_LIVE|GC_LIVE_OBJ)) !=    (GC_LIVE|GC_LIVE_OBJ))
pike.git/src/gc.c:3049:    INT32 line;    struct pike_string *file = get_program_line (o->prog, &line);    fprintf(stderr, ", prog %s:%d\n", file->str, line);    free_string(file);    }    else fputs(", is destructed\n", stderr);    );    destruct(o);    free_object(o);    gc_free_extra_ref(o); - #ifdef PIKE_DEBUG + #if defined (PIKE_DEBUG) || defined (DO_PIKE_CLEANUP)    destroy_count++;   #endif    debug_really_free_gc_frame(kill_list);    kill_list = next;    }       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;
pike.git/src/gc.c:3226: Inside #if defined(PIKE_DEBUG)
   tot_cycle_checked += cycle_checked;    tot_live_rec += live_rec, tot_frame_rot += frame_rot;   #endif      #ifdef ALWAYS_GC    ADD_GC_CALLBACK();   #else    if(d_flag > 3) ADD_GC_CALLBACK();   #endif    + #ifdef DO_PIKE_CLEANUP +  if (gc_destruct_everything) +  return destroy_count; + #endif    return unreferenced;   }      /*! @decl mapping(string:int|float) gc_status()    *! @belongs Debug    *!    *! Get statistics from the garbage collector.    *!    *! @returns    *! A mapping with the following content will be returned: