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.160 2001/06/30 07:05:54 hubbe Exp $"); + RCSID("$Id: gc.c,v 1.161 2001/06/30 21:28:35 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:226:   PTR_HASH_ALLOC(marker,MARKER_CHUNK_SIZE)      #ifdef PIKE_DEBUG      #undef get_marker   #define get_marker(X) ((struct marker *) debug_malloc_pass(debug_get_marker(X)))   #undef find_marker   #define find_marker(X) ((struct marker *) debug_malloc_pass(debug_find_marker(X)))      int gc_in_cycle_check = 0; - static unsigned weak_freed, checked, marked, cycle_checked, live_ref; + static unsigned delayed_freed, weak_freed, checked, marked, cycle_checked, live_ref;   static unsigned max_gc_frames, num_gc_frames = 0;   static unsigned gc_extra_refs = 0;      void dump_gc_info(void)   {    fprintf(stderr,"Current number of objects: %ld\n",(long)num_objects);    fprintf(stderr,"Objects allocated total : %ld\n",(long)num_allocs);    fprintf(stderr," threshold for next gc() : %ld\n",(long)alloc_threshold);    fprintf(stderr,"Average allocs per gc() : %f\n",objects_alloced);    fprintf(stderr,"Average frees per gc() : %f\n",objects_freed);
pike.git/src/gc.c:306:    * really be printed..    */   void describe_location(void *real_memblock,    int real_type,    void *location,    int indent,    int depth,    int flags)   {    struct program *p; -  void *memblock=0; +  void *memblock=0, *descblock;    int type=real_type;    if(!location) return;   /* fprintf(stderr,"**Location of (short) svalue: %p\n",location); */    -  if(real_type!=-1) memblock=real_memblock; +  if(real_type!=-1 && real_memblock != (void *) -1) memblock=real_memblock;      #ifdef DEBUG_MALLOC    if(memblock == 0 || type == -1)    {    extern void *dmalloc_find_memblock_base(void *);    memblock=dmalloc_find_memblock_base(location);    }   #endif       if(type==PIKE_T_UNKNOWN)    type=attempt_to_identify(memblock);       if(memblock)    fprintf(stderr,"%*s-> from %s %p offset %ld\n",    indent,"",    get_name_of_type(type),    memblock,    DO_NOT_WARN((long)((char *)location - (char *)memblock)));    else -  fprintf(stderr,"%*s-> at location %p in unknown memblock (mmaped?)\n", +  fprintf(stderr,"%*s-> at location %p%s\n",    indent,"", -  location); +  location, +  real_memblock == (void *) -1 ? "" : " in unknown memblock (mmaped?)");    -  -  if(memblock && depth>0) -  describe_something(memblock,type,indent+2,depth-1,flags | DESCRIBE_MEM); -  +     again: -  +  descblock = memblock;    switch(type)    {    case PIKE_T_UNKNOWN:    for(p=first_program;p;p=p->next)    {    if(memblock == (void *)p->program)    {    fprintf(stderr,"%*s **In memory block for program at %p\n",    indent,"",    p);
pike.git/src/gc.c:477:    if(tmp.name)    fprintf(stderr," (%s)",tmp.name->str);    fprintf(stderr,"\n");    }       }    }    break;    }    +  case T_MULTISET: +  descblock = ((struct multiset *) memblock)->ind; +  /* FALL THROUGH */    case T_ARRAY:    { -  struct array *a=(struct array *)memblock; +  struct array *a=(struct array *)descblock;    struct svalue *s=(struct svalue *)location; -  fprintf(stderr,"%*s **In index %ld\n",indent,"", +  fprintf(stderr,"%*s **In index number %ld\n",indent,"",    DO_NOT_WARN((long)(s-ITEM(a))));    break;    } -  +  +  case T_MAPPING: +  descblock = ((struct mapping *) memblock)->data; +  /* FALL THROUGH */ +  case T_MAPPING_DATA: { +  INT32 e; +  struct keypair *k; +  NEW_MAPPING_LOOP((struct mapping_data *) descblock) +  if (&k->ind == (struct svalue *) location) { +  fprintf(stderr, "%*s **In index ", indent, ""); +  print_svalue(stderr, &k->ind); +  fputc('\n', stderr); +  break;    } -  +  else if (&k->val == (struct svalue *) location) { +  fprintf(stderr, "%*s **In value with index ", indent, ""); +  print_svalue(stderr, &k->ind); +  fputc('\n', stderr); +  break; +  } +  break; +  } +  }    -  +  if(memblock && depth>0) +  describe_something(memblock,type,indent+2,depth-1,flags | DESCRIBE_MEM); +    #ifdef DEBUG_MALLOC    /* FIXME: Is the following call correct?    * Shouldn't the second argument be an offset?    */ -  dmalloc_describe_location(memblock, location, indent); +  dmalloc_describe_location(descblock, location, indent);   #endif   }      static void describe_gc_frame(struct gc_frame *l)   {    if (l->frameflags & GC_POP_FRAME)    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",
pike.git/src/gc.c:560:    }    Pike_in_gc = orig_gc_pass;    if (flags & 2)    fatal_after_gc = "Fatal in garbage collector.\n";    else    debug_fatal("Fatal in garbage collector.\n");   }      static void gdb_gc_stop_here(void *a, int weak)   { + #if 1 +  if (!found_in) fatal("found_in is zero.\n"); +  if (!found_where) fatal("found_where is zero.\n"); + #endif    fprintf(stderr,"***One %sref found%s. ",    weak ? "weak " : "", -  found_where?found_where:""); +  found_in && found_where?found_where:""); +  if (gc_svalue_location)    describe_location(found_in , found_in_type, gc_svalue_location,0,1,0); -  +  else { +  fputc('\n', stderr); +  describe_something(found_in, found_in_type, 2, 0, DESCRIBE_MEM); +  }    fprintf(stderr,"----------end------------\n");   }      void debug_gc_xmark_svalues(struct svalue *s, ptrdiff_t num, char *fromwhere)   { -  found_in=(void *)fromwhere; +  char *old_found_where = found_where; +  if (fromwhere) found_where = fromwhere; +  found_in=(void *) -1;    found_in_type=-1;    gc_xmark_svalues(s,num); -  +  found_where=old_found_where;    found_in_type=PIKE_T_UNKNOWN;    found_in=0;   }    - void debug_gc_check_svalues(struct svalue *s, ptrdiff_t num, TYPE_T t, void *data) + void debug_gc_check_svalues2(struct svalue *s, ptrdiff_t num, +  TYPE_T data_type, void *data, char *fromwhere)   { -  +  char *old_found_where = found_where; +  if (fromwhere) found_where = fromwhere;    found_in=data; -  found_in_type=t; +  found_in_type=data_type;    gc_check_svalues(s,num); -  +  found_where=old_found_where;    found_in_type=PIKE_T_UNKNOWN;    found_in=0;   }    - void debug_gc_check_weak_svalues(struct svalue *s, ptrdiff_t num, TYPE_T t, void *data) + void debug_gc_check_weak_svalues2(struct svalue *s, ptrdiff_t num, +  TYPE_T data_type, void *data, char *fromwhere)   { -  +  char *old_found_where = found_where; +  if (fromwhere) found_where = fromwhere;    found_in=data; -  found_in_type=t; +  found_in_type=data_type;    gc_check_weak_svalues(s,num); -  +  found_where=old_found_where;    found_in_type=PIKE_T_UNKNOWN;    found_in=0;   }    - void debug_gc_check_short_svalue(union anything *u, TYPE_T type, TYPE_T t, void *data) + void debug_gc_check_short_svalue2(union anything *u, TYPE_T type, +  TYPE_T data_type, void *data, char *fromwhere)   { -  +  char *old_found_where = found_where; +  if (fromwhere) found_where = fromwhere;    found_in=data; -  found_in_type=t; +  found_in_type=data_type;    gc_check_short_svalue(u,type); -  +  found_where=old_found_where;    found_in_type=PIKE_T_UNKNOWN;    found_in=0;   }    - void debug_gc_check_weak_short_svalue(union anything *u, TYPE_T type, TYPE_T t, void *data) + void debug_gc_check_weak_short_svalue2(union anything *u, TYPE_T type, +  TYPE_T data_type, void *data, char *fromwhere)   { -  +  char *old_found_where = found_where; +  if (fromwhere) found_where = fromwhere;    found_in=data; -  found_in_type=t; +  found_in_type=data_type;    gc_check_weak_short_svalue(u,type); -  +  found_where=old_found_where;    found_in_type=PIKE_T_UNKNOWN;    found_in=0;   }    - int debug_low_gc_check(void *x, TYPE_T t, void *data) + int debug_low_gc_check(void *x, TYPE_T data_type, void *data, char *fromwhere)   {    int ret; -  +  char *old_found_where = found_where; +  if (fromwhere) found_where = fromwhere;    found_in=data; -  found_in_type=t; +  found_in_type=data_type;    ret=gc_check(x); -  +  found_where=old_found_where;    found_in_type=PIKE_T_UNKNOWN;    found_in=0;    return ret;   }      /* Avoid loss of precision warning. */   #ifdef __ECL   static inline unsigned long SIZE_T_TO_ULONG(size_t x)   {    return DO_NOT_WARN((unsigned long)x);
pike.git/src/gc.c:785:    debug_dump_mapping((struct mapping *)m);    }    }    break;    }       case T_MAPPING:    fprintf(stderr,"%*s**Describing mapping:\n",indent,"");    debug_dump_mapping((struct mapping *)a);    fprintf(stderr,"%*s**Describing mapping data block:\n",indent,""); -  describe_something( ((struct mapping *)a)->data, -2, indent+2,depth-1,flags); +  describe_something( ((struct mapping *)a)->data, T_MAPPING_DATA, +  indent+2,-1,flags);    break;       case T_STRING:    {    struct pike_string *s=(struct pike_string *)a;    fprintf(stderr, "%*s**String length is %ld:\n", indent, "",    DO_NOT_WARN((long)s->len));    if(s->len>77)    {    fprintf(stderr,"%*s** \"%60s ...\"\n",indent,"",s->str);
pike.git/src/gc.c:970:    default:    fatal("debug_gc_touch() used in invalid gc pass.\n");    }   }      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(Pike_in_gc == GC_PASS_LOCATE)    {    if(check_for == a)    {    gdb_gc_stop_here(a, weak);    }    return 0;    }       if (Pike_in_gc != GC_PASS_CHECK)    fatal("gc check attempted in invalid pass.\n");
pike.git/src/gc.c:1072: Inside #if defined(GC_VERBOSE)
   free_all_gc_frame_blocks();   #ifdef GC_VERBOSE    num_gc_frames = 0;   #endif   }      #ifdef PIKE_DEBUG   void locate_references(void *a)   {    int tmp, orig_in_gc = Pike_in_gc; +  char *orig_found_where = found_where;    void *orig_check_for=check_for;    int i=0;    if(!marker_blocks)    {    i=1;    init_gc();    }    Pike_in_gc = GC_PASS_LOCATE;       /* Disable debug, this may help reduce recursion bugs */
