Branch: Tag:

2004-03-15

2004-03-15 22:47:15 by Martin Stjernholm <mast@lysator.liu.se>

Use the gc to get a good destruct order when DO_PIKE_CLEANUP is used. This
should avoid bogus errors from destroy functions in that case.

Rev: src/array.c:1.155
Rev: src/gc.c:1.242
Rev: src/gc.h:1.106
Rev: src/main.c:1.192
Rev: src/object.c:1.251
Rev: src/object.h:1.81

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.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"
33:      #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;   
108:   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   {
1396: Inside #if defined(PIKE_DEBUG)
  #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");
2179: Inside #if defined(PIKE_DEBUG)
   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) {
2457: Inside #if defined(PIKE_DEBUG)
   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;
2576:    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;
2797:    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. */
2821:    "| %d things to free, "    "got %"PRINTSIZET"u tricky weak refs\n",    marked, weak_freed, delayed_freed, gc_ext_weak_refs)); +  }       {   #ifdef PIKE_DEBUG
2987:    /* 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;
3056: Inside #if defined(PIKE_DEBUG)
  #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: ");
3068: Inside #if defined(PIKE_DEBUG)
   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);