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.227 2003/08/26 18:46:04 mast Exp $ + || $Id: gc.c,v 1.228 2003/09/08 20:05:20 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.227 2003/08/26 18:46:04 mast Exp $"); + RCSID("$Id: gc.c,v 1.228 2003/09/08 20:05:20 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:97:   #define GC_VERBOSE_DO(X) X   #else   #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; - struct pike_queue gc_mark_queue; +    time_t last_gc;   int gc_trace = 0, gc_debug = 0;      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. */
pike.git/src/gc.c:213:   struct callback *debug_add_gc_callback(callback_func call,    void *arg,    callback_func free_func)   {    return add_to_callback(&gc_callbacks, call, arg, free_func);   }      static void init_gc(void);   static void gc_cycle_pop(void *a);    -  +    #undef BLOCK_ALLOC_NEXT   #define BLOCK_ALLOC_NEXT next      #undef INIT_BLOCK   #ifdef PIKE_DEBUG   #define INIT_BLOCK(X) \    (X)->flags=(X)->refs=(X)->weak_refs=(X)->xrefs=0; \    (X)->saved_refs=-1; \    (X)->frame = 0;   #else
pike.git/src/gc.c:238: Inside #if defined(PIKE_DEBUG)
     #ifdef PIKE_DEBUG   #undef get_marker   #define get_marker debug_get_marker   #undef find_marker   #define find_marker debug_find_marker   #endif      PTR_HASH_ALLOC_FIXED_FILL_PAGES(marker,2)    + #if defined (PIKE_DEBUG) || defined (GC_MARK_DEBUG) + void *gc_found_in = NULL; + int gc_found_in_type = PIKE_T_UNKNOWN; + const char *gc_found_place = NULL; + #endif +    #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 delayed_freed, weak_freed, checked, marked, cycle_checked, live_ref;   static unsigned max_gc_frames, num_gc_frames = 0, live_rec, frame_rot;   static unsigned gc_extra_refs = 0;      static unsigned max_tot_gc_frames = 0;   static unsigned tot_cycle_checked = 0, tot_live_rec = 0, tot_frame_rot = 0;      static int gc_is_watching = 0;    - TYPE_T attempt_to_identify(void *something, void **inblock) + int attempt_to_identify(void *something, void **inblock)   {    size_t i;    struct array *a;    struct object *o;    struct program *p;    struct mapping *m;    struct multiset *mu;    struct pike_type *t;    struct callable *c;   
pike.git/src/gc.c:320:    return T_TYPE;       for (c = first_callable; c; c = c->next)    if (c == (struct callable *) something)    return T_STRUCT_CALLABLE;       return PIKE_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;      #ifdef DEBUG_MALLOC      /* To keep the markers after the gc. Only used for the dmalloc leak    * report at exit. */   int gc_keep_markers = 0;      int gc_external_refs_zapped = 0;
pike.git/src/gc.c:686: Inside #if defined(PIKE_DEBUG)
   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 -  if (!found_where) Pike_fatal("found_where is zero.\n"); - #endif +     fprintf(stderr,"***One %sref found%s. ",    weak ? "weak " : "", -  found_where?found_where:""); -  if (found_in) { +  gc_found_place ? gc_found_place : ""); +  if (gc_found_in) {    if (gc_svalue_location) -  describe_location(found_in , found_in_type, gc_svalue_location,0,1,0); +  describe_location(gc_found_in , gc_found_in_type, gc_svalue_location,0,1,0);    else {    fputc('\n', stderr); -  describe_something(found_in, found_in_type, 2, 0, DESCRIBE_MEM, 0); +  describe_something(gc_found_in, gc_found_in_type, 2, 0, DESCRIBE_MEM, 0);    }    }    else    fputc('\n', stderr);    fprintf(stderr,"----------end------------\n");   }    - void debug_gc_xmark_svalues(struct svalue *s, ptrdiff_t num, char *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_xmark_svalues2(struct svalue *s, ptrdiff_t num, -  int data_type, void *data, char *fromwhere) - { -  char *old_found_where = found_where; -  if (fromwhere) found_where = fromwhere; -  found_in=data; -  found_in_type=data_type; -  gc_xmark_svalues(s,num); -  found_where=old_found_where; -  found_in_type=PIKE_T_UNKNOWN; -  found_in=0; - } -  - void debug_gc_check_svalues2(struct svalue *s, ptrdiff_t num, -  int data_type, void *data, char *fromwhere) - { -  char *old_found_where = found_where; -  if (fromwhere) found_where = fromwhere; -  found_in=data; -  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_svalues2(struct svalue *s, ptrdiff_t num, -  int data_type, void *data, char *fromwhere) - { -  char *old_found_where = found_where; -  if (fromwhere) found_where = fromwhere; -  found_in=data; -  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_svalue2(union anything *u, int type, -  int data_type, void *data, char *fromwhere) - { -  char *old_found_where = found_where; -  if (fromwhere) found_where = fromwhere; -  found_in=data; -  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_svalue2(union anything *u, int type, -  int data_type, void *data, char *fromwhere) - { -  char *old_found_where = found_where; -  if (fromwhere) found_where = fromwhere; -  found_in=data; -  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, int 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=data_type; -  ret=gc_check(x); -  found_where=old_found_where; -  found_in_type=PIKE_T_UNKNOWN; -  found_in=0; -  return ret; - } -  +    void low_describe_something(void *a,    int t,    int indent,    int depth,    int flags,    void *inblock)   {    struct program *p=(struct program *)a;    struct marker *m;   