pike.git/src/gc.c:1118: Inside #if defined(PIKE_DEBUG) and #if defined(PIKE_DEBUG)
   }    {    extern struct mapping *builtin_constants;    if(builtin_constants) {    found_where = " as builtin_constants";    gc_external_mark2(builtin_constants,0," &builtin_constants");    }    }   #endif    -  found_where=" in a module"; +  found_where=0;    call_callback(& gc_callbacks, (void *)0);    -  found_where=""; +  found_where=orig_found_where;    check_for=orig_check_for;      #ifdef DEBUG_MALLOC    {    extern void dmalloc_find_references_to(void *);   #if 0    fprintf(stderr,"**DMALLOC Looking for references:\n");    dmalloc_find_references_to(a);   #endif    }
pike.git/src/gc.c:1209: Inside #if defined(PIKE_DEBUG)
   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 (!a) fatal("Got null pointer.\n"); -  if (Pike_in_gc != GC_PASS_CHECK && Pike_in_gc != GC_PASS_LOCATE) -  fatal("gc_external_mark() called in invalid gc pass.\n"); +     -  if(check_for) +  if(Pike_in_gc == GC_PASS_LOCATE)    {    if(a==check_for)    {    char *tmp=found_where;    void *tmp2=found_in;       if(where) found_where=where;    if(in) found_in=in;       gdb_gc_stop_here(a, 0);       found_where=tmp;    found_in=tmp2; -  -  return 1; +     }    return 0;    } -  +  +  if (Pike_in_gc != GC_PASS_CHECK) +  fatal("gc_external_mark() called in invalid gc pass.\n"); +     m=get_marker(a);    m->xrefs++;    m->flags|=GC_XREFERENCED;    if(Pike_in_gc == GC_PASS_CHECK &&    (m->refs + m->xrefs > *(INT32 *)a ||    (m->saved_refs != -1 && m->saved_refs != *(INT32 *)a)))    gc_fatal(a, 1, "Ref counts are wrong.\n");    return 0;   }   
