diff --git a/src/array.c b/src/array.c index fc28cdbe1e90a8dba0d443e6af909fcb52ec1316..663e52a27ec7e38281d951d843cb3c1a9d1e39b0 100644 --- a/src/array.c +++ b/src/array.c @@ -23,7 +23,7 @@ #include "stuff.h" #include "bignum.h" -RCSID("$Id: array.c,v 1.65 2000/04/17 16:48:57 grubba Exp $"); +RCSID("$Id: array.c,v 1.66 2000/04/20 01:49:42 mast Exp $"); struct array empty_array= { @@ -104,7 +104,7 @@ static void array_free_no_free(struct array *v) free((char *)v); - GC_FREE(); + GC_FREE(v); } /* diff --git a/src/gc.c b/src/gc.c index 32685e813c0924a64889ba09572dea8693575eaf..0038baea05bc8e4f8674fb39af709c91ce1478f8 100644 --- a/src/gc.c +++ b/src/gc.c @@ -29,7 +29,7 @@ struct callback *gc_evaluator_callback=0; #include "block_alloc.h" -RCSID("$Id: gc.c,v 1.73 2000/04/19 21:49:27 mast Exp $"); +RCSID("$Id: gc.c,v 1.74 2000/04/20 01:49:42 mast Exp $"); /* Run garbage collect approximate every time we have * 20 percent of all arrays, objects and programs is @@ -597,7 +597,7 @@ INT32 real_gc_check(void *a) return 0; } - if (Pike_in_gc != 1) + if (Pike_in_gc != 2) fatal("gc check attempted in pass %d.\n", Pike_in_gc); if(m->saved_refs != -1) @@ -727,7 +727,7 @@ int debug_gc_is_referenced(void *a) if(m->refs + m->xrefs > *(INT32 *)a || (!(m->refs < *(INT32 *)a) && m->xrefs) || - (Pike_in_gc < 3 && m->saved_refs != -1 && m->saved_refs != *(INT32 *)a)) + (Pike_in_gc < 4 && m->saved_refs != -1 && m->saved_refs != *(INT32 *)a)) { INT32 refs=m->refs; INT32 xrefs=m->xrefs; @@ -811,7 +811,7 @@ int gc_mark(void *a) m=get_marker(debug_malloc_pass(a)); #ifdef PIKE_DEBUG - if (Pike_in_gc != 2) + if (Pike_in_gc != 3) fatal("gc mark attempted in pass %d.\n", Pike_in_gc); #endif @@ -863,6 +863,7 @@ void do_gc(void) double tmp; INT32 tmp2; double multiplier; + int destroyed, destructed; #ifdef HAVE_GETHRTIME #ifdef PIKE_DEBUG hrtime_t gcstarttime; @@ -872,7 +873,10 @@ void do_gc(void) if(Pike_in_gc) return; Pike_in_gc=1; - /* Make sure there will be no callback to this while we're in the gc. */ + /* 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) @@ -906,6 +910,7 @@ void do_gc(void) init_gc(); + Pike_in_gc=2; /* First we count internal references */ gc_check_all_arrays(); gc_check_all_multisets(); @@ -927,8 +932,7 @@ void do_gc(void) */ call_callback(& gc_callbacks, (void *)0); - Pike_in_gc=2; - + Pike_in_gc=3; /* Next we mark anything with external references */ gc_mark_all_arrays(); run_queue(&gc_mark_queue); @@ -944,27 +948,35 @@ void do_gc(void) if(d_flag) gc_mark_all_strings(); - #ifdef PIKE_DEBUG check_for=(void *)1; #endif - Pike_in_gc=3; + Pike_in_gc=5; /* 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(); - gc_free_all_unreferenced_objects(); + Pike_in_gc=4; + /* 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=5; + 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=5; + Pike_in_gc=6; destruct_objects_to_destruct(); objects_freed -= (double) num_objects; diff --git a/src/gc.h b/src/gc.h index b539f0ffa816c0a3339c4ed4c346f4b7d8fa1273..00cd2a2039bfbd96862279f16e2e2f21e8bee932 100644 --- a/src/gc.h +++ b/src/gc.h @@ -1,5 +1,5 @@ /* - * $Id: gc.h,v 1.36 2000/04/19 21:25:33 mast Exp $ + * $Id: gc.h,v 1.37 2000/04/20 01:49:43 mast Exp $ */ #ifndef GC_H #define GC_H @@ -32,7 +32,7 @@ extern void *gc_svalue_location; num_allocs++; \ DO_IF_DEBUG( \ if(d_flag) CHECK_INTERPRETER_LOCK(); \ - if(Pike_in_gc >0 && Pike_in_gc<4) \ + if(Pike_in_gc > 1 && Pike_in_gc < 4 && Pike_in_gc != 5) \ fatal("Allocating new objects within gc is not allowed!\n"); \ ) \ if(num_allocs == alloc_threshold && !gc_evaluator_callback) \ @@ -43,10 +43,10 @@ extern void *gc_svalue_location; struct marker { struct marker *next; - INT32 refs; + INT32 refs; /* Internal references. */ #ifdef PIKE_DEBUG - INT32 xrefs; - INT32 saved_refs; + INT32 xrefs; /* Known external references. */ + INT32 saved_refs; /* Object refcount during check and mark pass. */ #endif INT32 flags; void *data; @@ -85,24 +85,19 @@ void f__gc_status(INT32 args); #define gc_check(VP) real_gc_check(debug_malloc_pass(VP)) #ifdef PIKE_DEBUG -#define LOW_GC_FREE() do { \ +#define LOW_GC_FREE(OBJ) do { \ extern int d_flag; \ if(d_flag) CHECK_INTERPRETER_LOCK(); \ num_objects-- ; \ if(num_objects < 0) \ fatal("Panic!! less than zero objects!\n"); \ + if (Pike_in_gc) remove_marker(OBJ); \ }while(0) -#define GC_FREE() do { \ - if(Pike_in_gc >0 && Pike_in_gc<3) \ +#define GC_FREE(OBJ) do { \ + if(Pike_in_gc >2 && Pike_in_gc <4) \ fatal("Freeing objects within gc is not allowed!\n"); \ - LOW_GC_FREE(); \ -}while(0) - -#define GC_FREE_OBJ() do { \ - if(Pike_in_gc >1 && Pike_in_gc<4) \ - fatal("Freeing objects within gc is not allowed!\n"); \ - LOW_GC_FREE(); \ + LOW_GC_FREE(OBJ); \ }while(0) #else @@ -110,9 +105,11 @@ void f__gc_status(INT32 args); #define debug_gc_check_short_svalue(S,N,T,V) gc_check_short_svalue((S),N) #define debug_gc_xmark_svalues(S,N,X) gc_xmark_svalues((S),N) #define debug_gc_check(VP,T,V) gc_check((VP)) -#define LOW_GC_FREE() do {} while(0) -#define GC_FREE() do { num_objects-- ; }while(0) -#define GC_FREE_OBJ() do { num_objects-- ; }while(0) +#define LOW_GC_FREE(OBJ) do { \ + num_objects-- ; \ + if (Pike_in_gc) remove_marker(OBJ); \ +}while(0) +#define GC_FREE(OBJ) LOW_GC_FREE(OBJ) #endif @@ -126,8 +123,8 @@ void f__gc_status(INT32 args); #define GC_XREFERENCED 2 #define GC_CHECKED 4 #ifdef PIKE_DEBUG -#define GC_DO_FREE_OBJ 8 -#define GC_OBJ_PASS_4 16 +#define GC_OBJ_DESTROY_CHECK 8 +#define GC_DO_FREE_OBJ 16 #endif #ifdef PIKE_DEBUG diff --git a/src/mapping.c b/src/mapping.c index ac6d0ad37d6ae8b0f4f0a6dd0e99c96c117fbce9..1fdfd11eb076ff31945ca45eeba0d4b263f44e24 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: mapping.c,v 1.77 2000/04/17 16:42:16 grubba Exp $"); +RCSID("$Id: mapping.c,v 1.78 2000/04/20 01:49:43 mast Exp $"); #include "main.h" #include "object.h" #include "mapping.h" @@ -63,7 +63,7 @@ DO_IF_DEBUG( \ \ if(m->next) m->next->prev = m->prev; \ \ - GC_FREE(); + GC_FREE(m); #undef COUNT_OTHER diff --git a/src/multiset.c b/src/multiset.c index 43ce3be3f228232b351b5b5fe24ca53dc383c981..4cbca589753fa55a367bc5c802d2a1aa3ee529fd 100644 --- a/src/multiset.c +++ b/src/multiset.c @@ -16,7 +16,7 @@ #include "gc.h" #include "security.h" -RCSID("$Id: multiset.c,v 1.18 2000/04/12 18:40:12 hubbe Exp $"); +RCSID("$Id: multiset.c,v 1.19 2000/04/20 01:49:43 mast Exp $"); struct multiset *first_multiset; @@ -66,7 +66,7 @@ void really_free_multiset(struct multiset *l) if(l->next) l->next->prev = l->prev; free((char *)l); - GC_FREE(); + GC_FREE(l); } diff --git a/src/object.c b/src/object.c index e34869f87f1026b88c51c2539d4c481807a55228..8152f6a5d54bb3cbe63b6d1c4a83ee9d2a8e9f8c 100644 --- a/src/object.c +++ b/src/object.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: object.c,v 1.115 2000/04/19 21:49:27 mast Exp $"); +RCSID("$Id: object.c,v 1.116 2000/04/20 01:49:43 mast Exp $"); #include "object.h" #include "dynamic_buffer.h" #include "interpret.h" @@ -471,7 +471,7 @@ void low_destruct(struct object *o,int do_free) #ifdef PIKE_DEBUG if(d_flag > 20) do_debug(); - if(Pike_in_gc && Pike_in_gc<4) + if(Pike_in_gc > 1 && Pike_in_gc < 4 && Pike_in_gc != 5) fatal("Destructing object inside gc()\n"); #endif @@ -561,7 +561,7 @@ void destruct_objects_to_destruct(void) struct object *o, *next; #ifdef PIKE_DEBUG - if (Pike_in_gc >= 3 && Pike_in_gc <= 4) + if (Pike_in_gc > 1 && Pike_in_gc < 6) fatal("Can't meddle with the object link list in gc pass %d.\n", Pike_in_gc); #endif @@ -612,7 +612,10 @@ void really_free_object(struct object *o) if(o->prog) { DOUBLELINK(objects_to_destruct,o); - if (Pike_in_gc) return; /* Done last in gc(). */ + if (Pike_in_gc) { + remove_marker(o); + if (Pike_in_gc < 6) return; /* Done last in gc(). */ + } if(!destruct_object_evaluator_callback) { destruct_object_evaluator_callback= @@ -633,9 +636,7 @@ void really_free_object(struct object *o) free((char *)o); - /* Not using GC_FREE_OBJ here, since it balks in gc pass 3. This - * case is ok, since no destroy() is called. */ - LOW_GC_FREE(); + GC_FREE(o); } } @@ -1223,10 +1224,10 @@ void gc_mark_all_objects(void) } -void gc_free_all_unreferenced_objects(void) +int gc_destroy_all_unreferenced_objects(void) { + int n = 0; struct object *o,*next; - extern int Pike_in_gc; #ifdef PIKE_DEBUG if(d_flag) @@ -1245,12 +1246,10 @@ void gc_free_all_unreferenced_objects(void) } #endif - Pike_in_gc=4; /* Allow thread switches, god help us */ - for(o=first_object;o;o=o->next) { #ifdef PIKE_DEBUG - get_marker(o)->flags |= GC_OBJ_PASS_4; + get_marker(o)->flags |= GC_OBJ_DESTROY_CHECK; #endif if(gc_do_free(o)) { @@ -1259,8 +1258,34 @@ void gc_free_all_unreferenced_objects(void) get_marker(o)->flags |= GC_DO_FREE_OBJ; #endif call_destroy(o,0); + n++; + } + } + + return n; +} + +int gc_free_all_unreferenced_objects(void) +{ + int n = 0; + struct object *o,*next; + +#ifdef PIKE_DEBUG + if(d_flag) + { + for(o=first_object;o;o=next) + { + if(!gc_do_free(o)) + { + add_ref(o); + gc_check_object(o); + SET_NEXT_AND_FREE(o,free_object); + }else{ + next=o->next; + } } } +#endif for(o=first_object;o;o=next) { @@ -1268,7 +1293,7 @@ void gc_free_all_unreferenced_objects(void) { #ifdef PIKE_DEBUG if (!(get_marker(o)->flags & GC_DO_FREE_OBJ) || - !(get_marker(o)->flags & GC_OBJ_PASS_4)) { + !(get_marker(o)->flags & GC_OBJ_DESTROY_CHECK)) { extern char *fatal_after_gc; fprintf(stderr,"**Object unexpectedly marked for gc. flags: %d\n", get_marker(o)->flags); @@ -1276,14 +1301,19 @@ void gc_free_all_unreferenced_objects(void) locate_references(o); fprintf(stderr,"##### Continuing search for more bugs....\n"); fatal_after_gc="Object unexpectedly marked for gc.\n"; + next=o->next; /* Leave it alone and continue. */ + continue; } #endif low_destruct(o,1); + n++; SET_NEXT_AND_FREE(o,free_object); }else{ next=o->next; } } + + return n; } void count_memory_in_objects(INT32 *num_, INT32 *size_) diff --git a/src/object.h b/src/object.h index f564caa1b26012723287aa775545ab9a4bbcfc0a..30048971e506f2f7421fd29c3c098595b0ab6d7d 100644 --- a/src/object.h +++ b/src/object.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: object.h,v 1.43 2000/04/19 21:49:27 mast Exp $ + * $Id: object.h,v 1.44 2000/04/20 01:49:44 mast Exp $ */ #ifndef OBJECT_H #define OBJECT_H @@ -96,7 +96,8 @@ struct array *object_values(struct object *o); void gc_mark_object_as_referenced(struct object *o); void gc_check_all_objects(void); void gc_mark_all_objects(void); -void gc_free_all_unreferenced_objects(void); +int gc_destroy_all_unreferenced_objects(void); +int gc_free_all_unreferenced_objects(void); void count_memory_in_objects(INT32 *num_, INT32 *size_); struct magic_index_struct; void push_magic_index(struct program *type, int inherit_no, int parent_level); diff --git a/src/program.c b/src/program.c index 96bf3abb947886f99fb248a432baa8472acf07e5..de0d0ac8772cfa3df2c9bbb0f507f4eb3fd9b7f9 100644 --- a/src/program.c +++ b/src/program.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: program.c,v 1.230 2000/04/19 16:05:19 mast Exp $"); +RCSID("$Id: program.c,v 1.231 2000/04/20 01:49:44 mast Exp $"); #include "program.h" #include "object.h" #include "dynamic_buffer.h" @@ -971,7 +971,7 @@ void really_free_program(struct program *p) FREE_PROT(p); dmfree((char *)p); - GC_FREE(); + GC_FREE(p); } #ifdef PIKE_DEBUG diff --git a/src/threads.h b/src/threads.h index ed6ad41d2fa6a40ac1c8dd13165bf72636eaacd4..256559d1f5cd2e2afdc2a991cee548345388a32c 100644 --- a/src/threads.h +++ b/src/threads.h @@ -1,5 +1,5 @@ /* - * $Id: threads.h,v 1.86 2000/04/19 16:03:31 mast Exp $ + * $Id: threads.h,v 1.87 2000/04/20 01:49:45 mast Exp $ */ #ifndef THREADS_H #define THREADS_H @@ -506,7 +506,7 @@ struct thread_state { DO_IF_DEBUG({ \ if(thread_for_id(th_self()) != thread_id) \ fatal("thread_for_id() (or thread_id) failed! %p != %p\n",thread_for_id(th_self()),thread_id); \ - if (Pike_in_gc >0 && Pike_in_gc <4) \ + if (Pike_in_gc >1 && Pike_in_gc <4) \ fatal("Threads allowed during garbage collection.\n"); \ }) \ if(num_threads > 1 && !threads_disabled) { \ @@ -541,7 +541,7 @@ struct thread_state { DO_IF_DEBUG({ \ if(thread_for_id(th_self()) != thread_id) \ fatal("thread_for_id() (or thread_id) failed! %p != %p\n",thread_for_id(th_self()),thread_id); \ - if (Pike_in_gc >0 && Pike_in_gc <4) \ + if (Pike_in_gc >1 && Pike_in_gc <4) \ fatal("Threads allowed during garbage collection.\n"); \ }) \ if(num_threads > 1 && !threads_disabled) { \