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.241 2004/03/15 22:23:14 mast Exp $ + || $Id: gc.c,v 1.242 2004/03/15 22:47:15 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.241 2004/03/15 22:23:14 mast Exp $"); + RCSID("$Id: gc.c,v 1.242 2004/03/15 22:47:15 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:101:   #define GC_VERBOSE_DO(X)   #endif      int num_objects = 3; /* Account for *_empty_array. */   int num_allocs =0;   ptrdiff_t alloc_threshold = GC_MIN_ALLOC_THRESHOLD;   PMOD_EXPORT int Pike_in_gc = 0;   int gc_generation = 0;   time_t last_gc;   int gc_trace = 0, gc_debug = 0; + #ifdef DO_PIKE_CLEANUP + int gc_destruct_everything = 0; + #else + #define gc_destruct_everything 0 + #endif      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:1389:    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 (gc_destruct_everything) +  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 "    "got missed by gc_is_referenced().\n");    else if (!(m->flags & GC_DO_FREE))
pike.git/src/gc.c:2172: Inside #if defined(PIKE_DEBUG)
   }       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"); +  if (!gc_destruct_everything) {    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 (weak && gc_rec_last == &rec_list)    gc_fatal(x, 1, "weak is %d when on top of stack.\n", weak);    if (gc_debug > 1) {    struct array *a;    struct object *o;    struct program *p;    struct mapping *m;    struct multiset *l;    for(a = gc_internal_array; a; a = a->next)    if(a == (struct array *) x) goto on_gc_internal_lists;
pike.git/src/gc.c:2450: Inside #if defined(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) 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");    if (m->flags & GC_XREFERENCED)    gc_fatal(a, 1, "Doing cycle check in externally referenced thing "    "missed in mark pass.\n"); -  +  }   #endif   #ifdef GC_CYCLE_DEBUG    gc_cycle_indent -= 2;   #endif       if (m->flags & GC_LIVE_RECURSE) {    m->flags &= ~GC_LIVE_RECURSE;    CYCLE_DEBUG_MSG(m, "gc_cycle_pop_live");    gc_rec_last = PREV(gc_rec_top);    debug_really_free_gc_frame(gc_rec_top);
pike.git/src/gc.c:2569: Inside #if defined(PIKE_DEBUG)
   "gc_do_free() in pass %d.\n", a, Pike_in_gc);    }    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) { +  /* We don't actually free much in this mode, just destruct +  * objects. So when we normally would return nonzero we just +  * remove the extra ref again. */ +  if (!(m->flags & GC_LIVE)) { +  if (*(INT32 *) a == 1) +  return 1; +  else { +  gc_free_extra_ref (a); +  --*(INT32 *) a; +  } +  } +  return 0; +  } +    #ifdef PIKE_DEBUG    if (*(INT32 *) a > !!(m->flags & GC_GOT_EXTRA_REF)) { -  if (!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED) +  if (!gc_destruct_everything && +  (!(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_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) +  if(!gc_destruct_everything && +  (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);   }      static void free_obj_arr(void *oa)   {
pike.git/src/gc.c:2790:       /* Anything after and including gc_internal_* in the linked lists    * are considered to lack external references. The mark pass move    * externally referenced things in front of these pointers. */    gc_internal_array = first_array;    gc_internal_multiset = first_multiset;    gc_internal_mapping = first_mapping;    gc_internal_program = first_program;    gc_internal_object = first_object;    +  if (gc_destruct_everything) { +  GC_VERBOSE_DO(fprintf(stderr, +  "| mark pass skipped - will destruct all objects\n")); +  } +  else {    /* Next we mark anything with external references. Note that we can    * follow the same reference several times, e.g. with shared mapping    * data blocks. */    ACCEPT_UNFINISHED_TYPE_FIELDS {    gc_mark_all_arrays();    gc_mark_run_queue();    gc_mark_all_multisets();    gc_mark_run_queue();    gc_mark_all_mappings();    gc_mark_run_queue();
pike.git/src/gc.c:2814: Inside #if defined(PIKE_DEBUG)
  #ifdef PIKE_DEBUG    if(gc_debug) gc_mark_all_strings();   #endif /* PIKE_DEBUG */    } END_ACCEPT_UNFINISHED_TYPE_FIELDS;       GC_VERBOSE_DO(fprintf(stderr,    "| mark: %u markers referenced, %u weak references freed,\n"    "| %d things to free, "    "got %"PRINTSIZET"u tricky weak refs\n",    marked, weak_freed, delayed_freed, gc_ext_weak_refs)); +  }       {   #ifdef PIKE_DEBUG    size_t orig_ext_weak_refs = gc_ext_weak_refs;    obj_count = delayed_freed;    max_gc_frames = 0;   #endif    Pike_in_gc=GC_PASS_CYCLE;       /* Now find all cycles in the internal structures. Note that we can
pike.git/src/gc.c:2980: Inside #if defined(PIKE_DEBUG)
   gc_internal_program = (struct program *) (ptrdiff_t) -1;    gc_internal_object = (struct object *) (ptrdiff_t) -1;       if(fatal_after_gc) Pike_fatal("%s", fatal_after_gc);   #endif       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) { +  if (last_cycle && Pike_interpreter.evaluator_stack && +  !gc_destruct_everything) {    objs -= num_objects;    warn_bad_cycles();    objs += num_objects;    }   #ifdef PIKE_DEBUG    destroy_count = 0;   #endif    while (kill_list) {    struct gc_frame *next = NEXT(kill_list);    struct object *o = (struct object *) kill_list->data;
pike.git/src/gc.c:3049:    n += gc_touch_all_programs();    n += gc_touch_all_objects();    /* gc_touch_all_strings(); */    if (n != (unsigned) num_objects)    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) {    size_t e; -  struct marker *m; +     fprintf (stderr, "Lost track of %d extra refs to things in gc.\n"    "Searching for marker(s) with extra refs:\n", gc_extra_refs); -  for (e = 0; e < marker_hash_table_size; e++) -  for (m = marker_hash_table[e]; m; m = m->next) +  for (e = 0; e < marker_hash_table_size; e++) { +  struct marker *s = marker_hash_table[e], *m; +  for (m = s; m;) {    if (m->flags & GC_GOT_EXTRA_REF) {    fprintf (stderr, "========================================\n"    "Found marker with extra ref: ");    describe_marker (m);    fprintf (stderr, "Describing the thing pointed to:\n");    describe (m->data);    } -  +  m = m->next; +  /* The marker might be moved to the head of the chain via +  * describe() above, so do this to avoid infinite recursion. +  * Some entries in the chain might be missed, but I don't want +  * to bother. */ +  if (m == s) break; +  } +  }    fprintf (stderr, "========================================\n"    "Done searching for marker(s) with extra refs.\n");    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);   #endif       Pike_in_gc=0;    exit_gc();