pike.git/src/gc.c:1145:    m->flags |= GC_WATCHED;    fprintf(stderr, "## Watching thing %p.\n", a);    gc_is_watching++;    }    else    fprintf(stderr, "## Already watching thing %p.\n", a);   }      #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 + { +  queue_call call; +  void *data; +  int in_type; +  void *in; +  const char *place; + }; +  + #define GC_QUEUE_ENTRIES 8191 +  + struct gc_queue_block + { +  struct gc_queue_block *next; +  int used; +  struct gc_queue_entry entries[GC_QUEUE_ENTRIES]; + }; +  + struct gc_queue_block *gc_mark_first = NULL, *gc_mark_last = NULL; +  + void gc_mark_run_queue() + { +  struct gc_queue_block *b; +  +  while((b=gc_mark_first)) +  { +  int e; +  for(e=0;e<b->used;e++) +  { +  debug_malloc_touch(b->entries[e].data); +  b->entries[e].call(b->entries[e].data); +  } +  +  gc_mark_first=b->next; +  free((char *)b); +  } +  gc_mark_last=0; + } +  + void gc_mark_discard_queue() + { +  struct gc_queue_block *b = gc_mark_first; +  while (b) +  { +  struct gc_queue_block *next = b->next; +  free((char *) b); +  b = next; +  } +  gc_mark_first = gc_mark_last = 0; + } +  + void gc_mark_enqueue (queue_call call, void *data) + { +  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); +  } +  } + #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; +  b->next=0; +  if(gc_mark_first) +  gc_mark_last->next=b; +  else +  gc_mark_first=b; +  gc_mark_last=b; +  } +  +  b->entries[b->used].call=call; +  b->entries[b->used].data=debug_malloc_pass(data); +  b->entries[b->used].in_type = gc_found_in_type; +  b->entries[b->used].in = debug_malloc_pass (gc_found_in); +  b->entries[b->used].place = gc_found_place; +  b->used++; + } +  + #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);    }
pike.git/src/gc.c:1264: Inside #if defined(PIKE_DEBUG)
   {    if(check_for == a)    {    gdb_gc_stop_here(a, weak);    }    return 0;    }      #if 0    fprintf (stderr, "Ref: %s %p -> %p%s\n", -  get_name_of_type (found_in_type), found_in, a, -  found_where ? found_where : ""); +  get_name_of_type (gc_found_in_type), gc_found_in, a, +  gc_found_place ? gc_found_place : "");   #endif       if (Pike_in_gc != GC_PASS_CHECK)    Pike_fatal("gc check attempted in invalid pass.\n");       m = get_marker(a);       if (!*(INT32 *)a)    gc_fatal(a, 1, "GC check on thing without refs.\n");    if (m->saved_refs == -1) m->saved_refs = *(INT32 *)a;
pike.git/src/gc.c:1294: Inside #if defined(PIKE_DEBUG)
  }      #endif /* PIKE_DEBUG */      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);    }    if (!(m = gc_check_debug(a, 0))) return 0;   #else    m = get_marker(a);   #endif   
