diff --git a/src/array.c b/src/array.c index 151cba7a35d179446881d293ba1b77dedd060d8e..f7c20a7ff2333f5e1b176e4d3b126c166b814130 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.67 2000/04/20 02:41:44 hubbe Exp $"); +RCSID("$Id: array.c,v 1.68 2000/04/23 03:01:25 mast Exp $"); struct array empty_array= { @@ -57,12 +57,12 @@ struct array *low_allocate_array(INT32 size,INT32 extra_space) return &empty_array; } - GC_ALLOC(); - v=(struct array *)malloc(sizeof(struct array)+ (size+extra_space-1)*sizeof(struct svalue)); if(!v) error("Couldn't allocate array, out of memory.\n"); + + GC_ALLOC(v); /* for now, we don't know what will go in here */ @@ -104,7 +104,7 @@ static void array_free_no_free(struct array *v) free((char *)v); - GC_FREE(v); + GC_FREE(); } /* @@ -1817,6 +1817,20 @@ static void gc_check_array(struct array *a) } } +#ifdef PIKE_DEBUG +INT32 gc_touch_all_arrays(void) +{ + INT32 n = 0; + struct array *a = &empty_array; + do { + debug_gc_touch(a); + n++; + a=a->next; + } while (a != &empty_array); + return n; +} +#endif + void gc_check_all_arrays(void) { struct array *a; diff --git a/src/array.h b/src/array.h index 5b65711c48a0d73b800802453bb5572a03a87b20..aa0b652fd0798fd36ab70aad8b16ee29c01b8a05 100644 --- a/src/array.h +++ b/src/array.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: array.h,v 1.18 1999/10/03 21:44:18 hubbe Exp $ + * $Id: array.h,v 1.19 2000/04/23 03:01:25 mast Exp $ */ #ifndef ARRAY_H #define ARRAY_H @@ -148,6 +148,7 @@ void array_replace(struct array *a, void check_array(struct array *a); void check_all_arrays(void); void gc_mark_array_as_referenced(struct array *a); +INT32 gc_touch_all_arrays(void); void gc_check_all_arrays(void); void gc_mark_all_arrays(void); void gc_free_all_unreferenced_arrays(void); diff --git a/src/gc.c b/src/gc.c index e4b02096e02bacd98eef199eec7fc31ba54e1c38..e541d534b5b07fc1f6d222f69afd863e03d72bb5 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.78 2000/04/22 02:23:56 hubbe Exp $"); +RCSID("$Id: gc.c,v 1.79 2000/04/23 03:01:25 mast Exp $"); /* Run garbage collect approximate every time we have * 20 percent of all arrays, objects and programs is @@ -42,7 +42,7 @@ RCSID("$Id: gc.c,v 1.78 2000/04/22 02:23:56 hubbe Exp $"); #define MULTIPLIER 0.9 #define MARKER_CHUNK_SIZE 1023 -INT32 num_objects =0; +INT32 num_objects = 1; /* Account for empty_array. */ INT32 num_allocs =0; INT32 alloc_threshold = MIN_ALLOC_THRESHOLD; int Pike_in_gc = 0; @@ -129,6 +129,7 @@ static void *found_in=0; static int found_in_type=0; void *gc_svalue_location=0; char *fatal_after_gc=0; +static int gc_debug = 0; #define DESCRIBE_MEM 1 #define DESCRIBE_NO_REFS 2 @@ -387,6 +388,19 @@ void low_describe_something(void *a, fprintf(stderr,"%*s**Parent identifier: %d\n",indent,"",((struct object *)a)->parent_identifier); fprintf(stderr,"%*s**Program id: %ld\n",indent,"",((struct object *)a)->program_id); + if (((struct object *)a)->next == ((struct object *)a)) + fprintf(stderr, "%*s**The object is fake.\n",indent,""); + + if(!p) + { + fprintf(stderr,"%*s**The object is destructed.\n",indent,""); + p=id_to_program(((struct object *)a)->program_id); + } + if (p) { + fprintf(stderr,"%*s**Attempting to describe program object was instantiated from:\n",indent,""); + low_describe_something(p, T_PROGRAM, indent, depth, flags); + } + if( ((struct object *)a)->parent) { fprintf(stderr,"%*s**Describing object's parent:\n",indent,""); @@ -396,14 +410,7 @@ void low_describe_something(void *a, }else{ fprintf(stderr,"%*s**There is no parent (any longer?)\n",indent,""); } - if(!p) - { - fprintf(stderr,"%*s**The object is destructed.\n",indent,""); - p=id_to_program(((struct object *)a)->program_id); - - if(!p) break; - } - fprintf(stderr,"%*s**Attempting to describe program object was instantiated from:\n",indent,""); + break; case T_PROGRAM: { @@ -566,13 +573,49 @@ void debug_describe_svalue(struct svalue *s) describe_something(s->u.refs,s->type,0,2,0); } +void debug_gc_touch(void *a) +{ + struct marker *m; + if (!a) fatal("real_gc_check(): Got null pointer.\n"); + + m = find_marker(a); + if (Pike_in_gc == GC_PASS_PRETOUCH) { + if (m) { + fprintf(stderr,"**Object touched twice.\n"); + describe(a); + fatal("Object touched twice.\n"); + } + get_marker(a)->flags |= GC_TOUCHED; + } + else if (Pike_in_gc == GC_PASS_POSTTOUCH) { + if (m) { + if (!(m->flags & GC_TOUCHED)) { + fprintf(stderr,"**An existing but untouched marker found for object in linked lists. flags: %x.\n", m->flags); + describe(a); + fatal("An existing but untouched marker found for object in linked lists.\n"); + } + if ((m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED) { + fprintf(stderr,"**An object to garb is still around. flags: %x.\n", m->flags); + fprintf(stderr," has %ld references, while gc() found %ld + %ld external.\n",(long)*(INT32 *)a,(long)m->refs,(long)m->xrefs); + describe(a); + locate_references(a); + fprintf(stderr,"##### Continuing search for more bugs....\n"); + fatal_after_gc="An object to garb is still around.\n"; + } + } + } + else + fatal("debug_gc_touch() used in invalid gc pass.\n"); +} + #endif /* PIKE_DEBUG */ INT32 real_gc_check(void *a) { - struct marker *m=get_marker(a); + struct marker *m; #ifdef PIKE_DEBUG + if (!a) fatal("real_gc_check(): Got null pointer.\n"); if(check_for) { if(check_for == a) @@ -580,9 +623,10 @@ INT32 real_gc_check(void *a) gdb_gc_stop_here(a); } - if(check_for == (void *)1 && gc_do_free(a)) + m=get_marker(a); + if(check_for == (void *)1 && + m && (m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED) { - struct marker *m=get_marker(a); int t=attempt_to_identify(a); if(t != T_STRING && t != T_UNKNOWN) { @@ -601,8 +645,10 @@ INT32 real_gc_check(void *a) return 0; } - if (Pike_in_gc /100 != 1) - fatal("gc check attempted in pass %d.\n", Pike_in_gc); + if (Pike_in_gc != GC_PASS_CHECK) + fatal("gc check attempted in invalid pass.\n"); + + m = get_marker(a); if(m->saved_refs != -1) if(m->saved_refs != *(INT32 *)a) { @@ -669,9 +715,15 @@ static void exit_gc(void) #ifdef PIKE_DEBUG void locate_references(void *a) { + int tmp, orig_in_gc = Pike_in_gc; void *orig_check_for=check_for; if(!Pike_in_gc) 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:\n"); @@ -717,8 +769,10 @@ void locate_references(void *a) } #endif + Pike_in_gc = orig_in_gc; if(!Pike_in_gc) exit_gc(); + d_flag=tmp; } #endif @@ -727,11 +781,13 @@ void locate_references(void *a) int debug_gc_is_referenced(void *a) { struct marker *m; - m=get_marker(a); + if (!a) fatal("real_gc_check(): Got null pointer.\n"); + m=get_marker(a); if(m->refs + m->xrefs > *(INT32 *)a || (!(m->refs < *(INT32 *)a) && m->xrefs) || - (Pike_in_gc < 300 && m->saved_refs != -1 && m->saved_refs != *(INT32 *)a)) + (Pike_in_gc >= GC_PASS_CHECK && Pike_in_gc <= GC_PASS_MARK && + m->saved_refs != -1 && m->saved_refs != *(INT32 *)a)) { INT32 refs=m->refs; INT32 xrefs=m->xrefs; @@ -744,7 +800,7 @@ int debug_gc_is_referenced(void *a) (long)xrefs); if(m->saved_refs != *(INT32 *)a) - fprintf(stderr,"**In pass one it had %ld refs!!!\n",(long)m->saved_refs); + fprintf(stderr,"**In check pass it had %ld refs!!!\n",(long)m->saved_refs); describe_something(a, t, 0,2,0); @@ -764,6 +820,7 @@ int debug_gc_is_referenced(void *a) int gc_external_mark3(void *a, void *in, char *where) { struct marker *m; + if (!a) fatal("real_gc_check(): Got null pointer.\n"); if(check_for) { @@ -783,9 +840,10 @@ int gc_external_mark3(void *a, void *in, char *where) return 1; } - if(check_for == (void *)1 && gc_do_free(a)) + m=get_marker(a); + if(check_for == (void *)1 && + m && (m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED) { - struct marker *m=get_marker(a); int t=attempt_to_identify(a); if(t != T_STRING && t != T_UNKNOWN) { @@ -816,13 +874,14 @@ int gc_external_mark3(void *a, void *in, char *where) int gc_mark(void *a) { struct marker *m; - m=get_marker(debug_malloc_pass(a)); #ifdef PIKE_DEBUG - if (Pike_in_gc /100 != 2) - fatal("gc mark attempted in pass %d.\n", Pike_in_gc); + if (!a) fatal("real_gc_check(): Got null pointer.\n"); + if (Pike_in_gc != GC_PASS_MARK) + fatal("gc mark attempted in invalid pass.\n"); #endif + m = get_marker(debug_malloc_pass(a)); if(m->flags & GC_REFERENCED) { return 0; @@ -836,8 +895,10 @@ int gc_mark(void *a) int debug_gc_do_free(void *a) { struct marker *m; + if (!a) fatal("real_gc_check(): Got null pointer.\n"); - m=get_marker(debug_malloc_pass(a)); + m=find_marker(debug_malloc_pass(a)); + if (!m) return 0; /* Object created after mark pass. */ if( (m->flags & (GC_REFERENCED|GC_CHECKED)) == GC_CHECKED && (m->flags & GC_XREFERENCED) ) @@ -849,12 +910,12 @@ int debug_gc_do_free(void *a) { fprintf(stderr, "**gc_is_referenced failed, object has %ld references,\n" - "** while gc() found %ld + %ld external. (type=%d, flags=%d)\n", + "** while gc() found %ld + %ld external. (type=%d, flags=%x)\n", (long)*(INT32 *)a,(long)refs,(long)xrefs,t,m->flags); describe_something(a, t, 4,1,0); locate_references(a); - + fatal("GC failed object (has %d, found %d + %d external)\n", *(INT32 *)a, refs, @@ -879,7 +940,11 @@ void do_gc(void) #endif if(Pike_in_gc) return; - Pike_in_gc=10; /* before pass 1 */ + init_gc(); + Pike_in_gc=GC_PASS_PREPARE; +#ifdef PIKE_DEBUG + gc_debug = d_flag; +#endif /* 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 @@ -915,10 +980,21 @@ void do_gc(void) objects_freed*=multiplier; objects_freed += (double) num_objects; +#ifdef PIKE_DEBUG + if (gc_debug) { + INT32 n; + Pike_in_gc = GC_PASS_PRETOUCH; + n = gc_touch_all_arrays(); + n += gc_touch_all_multisets(); + n += gc_touch_all_mappings(); + n += gc_touch_all_programs(); + n += gc_touch_all_objects(); + if (n != num_objects) + fatal("Object count wrong before gc; expected %d, got %d.\n", num_objects, n); + } +#endif - init_gc(); - - Pike_in_gc=100; /* pass one */ + Pike_in_gc=GC_PASS_CHECK; /* First we count internal references */ gc_check_all_arrays(); gc_check_all_multisets(); @@ -935,12 +1011,12 @@ void do_gc(void) } #endif - /* These callbacks are mainly for pass 1, but can also - * do things that are normally associated with pass 2 + /* 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, (void *)0); - Pike_in_gc=200; /* pass two */ + Pike_in_gc=GC_PASS_MARK; /* Next we mark anything with external references */ gc_mark_all_arrays(); run_queue(&gc_mark_queue); @@ -959,21 +1035,19 @@ void do_gc(void) #ifdef PIKE_DEBUG check_for=(void *)1; #endif - Pike_in_gc=350; /* pass 3.5 */ + Pike_in_gc=GC_PASS_FREE; /* 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(); - Pike_in_gc=300; + Pike_in_gc=GC_PASS_DESTROY; /* Pike code allowed in this pass. */ /* 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=350; + Pike_in_gc=GC_PASS_FREE; destructed = gc_free_all_unreferenced_objects(); #ifdef PIKE_DEBUG @@ -984,11 +1058,27 @@ void do_gc(void) if(fatal_after_gc) fatal(fatal_after_gc); #endif + Pike_in_gc=GC_PASS_DESTRUCT; + destruct_objects_to_destruct(); + +#ifdef PIKE_DEBUG + if (gc_debug) { + INT32 n; + Pike_in_gc=GC_PASS_POSTTOUCH; + n = gc_touch_all_arrays(); + n += gc_touch_all_multisets(); + n += gc_touch_all_mappings(); + n += gc_touch_all_programs(); + n += gc_touch_all_objects(); + if (n != num_objects) + fatal("Object count wrong after gc; expected %d, got %d.\n", num_objects, n); + if(fatal_after_gc) fatal(fatal_after_gc); + } +#endif + + Pike_in_gc=0; exit_gc(); - Pike_in_gc=400; - destruct_objects_to_destruct(); - objects_freed -= (double) num_objects; tmp=(double)num_objects; @@ -1026,7 +1116,6 @@ void do_gc(void) #else if(d_flag > 3) ADD_GC_CALLBACK(); #endif - Pike_in_gc=0; } @@ -1057,4 +1146,3 @@ void f__gc_status(INT32 args) f_aggregate_mapping(14); } - diff --git a/src/gc.h b/src/gc.h index 00cd2a2039bfbd96862279f16e2e2f21e8bee932..b60cc46499fbd991b39d7427dba95901a45fdc5c 100644 --- a/src/gc.h +++ b/src/gc.h @@ -1,5 +1,5 @@ /* - * $Id: gc.h,v 1.37 2000/04/20 01:49:43 mast Exp $ + * $Id: gc.h,v 1.38 2000/04/23 03:01:25 mast Exp $ */ #ifndef GC_H #define GC_H @@ -23,21 +23,29 @@ extern void *gc_svalue_location; #define ADD_GC_CALLBACK() gc_evaluator_callback=add_to_callback(&evaluator_callbacks,(callback_func)do_gc,0,0) -#ifdef ALWAYS_GC -#define GC_ALLOC() do{ num_objects++; num_allocs++; if(!gc_evaluator_callback) ADD_GC_CALLBACK(); } while(0) -#else -#define GC_ALLOC() do{ \ +#define LOW_GC_ALLOC(OBJ) do { \ extern int d_flag; \ num_objects++; \ num_allocs++; \ DO_IF_DEBUG( \ if(d_flag) CHECK_INTERPRETER_LOCK(); \ - if(Pike_in_gc > 1 && Pike_in_gc < 4 && Pike_in_gc != 5) \ + if(Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc <= GC_PASS_MARK) \ fatal("Allocating new objects within gc is not allowed!\n"); \ ) \ - if(num_allocs == alloc_threshold && !gc_evaluator_callback) \ - ADD_GC_CALLBACK(); \ - } while(0) + if (Pike_in_gc) remove_marker(OBJ); \ +} while (0) + +#ifdef ALWAYS_GC +#define GC_ALLOC(OBJ) do{ \ + LOW_GC_ALLOC(OBJ); \ + if(!gc_evaluator_callback) ADD_GC_CALLBACK(); \ +} while(0) +#else +#define GC_ALLOC(OBJ) do{ \ + LOW_GC_ALLOC(OBJ); \ + if(num_allocs == alloc_threshold && !gc_evaluator_callback) \ + ADD_GC_CALLBACK(); \ +} while(0) #endif struct marker @@ -69,6 +77,7 @@ int debug_gc_check(void *x, TYPE_T t, void *data); void describe_something(void *a, int t, int indent, int depth, int flags); void describe(void *x); void debug_describe_svalue(struct svalue *s); +void debug_gc_touch(void *a); INT32 real_gc_check(void *a); void locate_references(void *a); int debug_gc_is_referenced(void *a); @@ -85,19 +94,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(OBJ) do { \ + +#define LOW_GC_FREE() 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(OBJ) do { \ - if(Pike_in_gc >2 && Pike_in_gc <4) \ +#define GC_FREE() do { \ + if(Pike_in_gc == GC_PASS_MARK) \ fatal("Freeing objects within gc is not allowed!\n"); \ - LOW_GC_FREE(OBJ); \ + LOW_GC_FREE(); \ }while(0) #else @@ -105,11 +114,8 @@ 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(OBJ) do { \ - num_objects-- ; \ - if (Pike_in_gc) remove_marker(OBJ); \ -}while(0) -#define GC_FREE(OBJ) LOW_GC_FREE(OBJ) +#define LOW_GC_FREE() do {num_objects-- ; }while(0) +#define GC_FREE() LOW_GC_FREE() #endif @@ -122,10 +128,20 @@ void f__gc_status(INT32 args); #define GC_REFERENCED 1 #define GC_XREFERENCED 2 #define GC_CHECKED 4 -#ifdef PIKE_DEBUG #define GC_OBJ_DESTROY_CHECK 8 #define GC_DO_FREE_OBJ 16 -#endif +#define GC_TOUCHED 32 + +#define GC_PASS_PREPARE 50 +#define GC_PASS_PRETOUCH 90 +#define GC_PASS_CHECK 100 +#define GC_PASS_MARK 200 +#define GC_PASS_DESTROY 300 +#define GC_PASS_FREE 400 +#define GC_PASS_DESTRUCT 500 +#define GC_PASS_POSTTOUCH 600 + +#define GC_PASS_LOCATE -1 #ifdef PIKE_DEBUG #define gc_is_referenced(X) debug_gc_is_referenced(debug_malloc_pass(X)) diff --git a/src/mapping.c b/src/mapping.c index 1fdfd11eb076ff31945ca45eeba0d4b263f44e24..859b101c6474b940820b81667bac46c507221814 100644 --- a/src/mapping.c +++ b/src/mapping.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: mapping.c,v 1.78 2000/04/20 01:49:43 mast Exp $"); +RCSID("$Id: mapping.c,v 1.79 2000/04/23 03:01:25 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(m); + GC_FREE(); #undef COUNT_OTHER @@ -131,7 +131,7 @@ static void init_mapping(struct mapping *m, INT32 size) e=MAPPING_DATA_SIZE(hashsize, size); md=(struct mapping_data *)xalloc(e); - + m->data=md; md->hashsize=hashsize; @@ -170,10 +170,10 @@ struct mapping *debug_allocate_mapping(int size) { struct mapping *m; - GC_ALLOC(); - m=alloc_mapping(); + GC_ALLOC(m); + INITIALIZE_PROT(m); init_mapping(m,size); @@ -1878,6 +1878,19 @@ static void gc_check_mapping(struct mapping *m) } } +#ifdef PIKE_DEBUG +INT32 gc_touch_all_mappings(void) +{ + INT32 n = 0; + struct mapping *m; + for (m = first_mapping; m; m = m->next) { + debug_gc_touch(m); + n++; + } + return n; +} +#endif + void gc_check_all_mappings(void) { struct mapping *m; diff --git a/src/mapping.h b/src/mapping.h index 5099b7becd38aa42e7184ba8bfd1648630816bdd..b68d318b2586d0954d553e87116ecfc18e2981d4 100644 --- a/src/mapping.h +++ b/src/mapping.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: mapping.h,v 1.23 2000/03/28 17:57:37 grubba Exp $ + * $Id: mapping.h,v 1.24 2000/04/23 03:01:25 mast Exp $ */ #ifndef MAPPING_H #define MAPPING_H @@ -145,6 +145,7 @@ void mapping_search_no_free(struct svalue *to, void check_mapping(struct mapping *m); void check_all_mappings(void); void gc_mark_mapping_as_referenced(struct mapping *m); +INT32 gc_touch_all_mappings(void); void gc_check_all_mappings(void); void gc_mark_all_mappings(void); void gc_free_all_unreferenced_mappings(void); diff --git a/src/multiset.c b/src/multiset.c index 4cbca589753fa55a367bc5c802d2a1aa3ee529fd..6d0f6a3534c4c1af5b5995f38b5b38b00d6a4d85 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.19 2000/04/20 01:49:43 mast Exp $"); +RCSID("$Id: multiset.c,v 1.20 2000/04/23 03:01:25 mast Exp $"); struct multiset *first_multiset; @@ -31,8 +31,8 @@ int multiset_member(struct multiset *l, struct svalue *ind) struct multiset *allocate_multiset(struct array *ind) { struct multiset *l; - GC_ALLOC(); l=ALLOC_STRUCT(multiset); + GC_ALLOC(l); l->next = first_multiset; l->prev = 0; l->refs = 1; @@ -66,7 +66,7 @@ void really_free_multiset(struct multiset *l) if(l->next) l->next->prev = l->prev; free((char *)l); - GC_FREE(l); + GC_FREE(); } @@ -291,6 +291,19 @@ void gc_mark_multiset_as_referenced(struct multiset *l) gc_mark_array_as_referenced(l->ind); } +#ifdef PIKE_DEBUG +INT32 gc_touch_all_multisets(void) +{ + INT32 n = 0; + struct multiset *l; + for(l=first_multiset;l;l=l->next) { + debug_gc_touch(l); + n++; + } + return n; +} +#endif + void gc_check_all_multisets(void) { struct multiset *l; diff --git a/src/multiset.h b/src/multiset.h index 87c4a1aeaedbe6bc8582177766aaf10d2a04fcaa..a84f7c5a5d98de9ab729ff27c59feef6c35486f9 100644 --- a/src/multiset.h +++ b/src/multiset.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: multiset.h,v 1.9 1999/04/13 20:10:06 hubbe Exp $ + * $Id: multiset.h,v 1.10 2000/04/23 03:01:25 mast Exp $ */ #ifndef MULTISET_H #define MULTISET_H @@ -51,6 +51,7 @@ void f_aggregate_multiset(INT32 args); struct multiset *copy_multiset_recursively(struct multiset *l, struct processing *p); void gc_mark_multiset_as_referenced(struct multiset *l); +INT32 gc_touch_all_multisets(void); void gc_check_all_multisets(void); void gc_mark_all_multisets(void); void gc_free_all_unreferenced_multisets(void); diff --git a/src/object.c b/src/object.c index 12fbce252a1782ee65987e9e63f6719534d64cae..1953e5e25418a4182f379381a4b500b23eb1d1d2 100644 --- a/src/object.c +++ b/src/object.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: object.c,v 1.119 2000/04/22 02:25:10 hubbe Exp $"); +RCSID("$Id: object.c,v 1.120 2000/04/23 03:01:25 mast Exp $"); #include "object.h" #include "dynamic_buffer.h" #include "interpret.h" @@ -84,10 +84,10 @@ struct object *low_clone(struct program *p) p->num_clones++; #endif /* PROFILING */ - GC_ALLOC(); - o=(struct object *)xalloc( ((long)(((struct object *)0)->storage))+p->storage_needed); + GC_ALLOC(o); + #ifdef DEBUG_MALLOC if(!debug_malloc_copy_names(o, p)) { @@ -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 >= 100 && Pike_in_gc < 300) + if(Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc <= GC_PASS_MARK) 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 >= 100 && Pike_in_gc < 400) + if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc != GC_PASS_DESTRUCT) fatal("Can't meddle with the object link list in gc pass %d.\n", Pike_in_gc); #endif @@ -572,7 +572,7 @@ void destruct_objects_to_destruct(void) /* link */ DOUBLELINK(first_object,o); - + /* call destroy, keep one ref */ add_ref(o); call_destroy(o,0); @@ -612,10 +612,9 @@ void really_free_object(struct object *o) if(o->prog) { DOUBLELINK(objects_to_destruct,o); - if (Pike_in_gc) { - remove_marker(o); - if (Pike_in_gc < 400) return; /* Done last in gc(). */ - } + if (Pike_in_gc > GC_PASS_PREPARE && Pike_in_gc < GC_PASS_DESTRUCT) + /* destruct_objects_to_destruct() done last in gc() instead. */ + return; if(!destruct_object_evaluator_callback) { destruct_object_evaluator_callback= @@ -636,7 +635,7 @@ void really_free_object(struct object *o) free((char *)o); - GC_FREE(o); + GC_FREE(); } } @@ -1207,10 +1206,24 @@ static inline void gc_check_object(struct object *o) } } -void gc_check_all_objects(void) +#ifdef PIKE_DEBUG +INT32 gc_touch_all_objects(void) { + INT32 n = 0; struct object *o; + for (o = first_object; o; o = o->next) { + debug_gc_touch(o); + n++; + } + if (objects_to_destruct) + fatal("Shouldn't have any objects to destruct in touch pass.\n"); + return n; +} +#endif +void gc_check_all_objects(void) +{ + struct object *o; for(o=first_object;o;o=o->next) gc_check_object(o); } @@ -1281,17 +1294,13 @@ int gc_free_all_unreferenced_objects(void) if(gc_do_free(o)) { #ifdef PIKE_DEBUG - if (!(get_marker(o)->flags & GC_DO_FREE_OBJ) || - !(get_marker(o)->flags & GC_OBJ_DESTROY_CHECK)) { + if (!(get_marker(o)->flags & (GC_OBJ_DESTROY_CHECK|GC_DO_FREE_OBJ))) { extern char *fatal_after_gc; - fprintf(stderr,"**Object unexpectedly marked for gc. flags: %d\n", + fprintf(stderr,"**Object unexpectedly marked for gc. flags: %x\n", get_marker(o)->flags); describe(o); 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; + fatal("Object unexpectedly marked for gc.\n"); } #endif low_destruct(o,1); diff --git a/src/object.h b/src/object.h index 30048971e506f2f7421fd29c3c098595b0ab6d7d..e3562fea391ef9184d6b23bd3c7694029643e429 100644 --- a/src/object.h +++ b/src/object.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: object.h,v 1.44 2000/04/20 01:49:44 mast Exp $ + * $Id: object.h,v 1.45 2000/04/23 03:01:25 mast Exp $ */ #ifndef OBJECT_H #define OBJECT_H @@ -94,6 +94,7 @@ void cleanup_objects(void); struct array *object_indices(struct object *o); struct array *object_values(struct object *o); void gc_mark_object_as_referenced(struct object *o); +INT32 gc_touch_all_objects(void); void gc_check_all_objects(void); void gc_mark_all_objects(void); int gc_destroy_all_unreferenced_objects(void); diff --git a/src/program.c b/src/program.c index de0d0ac8772cfa3df2c9bbb0f507f4eb3fd9b7f9..335830241c2ceab6e9f0b6bcc0237abcb160584d 100644 --- a/src/program.c +++ b/src/program.c @@ -5,7 +5,7 @@ \*/ /**/ #include "global.h" -RCSID("$Id: program.c,v 1.231 2000/04/20 01:49:44 mast Exp $"); +RCSID("$Id: program.c,v 1.232 2000/04/23 03:01:26 mast Exp $"); #include "program.h" #include "object.h" #include "dynamic_buffer.h" @@ -689,7 +689,7 @@ struct program *low_allocate_program(void) MEMSET(p, 0, sizeof(struct program)); p->alignment_needed=1; - GC_ALLOC(); + GC_ALLOC(p); p->refs=1; p->id=++current_program_id; @@ -784,7 +784,7 @@ void low_start_new_program(struct program *p, #else fake_object=ALLOC_STRUCT(object); #endif - GC_ALLOC(); + GC_ALLOC(fake_object); fake_object->next=fake_object; fake_object->prev=fake_object; @@ -971,7 +971,7 @@ void really_free_program(struct program *p) FREE_PROT(p); dmfree((char *)p); - GC_FREE(p); + GC_FREE(); } #ifdef PIKE_DEBUG @@ -3561,6 +3561,25 @@ static void gc_check_program(struct program *p) #endif } +#ifdef PIKE_DEBUG +INT32 gc_touch_all_programs(void) +{ + INT32 n = 0; + struct program *p; + struct program_state *ps; + for (p = first_program; p; p = p->next) { + debug_gc_touch(p); + n++; + } + /* Count the fake objects. They're not part of the gc, but they're + * still counted by the gc. */ + if (fake_object) n++; + for (ps = previous_program_state; ps; ps = ps->previous) + if (ps->fake_object) n++; + return n; +} +#endif + void gc_check_all_programs(void) { struct program *p; diff --git a/src/program.h b/src/program.h index ceb71467425c1744aa591a71a3e68776466fade4..2f52cfc2063264b1c1721da5105514df616f9cef 100644 --- a/src/program.h +++ b/src/program.h @@ -5,7 +5,7 @@ \*/ /* - * $Id: program.h,v 1.86 2000/04/08 02:01:09 hubbe Exp $ + * $Id: program.h,v 1.87 2000/04/23 03:01:26 mast Exp $ */ #ifndef PROGRAM_H #define PROGRAM_H @@ -453,6 +453,7 @@ void check_all_programs(void); void init_program(void); void cleanup_program(void); void gc_mark_program_as_referenced(struct program *p); +INT32 gc_touch_all_programs(void); void gc_check_all_programs(void); void gc_mark_all_programs(void); void gc_free_all_unreferenced_programs(void); diff --git a/src/svalue.c b/src/svalue.c index 57c31792773064e76f70cdf23e798012ad85e34b..fbd8357213123f858f9605cb9f826bf77add35bf 100644 --- a/src/svalue.c +++ b/src/svalue.c @@ -23,7 +23,7 @@ #include "queue.h" #include "bignum.h" -RCSID("$Id: svalue.c,v 1.71 2000/04/19 16:05:19 mast Exp $"); +RCSID("$Id: svalue.c,v 1.72 2000/04/23 03:01:26 mast Exp $"); struct svalue dest_ob_zero = { T_INT, 0 }; @@ -1411,7 +1411,7 @@ void debug_gc_mark_svalues(struct svalue *s, int num) else { describe(s->u.object); - fatal("Unfreed destructed object in GC pass 2??\n"); + fatal("Unfreed destructed object in GC mark pass??\n"); } #endif break; @@ -1425,7 +1425,7 @@ void debug_gc_mark_short_svalue(union anything *u, TYPE_T type) { #ifdef PIKE_DEBUG case T_STRING: - if(d_flag) gc_mark(debug_malloc_pass(u->string)); + if(d_flag && u->refs) gc_mark(debug_malloc_pass(u->string)); break; #endif @@ -1470,7 +1470,7 @@ void debug_gc_mark_short_svalue(union anything *u, TYPE_T type) else { describe(u->object); - fatal("Unfreed destructed object in GC pass 2??\n"); + fatal("Unfreed destructed object in GC mark pass??\n"); } #endif break; diff --git a/src/threads.h b/src/threads.h index f907dd782e7c20930df45a26ca17c628dfb5608f..268dcccf06f05f2fc5bd95e6483cd19bd7229eb1 100644 --- a/src/threads.h +++ b/src/threads.h @@ -1,5 +1,5 @@ /* - * $Id: threads.h,v 1.88 2000/04/21 23:07:10 hubbe Exp $ + * $Id: threads.h,v 1.89 2000/04/23 03:01:26 mast Exp $ */ #ifndef THREADS_H #define THREADS_H @@ -57,9 +57,6 @@ struct object; extern size_t thread_stack_size; extern struct object *thread_id; -/* Used by debug code. Avoid pulling in gc.h only for this. */ -extern int Pike_in_gc; - #define DEFINE_MUTEX(X) PIKE_MUTEX_T X @@ -504,9 +501,10 @@ struct thread_state { #define THREADS_ALLOW() do { \ struct thread_state *_tmp=OBJ2THREAD(thread_id); \ DO_IF_DEBUG({ \ + extern int Pike_in_gc; \ 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 >=100 && Pike_in_gc <300) \ + if (Pike_in_gc >= 100 && Pike_in_gc != 300 && Pike_in_gc != 500) \ fatal("Threads allowed during garbage collection.\n"); \ }) \ if(num_threads > 1 && !threads_disabled) { \ @@ -539,9 +537,10 @@ struct thread_state { #define THREADS_ALLOW_UID() do { \ struct thread_state *_tmp_uid=OBJ2THREAD(thread_id); \ DO_IF_DEBUG({ \ + extern int Pike_in_gc; \ 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 >=100 && Pike_in_gc <300) \ + if (Pike_in_gc >= 100 && Pike_in_gc != 300 && Pike_in_gc != 500) \ fatal("Threads allowed during garbage collection.\n"); \ }) \ if(num_threads > 1 && !threads_disabled) { \