pike.git / src / gc.c

version» Context lines:

pike.git/src/gc.c:22:   #include "time_stuff.h"   #include "constants.h"   #include "interpret.h"      #include "gc.h"   #include "main.h"   #include <math.h>      #include "block_alloc.h"    - RCSID("$Id: gc.c,v 1.78 2000/04/22 02:23:56 hubbe Exp $"); + RCSID("$Id: gc.c,v 1.79 2000/04/23 03:01:25 mast Exp $");      /* Run garbage collect approximate every time we have    * 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   #define MARKER_CHUNK_SIZE 1023    - INT32 num_objects =0; + INT32 num_objects = 1; /* Account for empty_array. */   INT32 num_allocs =0;   INT32 alloc_threshold = MIN_ALLOC_THRESHOLD;   int Pike_in_gc = 0;   struct pike_queue gc_mark_queue;   time_t last_gc;         static double objects_alloced = 0.0;   static double objects_freed = 0.0;   
pike.git/src/gc.c:122: Inside #if defined(PIKE_DEBUG)
      return 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; + static 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:380:    {    fprintf(stderr,"%*s**Builtin function!\n",indent,"");    break;    }       case T_OBJECT:    p=((struct object *)a)->prog;    fprintf(stderr,"%*s**Parent identifier: %d\n",indent,"",((struct object *)a)->parent_identifier);    fprintf(stderr,"%*s**Program id: %ld\n",indent,"",((struct object *)a)->program_id);    +  if (((struct object *)a)->next == ((struct object *)a)) +  fprintf(stderr, "%*s**The object is fake.\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**Attempting to describe program object was instantiated from:\n",indent,""); +  low_describe_something(p, T_PROGRAM, indent, depth, flags); +  } +     if( ((struct object *)a)->parent)    {    fprintf(stderr,"%*s**Describing object's parent:\n",indent,"");    describe_something( ((struct object *)a)->parent, t, indent+2,depth-1,    (flags | DESCRIBE_SHORT | DESCRIBE_NO_REFS )    & ~ (DESCRIBE_MEM));    }else{    fprintf(stderr,"%*s**There is no parent (any longer?)\n",indent,"");    } -  if(!p) -  { -  fprintf(stderr,"%*s**The object is destructed.\n",indent,""); -  p=id_to_program(((struct object *)a)->program_id); +  break;    -  if(!p) break; -  } -  fprintf(stderr,"%*s**Attempting to describe program object was instantiated from:\n",indent,""); -  +     case T_PROGRAM:    {    char *tmp;    INT32 line,pos;    int foo=0;       fprintf(stderr,"%*s**Program id: %ld\n",indent,"",(long)(p->id));    if(p->flags & PROGRAM_HAS_C_METHODS)    {    fprintf(stderr,"%*s**The program was written in C.\n",indent,"");
pike.git/src/gc.c:559:    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);   }    + void debug_gc_touch(void *a) + { +  struct marker *m; +  if (!a) fatal("real_gc_check(): Got null pointer.\n"); +  +  m = find_marker(a); +  if (Pike_in_gc == GC_PASS_PRETOUCH) { +  if (m) { +  fprintf(stderr,"**Object touched twice.\n"); +  describe(a); +  fatal("Object touched twice.\n"); +  } +  get_marker(a)->flags |= GC_TOUCHED; +  } +  else if (Pike_in_gc == GC_PASS_POSTTOUCH) { +  if (m) { +  if (!(m->flags & GC_TOUCHED)) { +  fprintf(stderr,"**An existing but untouched marker found for object in linked lists. flags: %x.\n", m->flags); +  describe(a); +  fatal("An existing but untouched marker found for object in linked lists.\n"); +  } +  if ((m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED) { +  fprintf(stderr,"**An object to garb is still around. flags: %x.\n", m->flags); +  fprintf(stderr," has %ld references, while gc() found %ld + %ld external.\n",(long)*(INT32 *)a,(long)m->refs,(long)m->xrefs); +  describe(a); +  locate_references(a); +  fprintf(stderr,"##### Continuing search for more bugs....\n"); +  fatal_after_gc="An object to garb is still around.\n"; +  } +  } +  } +  else +  fatal("debug_gc_touch() used in invalid gc pass.\n"); + } +    #endif /* PIKE_DEBUG */      INT32 real_gc_check(void *a)   { -  struct marker *m=get_marker(a); +  struct marker *m;      #ifdef PIKE_DEBUG -  +  if (!a) fatal("real_gc_check(): Got null pointer.\n");    if(check_for)    {    if(check_for == a)    {    gdb_gc_stop_here(a);    }    -  if(check_for == (void *)1 && gc_do_free(a)) +  m=get_marker(a); +  if(check_for == (void *)1 && +  m && (m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED)    { -  struct marker *m=get_marker(a); +     int t=attempt_to_identify(a);    if(t != T_STRING && t != T_UNKNOWN)    {    fprintf(stderr,"**Reference to object to free in referenced object!\n");    fprintf(stderr," has %ld references, while gc() found %ld + %ld external.\n",(long)*(INT32 *)a,(long)m->refs,(long)m->xrefs);    describe(a);    locate_references(a);   #if 1    fatal("Reference to object to free in referenced object!\n");   #else    fprintf(stderr,"##### Continuing search for more bugs....\n");    fatal_after_gc="Reference to object to free in referenced object!\n";   #endif    }    }    return 0;    }    -  if (Pike_in_gc /100 != 1) -  fatal("gc check attempted in pass %d.\n", Pike_in_gc); +  if (Pike_in_gc != GC_PASS_CHECK) +  fatal("gc check attempted in invalid pass.\n");    -  +  m = get_marker(a); +     if(m->saved_refs != -1)    if(m->saved_refs != *(INT32 *)a) {    fprintf(stderr,"**Refs changed in gc() pass %d. Expected %ld, got %ld.\n",    Pike_in_gc, (long)m->saved_refs, (long)*(INT32 *)a);    describe(a);    locate_references(a);    fprintf(stderr,"##### Continuing search for more bugs....\n");    fatal_after_gc="Refs changed in gc()\n";    }    m->saved_refs = *(INT32 *)a;
pike.git/src/gc.c:662: Inside #if defined(DO_PIKE_CLEANUP)
   while(marker_hash_table[e])    remove_marker(marker_hash_table[e]->data);   #endif    exit_marker_hash();   #endif   }      #ifdef PIKE_DEBUG   void locate_references(void *a)   { +  int tmp, orig_in_gc = Pike_in_gc;    void *orig_check_for=check_for;    if(!Pike_in_gc)    init_gc(); -  +  Pike_in_gc = GC_PASS_LOCATE;    -  +  /* Disable debug, this may help reduce recursion bugs */ +  tmp=d_flag; +  d_flag=0; +     fprintf(stderr,"**Looking for references:\n");       check_for=a;       found_where=" in an array";    gc_check_all_arrays();       found_where=" in a multiset";    gc_check_all_multisets();   
pike.git/src/gc.c:710: Inside #if defined(PIKE_DEBUG) and #if defined(DEBUG_MALLOC)
  #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    }   #endif    +  Pike_in_gc = orig_in_gc;    if(!Pike_in_gc)    exit_gc(); -  +  d_flag=tmp;   }   #endif      #ifdef PIKE_DEBUG      int debug_gc_is_referenced(void *a)   {    struct marker *m; -  m=get_marker(a); +  if (!a) fatal("real_gc_check(): Got null pointer.\n");    -  +  m=get_marker(a);    if(m->refs + m->xrefs > *(INT32 *)a ||    (!(m->refs < *(INT32 *)a) && m->xrefs) || -  (Pike_in_gc < 300 && m->saved_refs != -1 && m->saved_refs != *(INT32 *)a)) +  (Pike_in_gc >= GC_PASS_CHECK && Pike_in_gc <= GC_PASS_MARK && +  m->saved_refs != -1 && m->saved_refs != *(INT32 *)a))    {    INT32 refs=m->refs;    INT32 xrefs=m->xrefs;    TYPE_T t=attempt_to_identify(a);    d_flag=0;       fprintf(stderr,"**Something has %ld refs, while gc() found %ld + %ld external.\n",    (long)*(INT32 *)a,    (long)refs,    (long)xrefs);       if(m->saved_refs != *(INT32 *)a) -  fprintf(stderr,"**In pass one it had %ld refs!!!\n",(long)m->saved_refs); +  fprintf(stderr,"**In check pass it had %ld refs!!!\n",(long)m->saved_refs);       describe_something(a, t, 0,2,0);       locate_references(a);       fatal("Ref counts are wrong (has %d, found %d + %d external)\n",    *(INT32 *)a,    refs,    xrefs);    }       return m->refs < *(INT32 *)a;   }   #endif      #ifdef PIKE_DEBUG   int gc_external_mark3(void *a, void *in, char *where)   {    struct marker *m; -  +  if (!a) fatal("real_gc_check(): Got null pointer.\n");       if(check_for)    {    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);       found_where=tmp;    found_in=tmp2;       return 1;    }    -  if(check_for == (void *)1 && gc_do_free(a)) +  m=get_marker(a); +  if(check_for == (void *)1 && +  m && (m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED)    { -  struct marker *m=get_marker(a); +     int t=attempt_to_identify(a);    if(t != T_STRING && t != T_UNKNOWN)    {    fprintf(stderr,"EXTERNAL Reference to object to free%s!\n",in?(char *)in:"");    fprintf(stderr," has %ld references, while gc() found %ld + %ld external.\n",(long)*(INT32 *)a,(long)m->refs,(long)m->xrefs);    if(where) describe_location(0,T_UNKNOWN,where,4,1,0);    describe(a);    locate_references(a);   #if 1    fatal("EXTERNAL Reference to object to free.\n");
pike.git/src/gc.c:809:    m->xrefs++;    m->flags|=GC_XREFERENCED;    gc_is_referenced(a);    return 0;   }   #endif      int gc_mark(void *a)   {    struct marker *m; -  m=get_marker(debug_malloc_pass(a)); +       #ifdef PIKE_DEBUG -  if (Pike_in_gc /100 != 2) -  fatal("gc mark attempted in pass %d.\n", Pike_in_gc); +  if (!a) fatal("real_gc_check(): Got null pointer.\n"); +  if (Pike_in_gc != GC_PASS_MARK) +  fatal("gc mark attempted in invalid pass.\n");   #endif    -  +  m = get_marker(debug_malloc_pass(a));    if(m->flags & GC_REFERENCED)    {    return 0;    }else{    m->flags |= GC_REFERENCED;    return 1;    }   }      #ifdef PIKE_DEBUG   int debug_gc_do_free(void *a)   {    struct marker *m; -  +  if (!a) fatal("real_gc_check(): Got null pointer.\n");    -  m=get_marker(debug_malloc_pass(a)); +  m=find_marker(debug_malloc_pass(a)); +  if (!m) return 0; /* Object created after mark pass. */       if( (m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED &&    (m->flags & GC_XREFERENCED) )    {    INT32 refs=m->refs;    INT32 xrefs=m->xrefs;    TYPE_T t=attempt_to_identify(a);    if(t != T_STRING && t != T_UNKNOWN)    {    fprintf(stderr,    "**gc_is_referenced failed, object has %ld references,\n" -  "** while gc() found %ld + %ld external. (type=%d, flags=%d)\n", +  "** while gc() found %ld + %ld external. (type=%d, flags=%x)\n",    (long)*(INT32 *)a,(long)refs,(long)xrefs,t,m->flags);    describe_something(a, t, 4,1,0);       locate_references(a);       fatal("GC failed object (has %d, found %d + %d external)\n",    *(INT32 *)a,    refs,    xrefs);    }
pike.git/src/gc.c:872:    INT32 tmp2;    double multiplier;    int destroyed, destructed;   #ifdef HAVE_GETHRTIME   #ifdef PIKE_DEBUG    hrtime_t gcstarttime;   #endif   #endif       if(Pike_in_gc) return; -  Pike_in_gc=10; /* before pass 1 */ +  init_gc(); +  Pike_in_gc=GC_PASS_PREPARE; + #ifdef PIKE_DEBUG +  gc_debug = d_flag; + #endif       /* Make sure there will be no callback to this while we're in the    * gc. That can be fatal since this function links objects back to    * the object list, which causes that list to be reordered and the    * various gc loops over it might then miss things. */    destruct_objects_to_destruct();       if(gc_evaluator_callback)    {    remove_callback(gc_evaluator_callback);
pike.git/src/gc.c:908:       last_gc=TIME(0);       multiplier=pow(MULTIPLIER, (double) num_allocs / (double) alloc_threshold);    objects_alloced*=multiplier;    objects_alloced += (double) num_allocs;       objects_freed*=multiplier;    objects_freed += (double) num_objects;    + #ifdef PIKE_DEBUG +  if (gc_debug) { +  INT32 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(); +  if (n != num_objects) +  fatal("Object count wrong before gc; expected %d, got %d.\n", num_objects, n); +  } + #endif    -  init_gc(); -  -  Pike_in_gc=100; /* pass one */ +  Pike_in_gc=GC_PASS_CHECK;    /* 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();      #ifdef PIKE_DEBUG    if(master_object) gc_external_mark2(master_object,0," &master_object");    {    extern struct mapping *builtin_constants;    if(builtin_constants)    gc_external_mark2(builtin_constants,0," &builtin_constants");    }   #endif    -  /* These callbacks are mainly for pass 1, but can also -  * do things that are normally associated with pass 2 +  /* These callbacks are mainly for the check pass, but can also +  * do things that are normally associated with the mark pass    */    call_callback(& gc_callbacks, (void *)0);    -  Pike_in_gc=200; /* pass two */ +  Pike_in_gc=GC_PASS_MARK;    /* Next we mark anything with external references */    gc_mark_all_arrays();    run_queue(&gc_mark_queue);    gc_mark_all_multisets();    run_queue(&gc_mark_queue);    gc_mark_all_mappings();    run_queue(&gc_mark_queue);    gc_mark_all_programs();    run_queue(&gc_mark_queue);    gc_mark_all_objects();    run_queue(&gc_mark_queue);       if(d_flag)    gc_mark_all_strings();      #ifdef PIKE_DEBUG    check_for=(void *)1;   #endif -  Pike_in_gc=350; /* pass 3.5 */ +  Pike_in_gc=GC_PASS_FREE;    /* Now we free the unused stuff */ -  -  +     gc_free_all_unreferenced_arrays();    gc_free_all_unreferenced_multisets();    gc_free_all_unreferenced_mappings();    gc_free_all_unreferenced_programs(); -  Pike_in_gc=300; +  Pike_in_gc=GC_PASS_DESTROY; /* Pike code allowed in this pass. */    /* This is intended to happen before the freeing done above. But    * it's put here for the time being, since the problem of non-object    * objects getting external references from destroy code isn't    * solved yet. */    destroyed = gc_destroy_all_unreferenced_objects(); -  Pike_in_gc=350; +  Pike_in_gc=GC_PASS_FREE;    destructed = gc_free_all_unreferenced_objects();      #ifdef PIKE_DEBUG    if (destroyed != destructed)    fatal("destroy() called in %d objects in gc, but %d destructed.\n",    destroyed, destructed);    check_for=0;    if(fatal_after_gc) fatal(fatal_after_gc);   #endif    -  exit_gc(); -  -  Pike_in_gc=400; +  Pike_in_gc=GC_PASS_DESTRUCT;    destruct_objects_to_destruct();    -  + #ifdef PIKE_DEBUG +  if (gc_debug) { +  INT32 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(); +  if (n != num_objects) +  fatal("Object count wrong after gc; expected %d, got %d.\n", num_objects, n); +  if(fatal_after_gc) fatal(fatal_after_gc); +  } + #endif +  +  Pike_in_gc=0; +  exit_gc(); +     objects_freed -= (double) num_objects;       tmp=(double)num_objects;    tmp=tmp * GC_CONST/100.0 * (objects_alloced+1.0) / (objects_freed+1.0);       if((int)tmp < alloc_threshold + num_allocs)    {    alloc_threshold=(int)tmp;    }else{    alloc_threshold+=num_allocs;
pike.git/src/gc.c:1019:    (long)(tmp2-num_objects),(long)tmp2);   #endif    }   #endif      #ifdef ALWAYS_GC    ADD_GC_CALLBACK();   #else    if(d_flag > 3) ADD_GC_CALLBACK();   #endif -  Pike_in_gc=0; +    }         void f__gc_status(INT32 args)   {    pop_n_elems(args);       push_constant_text("num_objects");    push_int(num_objects);   
pike.git/src/gc.c:1050:    push_int(objects_freed);       push_constant_text("last_gc");    push_int(last_gc);       push_constant_text("projected_garbage");    push_float(objects_freed * (double) num_allocs / (double) alloc_threshold);       f_aggregate_mapping(14);   } -  +