Branch: Tag:

2003-09-08

2003-09-08 20:05:21 by Martin Stjernholm <mast@lysator.liu.se>

Cleaned up the gc check stuff a bit (large indentantion changes). Added more
tracking in the gc to help track down bugs when the gc follows munged
pointers in the mark pass. That's activated with GC_MARK_DEBUG.

Rev: src/array.c:1.149
Rev: src/backend.cmod:1.47
Rev: src/error.c:1.115
Rev: src/gc.c:1.228
Rev: src/gc.h:1.104
Rev: src/interpret.c:1.329
Rev: src/mapping.c:1.170
Rev: src/multiset.c:1.78
Rev: src/object.c:1.247
Rev: src/program.c:1.524
Rev: src/security.c:1.45
Rev: src/svalue.c:1.173
Rev: src/svalue.h:1.123
Rev: src/threads.c:1.220

2:   || 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"
33:      #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;   
104:   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;   
220:   static void init_gc(void);   static void gc_cycle_pop(void *a);    -  +    #undef BLOCK_ALLOC_NEXT   #define BLOCK_ALLOC_NEXT next   
245:      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
262:      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;
327:   }      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;   
693: Inside #if defined(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
712: Inside #if defined(PIKE_DEBUG)
   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,
1152:      #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;
1271: Inside #if defined(PIKE_DEBUG) and #if 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)
1301:    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 "
1324:    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 "
1409: Inside #if defined(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)    {
1427: Inside #if defined(PIKE_DEBUG)
      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 *);
1557: Inside #if defined(PIKE_DEBUG)
   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;    }
1738:    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));
2624: Inside #if defined(PIKE_DEBUG)
     #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   
2658:    * 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 */