pike.git/src/gc.c:1309: Inside #if defined(PIKE_DEBUG)
   m->saved_refs--;    m->flags |= GC_WEAK_FREED;   #endif       if (*(INT32 *) a == 1) {    /* Make sure the thing doesn't run out of refs, since we can't    * handle cascading frees now. We'll do it in the free pass    * instead. */    gc_add_extra_ref(a);    m->flags |= GC_GOT_DEAD_REF; + #ifdef PIKE_DEBUG +  delayed_freed++; + #endif    }       return 1;   }      void gc_delayed_free(void *a)   {    struct marker *m;      #ifdef PIKE_DEBUG
pike.git/src/gc.c:1332: Inside #if defined(PIKE_DEBUG)
   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");    if ((!(m->flags & GC_NOT_REFERENCED) || m->flags & GC_MARKED))    gc_fatal(a, 1, "gc_delayed_free() got a thing marked as referenced.\n");    debug_malloc_touch(a); +  delayed_freed++;   #else    m = get_marker(a);   #endif       gc_add_extra_ref(a);    m->flags |= GC_GOT_DEAD_REF;   }      int gc_mark(void *a)   {
pike.git/src/gc.c:2095:    multiplier=pow(MULTIPLIER, (double) num_allocs / (double) alloc_threshold);    objects_alloced*=multiplier;    objects_alloced += (double) num_allocs;       objects_freed*=multiplier;       /* Thread switches, object alloc/free and any reference changes are    * disallowed now. */      #ifdef PIKE_DEBUG -  weak_freed = checked = marked = cycle_checked = live_ref = 0; +  delayed_freed = weak_freed = checked = marked = cycle_checked = live_ref = 0;    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();    gc_touch_all_strings();    if (n != (unsigned) num_objects)
pike.git/src/gc.c:2169:    gc_mark_all_programs();    run_queue(&gc_mark_queue);    gc_mark_all_objects();    run_queue(&gc_mark_queue);   #ifdef PIKE_DEBUG    if(gc_debug) gc_mark_all_strings();   #endif /* PIKE_DEBUG */       GC_VERBOSE_DO(fprintf(stderr,    "| mark: %u markers referenced, %u weak references freed,\n" -  "| %d things really freed, got %lu tricky weak refs\n", -  marked, weak_freed, objs - num_objects, +  "| %d things to free, got %lu tricky weak refs\n", +  marked, weak_freed, delayed_freed,    SIZE_T_TO_ULONG(gc_ext_weak_refs)));       {   #ifdef PIKE_DEBUG    size_t orig_ext_weak_refs = gc_ext_weak_refs; -  obj_count = num_objects; +  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    * follow the same reference several times, just like in the mark    * pass. */    /* Note: The order between types here is normally not significant,    * but the permuting destruct order tests in the testsuite won't be    * really effective unless objects are handled first. :P */
pike.git/src/gc.c:2205: Inside #if defined(PIKE_DEBUG)
   fatal("gc_rec_top not empty at end of cycle check pass.\n");    if (NEXT(&rec_list) || gc_rec_last != &rec_list || gc_rec_top)    fatal("Recurse list not empty or inconsistent after cycle check pass.\n");    if (gc_ext_weak_refs != orig_ext_weak_refs)    fatal("gc_ext_weak_refs changed from %lu to %lu in cycle check pass.\n",    SIZE_T_TO_ULONG(orig_ext_weak_refs), SIZE_T_TO_ULONG(gc_ext_weak_refs));   #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" +  "| %u weak references freed, %d more things to free,\n"    "| space for %u gc frames used\n",    cycle_checked, last_cycle, weak_freed, -  obj_count - num_objects, max_gc_frames)); +  obj_count - delayed_freed, max_gc_frames));    }       if (gc_ext_weak_refs) {    size_t to_free = gc_ext_weak_refs;   #ifdef PIKE_DEBUG -  obj_count = num_objects; +  obj_count = delayed_freed;   #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    * things. */    gc_zap_ext_weak_refs_in_mappings();    gc_zap_ext_weak_refs_in_arrays();    /* Multisets handled as arrays. */    gc_zap_ext_weak_refs_in_objects();    gc_zap_ext_weak_refs_in_programs();    GC_VERBOSE_DO(    fprintf(stderr,    "| zap weak: freed %ld external weak refs, %lu internal still around,\n" -  "| %d things really freed\n", +  "| %d more things to free\n",    PTRDIFF_T_TO_LONG(to_free - gc_ext_weak_refs), -  SIZE_T_TO_ULONG(gc_ext_weak_refs), obj_count - num_objects)); +  SIZE_T_TO_ULONG(gc_ext_weak_refs), obj_count - delayed_freed));    }      #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();