pike.git/src/gc.c:1317:    m->flags |= GC_NOT_REFERENCED;    return ret;   }      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);    }    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");
pike.git/src/gc.c:1402: Inside #if defined(PIKE_DEBUG)
   gc_is_watching);    gc_is_watching = 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 */    tmp=d_flag;    d_flag=0;       fprintf(stderr,"**Looking for references to %p:\n", a);       check_for=a;    -  found_where=" in an array"; +     gc_check_all_arrays(); -  -  found_where=" in a multiset"; +     gc_check_all_multisets(); -  -  found_where=" in a mapping"; +     gc_check_all_mappings(); -  -  found_where=" in a program"; +     gc_check_all_programs(); -  -  found_where=" in an object"; +     gc_check_all_objects();      #ifdef PIKE_DEBUG    if(master_object) -  gc_external_mark2(master_object,0," as master_object"); +  gc_mark_external (master_object, " as master_object");    {    extern struct mapping *builtin_constants;    if(builtin_constants) -  gc_external_mark2(builtin_constants,0," as builtin_constants"); +  gc_mark_external (builtin_constants, " as builtin_constants");    }   #endif    -  found_where=0; +     call_callback(& gc_callbacks, NULL);    -  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    }   #endif   
pike.git/src/gc.c:1550: Inside #if defined(PIKE_DEBUG)
   }    else m = get_marker(a);       if (m->flags & GC_IS_REFERENCED)    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) + 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_external_mark3() in pass %d.\n", a, Pike_in_gc); +  "gc_mark_external() in pass %d.\n", a, Pike_in_gc);    }       if (!a) Pike_fatal("Got null pointer.\n");       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; -  +  if(a==check_for) { +  const char *orig_gc_found_place = gc_found_place; +  gc_found_place = place;    gdb_gc_stop_here(a, 0); -  -  found_where=tmp; -  found_in=tmp2; +  gc_found_place = orig_gc_found_place;    }    return 0;    }       if (Pike_in_gc != GC_PASS_CHECK) -  Pike_fatal("gc_external_mark() called in invalid gc pass.\n"); +  Pike_fatal("gc_mark_external() called in invalid gc pass.\n");      #ifdef DEBUG_MALLOC    if (gc_external_refs_zapped) {    fprintf (stderr, "One external ref to %p found%s.\n", -  a, where ? where : ""); +  a, place ? place : "");    if (in) describe (in);    return 0;    }   #endif       m=get_marker(a);    m->xrefs++;    m->flags|=GC_XREFERENCED;    if(Pike_in_gc == GC_PASS_CHECK &&    (m->refs + m->xrefs > *(INT32 *)a ||
pike.git/src/gc.c:1731:    l->u.free_extra_type = type;    l->back = free_extra_list;    l->frameflags = 0;    free_extra_list = l;    }       gc_add_extra_ref(a);    m->flags |= GC_GOT_DEAD_REF;   }    - #ifdef PIKE_DEBUG - void gc_mark_enqueue(queue_call call, void *data) - { -  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); -  } -  enqueue(&gc_mark_queue, call, data); - } - #endif -  +    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);    }
pike.git/src/gc.c:2617:    ACCEPT_UNFINISHED_TYPE_FIELDS {    gc_check_all_arrays();    gc_check_all_multisets();    gc_check_all_mappings();    gc_check_all_programs();    gc_check_all_objects();    } END_ACCEPT_UNFINISHED_TYPE_FIELDS;      #ifdef PIKE_DEBUG    if(master_object) -  gc_external_mark2(master_object,0," as master_object"); +  gc_mark_external (master_object, " as master_object");       {    extern struct mapping *builtin_constants;    if(builtin_constants) -  gc_external_mark2(builtin_constants,0," as builtin_constants"); +  gc_mark_external (builtin_constants, " as builtin_constants");    }   #endif       /* 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, NULL);       GC_VERBOSE_DO(fprintf(stderr, "| check: %u references in %d things, "    "counted %"PRINTSIZET"u weak refs\n",
pike.git/src/gc.c:2651:    gc_internal_multiset = first_multiset;    gc_internal_mapping = first_mapping;    gc_internal_program = first_program;    gc_internal_object = first_object;       /* 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(); -  run_queue(&gc_mark_queue); +  gc_mark_run_queue();    gc_mark_all_multisets(); -  run_queue(&gc_mark_queue); +  gc_mark_run_queue();    gc_mark_all_mappings(); -  run_queue(&gc_mark_queue); +  gc_mark_run_queue();    gc_mark_all_programs(); -  run_queue(&gc_mark_queue); +  gc_mark_run_queue();    gc_mark_all_objects(); -  run_queue(&gc_mark_queue); +  gc_mark_run_queue();   #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));