diff --git a/src/array.c b/src/array.c index 88bf09f4b28c9b358918ba0e894c6f3cd269c387..7a80d8ea786170fa9a19335fa4ae46b80bfcfade 100644 --- a/src/array.c +++ b/src/array.c @@ -2,7 +2,7 @@ || 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: array.c,v 1.154 2004/03/15 22:23:14 mast Exp $ +|| $Id: array.c,v 1.155 2004/03/15 22:47:15 mast Exp $ */ #include "global.h" @@ -26,7 +26,7 @@ #include "cyclic.h" #include "multiset.h" -RCSID("$Id: array.c,v 1.154 2004/03/15 22:23:14 mast Exp $"); +RCSID("$Id: array.c,v 1.155 2004/03/15 22:47:15 mast Exp $"); PMOD_EXPORT struct array empty_array= { @@ -2350,7 +2350,8 @@ void real_gc_cycle_check_array(struct array *a, int weak) { GC_CYCLE_ENTER(a, T_ARRAY, weak) { #ifdef PIKE_DEBUG - if (a == &empty_array || a == &weak_empty_array || a == &weak_shrink_empty_array) + if (!gc_destruct_everything && + (a == &empty_array || a == &weak_empty_array || a == &weak_shrink_empty_array)) Pike_fatal("Trying to gc cycle check some *_empty_array.\n"); #endif diff --git a/src/gc.c b/src/gc.c index b0d9aaaf8ae296a606dec1737d9eb9ca1cd95495..3a0f69a0335591973fa1dd4b7c72063881e17f3d 100644 --- a/src/gc.c +++ b/src/gc.c @@ -2,7 +2,7 @@ || 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,7 +33,7 @@ struct callback *gc_evaluator_callback=0; #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,6 +108,11 @@ PMOD_EXPORT int Pike_in_gc = 0; 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,6 +1401,8 @@ void debug_gc_touch(void *a) #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,12 +2186,14 @@ int gc_cycle_push(void *x, struct marker *m, int weak) 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 ((!(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 (!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,12 +2466,14 @@ static void gc_cycle_pop(void *a) 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 ((!(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"); + 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,16 +2587,33 @@ int gc_do_free(void *a) 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,30 +2825,36 @@ size_t do_gc(void *ignored, int explicit_call) 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(); - gc_mark_run_queue(); - gc_mark_all_multisets(); - gc_mark_run_queue(); - gc_mark_all_mappings(); - gc_mark_run_queue(); - gc_mark_all_programs(); - gc_mark_run_queue(); - gc_mark_all_objects(); - gc_mark_run_queue(); -#ifdef PIKE_DEBUG - if(gc_debug) gc_mark_all_strings(); + 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. */ + ACCEPT_UNFINISHED_TYPE_FIELDS { + gc_mark_all_arrays(); + gc_mark_run_queue(); + gc_mark_all_multisets(); + gc_mark_run_queue(); + gc_mark_all_mappings(); + gc_mark_run_queue(); + gc_mark_all_programs(); + gc_mark_run_queue(); + gc_mark_all_objects(); + gc_mark_run_queue(); +#ifdef PIKE_DEBUG + if(gc_debug) gc_mark_all_strings(); #endif /* PIKE_DEBUG */ - } END_ACCEPT_UNFINISHED_TYPE_FIELDS; + } 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)); + 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)); + } { #ifdef PIKE_DEBUG @@ -2987,7 +3021,8 @@ size_t do_gc(void *ignored, int explicit_call) /* 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,11 +3091,11 @@ size_t do_gc(void *ignored, int explicit_call) #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,6 +3103,14 @@ size_t do_gc(void *ignored, int explicit_call) 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); diff --git a/src/gc.h b/src/gc.h index 371748a8e61dd8bab5290bdbb2bfdfdcbe8a1789..f310185eb7c328ecc849abc04fc351ae8d9f36c4 100644 --- a/src/gc.h +++ b/src/gc.h @@ -2,7 +2,7 @@ || 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.h,v 1.105 2003/09/23 20:06:28 mast Exp $ +|| $Id: gc.h,v 1.106 2004/03/15 22:47:15 mast Exp $ */ #ifndef GC_H @@ -55,6 +55,9 @@ extern ptrdiff_t alloc_threshold; PMOD_EXPORT extern int Pike_in_gc; extern int gc_generation; extern int gc_trace, gc_debug; +#ifdef DO_PIKE_CLEANUP +extern int gc_destruct_everything; +#endif extern cpu_time_t auto_gc_time; extern struct callback *gc_evaluator_callback; diff --git a/src/main.c b/src/main.c index 23375d98d9440d5bbff778b9a3cd28c5ec49f33b..c0820c467dad389d04e9eb07f1c6e7107fc7cbf5 100644 --- a/src/main.c +++ b/src/main.c @@ -2,11 +2,11 @@ || 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: main.c,v 1.191 2004/03/15 22:23:14 mast Exp $ +|| $Id: main.c,v 1.192 2004/03/15 22:47:15 mast Exp $ */ #include "global.h" -RCSID("$Id: main.c,v 1.191 2004/03/15 22:23:14 mast Exp $"); +RCSID("$Id: main.c,v 1.192 2004/03/15 22:47:15 mast Exp $"); #include "fdlib.h" #include "backend.h" #include "module.h" @@ -906,8 +906,11 @@ void exit_main(void) /* Destruct all remaining objects before modules are shut down, so * that they don't get calls to object exit callbacks after their * module exit callback. The downside is that the leak report below - * will always report destructed objects. */ - cleanup_objects(); + * will always report destructed objects. We use the gc in a special + * mode for this to get a reasonably sane destruct order. */ + gc_destruct_everything = 1; + do_gc (NULL, 1); + gc_destruct_everything = 0; /* Unload dynamic modules before static ones. */ exit_dynamic_load(); diff --git a/src/object.c b/src/object.c index 3aab923387c86482d5644f3acf81c3db2dd4318c..d8a9cef14227f6c4bd6e562c0a338ff58b626e2d 100644 --- a/src/object.c +++ b/src/object.c @@ -2,11 +2,11 @@ || 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: object.c,v 1.250 2003/11/18 19:33:45 grubba Exp $ +|| $Id: object.c,v 1.251 2004/03/15 22:47:15 mast Exp $ */ #include "global.h" -RCSID("$Id: object.c,v 1.250 2003/11/18 19:33:45 grubba Exp $"); +RCSID("$Id: object.c,v 1.251 2004/03/15 22:47:15 mast Exp $"); #include "object.h" #include "dynamic_buffer.h" #include "interpret.h" @@ -1601,28 +1601,6 @@ PMOD_EXPORT int object_equal_p(struct object *a, struct object *b, struct proces return 1; } -void cleanup_objects(void) -{ - struct object *o, *next; - - for(o=first_object;o;o=next) - { - add_ref(o); - if(o != master_object && /* Wait with the master till last. */ - o->prog) - { - debug_malloc_touch(o); - debug_malloc_touch(o->storage); - call_destroy(o,1); - destruct(o); - } else { - debug_malloc_touch(o); - } - SET_NEXT_AND_FREE(o,free_object); - } - destruct_objects_to_destruct(); -} - PMOD_EXPORT struct array *object_indices(struct object *o) { struct program *p; diff --git a/src/object.h b/src/object.h index 9f082b260639aee18ad2b5e3b8c403e4fdfbe35a..e6f97a67f1a3f2b6aec64a00e03c3725dd5b3a07 100644 --- a/src/object.h +++ b/src/object.h @@ -2,7 +2,7 @@ || 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: object.h,v 1.80 2003/08/01 22:46:06 mast Exp $ +|| $Id: object.h,v 1.81 2004/03/15 22:47:15 mast Exp $ */ #ifndef OBJECT_H @@ -98,7 +98,6 @@ union anything *object_get_item_ptr(struct object *o, struct svalue *key, TYPE_T type); PMOD_EXPORT int object_equal_p(struct object *a, struct object *b, struct processing *p); -void cleanup_objects(void); PMOD_EXPORT struct array *object_indices(struct object *o); PMOD_EXPORT struct array *object_values(struct object *o); PMOD_EXPORT void gc_mark_object_as_referenced(struct object *o);