pike.git/src/gc.c:2350: Inside #if defined(PIKE_DEBUG)
  #ifdef PIKE_DEBUG    if ((get_marker(kill_list->data)->flags & (GC_LIVE|GC_LIVE_OBJ)) !=    (GC_LIVE|GC_LIVE_OBJ))    gc_fatal(o, 0, "Invalid thing in kill list.\n");    if (o->prog && (o->prog->flags & PROGRAM_USES_PARENT) &&    PARENT_INFO(o)->parent &&    !PARENT_INFO(o)->parent->prog &&    get_marker(PARENT_INFO(o)->parent)->flags & GC_LIVE_OBJ)    gc_fatal(o, 0, "GC destructed parent prematurely.\n");   #endif -  GC_VERBOSE_DO(fprintf(stderr, "| Killing %p with %d refs\n", -  o, o->refs)); +  GC_VERBOSE_DO( +  fprintf(stderr, "| Killing %p with %d refs", o, o->refs); +  if (o->prog) { +  INT32 line; +  char *file = get_program_line (o->prog, &line); +  fprintf(stderr, ", prog %s:%d\n", file, line); +  } +  else fputs(", is destructed\n", stderr); +  );    destruct(o);    free_object(o);    gc_free_extra_ref(o);   #ifdef PIKE_DEBUG    destroy_count++;   #endif    debug_really_free_gc_frame(kill_list);    kill_list = next;    }   
pike.git/src/gc.c:2422:       alloc_threshold = (ptrdiff_t)tmp;       num_allocs=0;      #ifdef PIKE_DEBUG    UNSET_ONERROR (uwp);    if(GC_VERBOSE_DO(1 ||) t_flag)    {   #ifdef HAVE_GETHRTIME -  fprintf(stderr,"done (freed %ld of %ld objects), %ld ms.\n", +  fprintf(stderr,"done (freed %ld of %ld things), %ld ms.\n",    (long)objs,(long)objs + num_objects,    (long)((gethrtime() - gcstarttime)/1000000));   #else -  fprintf(stderr,"done (freed %ld of %ld objects)\n", +  fprintf(stderr,"done (freed %ld of %ld things)\n",    (long)objs,(long)objs + num_objects);   #endif    }   #endif      #ifdef ALWAYS_GC    ADD_GC_CALLBACK();   #else    if(d_flag > 3) ADD_GC_CALLBACK();   #endif