6930181996-02-25Fredrik Hübinette (Hubbe) /*\
06983f1996-09-22Fredrik Hübinette (Hubbe) ||| This file a part of Pike, and is copyright by Fredrik Hubinette ||| Pike is distributed as GPL (General Public License)
6930181996-02-25Fredrik Hübinette (Hubbe) ||| See the files COPYING and DISCLAIMER for more information. \*/ #include "global.h" #ifdef GC2
c94c371996-03-28Fredrik Hübinette (Hubbe) 
a29e021996-10-15Fredrik Hübinette (Hubbe) struct callback *gc_evaluator_callback=0;
c94c371996-03-28Fredrik Hübinette (Hubbe) #include "array.h"
06983f1996-09-22Fredrik Hübinette (Hubbe) #include "multiset.h"
c94c371996-03-28Fredrik Hübinette (Hubbe) #include "mapping.h" #include "object.h" #include "program.h"
4a578f1997-01-27Fredrik Hübinette (Hubbe) #include "stralloc.h"
9c6f7d1997-04-15Fredrik Hübinette (Hubbe) #include "stuff.h" #include "error.h"
c94c371996-03-28Fredrik Hübinette (Hubbe) 
6930181996-02-25Fredrik Hübinette (Hubbe) #include "gc.h" #include "main.h" /* Run garbage collect approximate every time we have * 20 percent of all arrays, objects and programs is * garbage. */ #define GC_CONST 20 #define MIN_ALLOC_THRESHOLD 1000
b95bef1996-03-29Fredrik Hübinette (Hubbe) #define MAX_ALLOC_THRESHOLD 10000000
6930181996-02-25Fredrik Hübinette (Hubbe) #define MULTIPLIER 0.9
c94c371996-03-28Fredrik Hübinette (Hubbe) #define MARKER_CHUNK_SIZE 1023
6930181996-02-25Fredrik Hübinette (Hubbe)  INT32 num_objects; INT32 num_allocs; INT32 alloc_threshold = MIN_ALLOC_THRESHOLD; static double objects_alloced; static double objects_freed;
4a578f1997-01-27Fredrik Hübinette (Hubbe) struct callback_list gc_callbacks; struct callback *add_gc_callback(callback_func call, void *arg, callback_func free_func) { return add_to_callback(&gc_callbacks, call, arg, free_func); }
c94c371996-03-28Fredrik Hübinette (Hubbe) #define GC_REFERENCED 1 struct marker { struct marker *next; void *marked; INT32 refs; INT32 flags; }; struct marker_chunk { struct marker_chunk *next; struct marker markers[MARKER_CHUNK_SIZE]; }; static struct marker_chunk *chunk=0; static int markers_left_in_chunk=0; static struct marker *new_marker() { if(!markers_left_in_chunk) { struct marker_chunk *m; m=(struct marker_chunk *)xalloc(sizeof(struct marker_chunk)); m->next=chunk; chunk=m; markers_left_in_chunk=MARKER_CHUNK_SIZE; } markers_left_in_chunk--; return chunk->markers + markers_left_in_chunk; } static struct marker **hash=0; static int hashsize=0; static struct marker *getmark(void *a) { int hashval; struct marker *m; hashval=((long)a)%hashsize; for(m=hash[hashval];m;m=m->next) if(m->marked == a) return m; m=new_marker(); m->marked=a; m->refs=0; m->flags=0; m->next=hash[hashval]; hash[hashval]=m; return m; }
b8a6e71996-09-25Fredrik Hübinette (Hubbe) #ifdef DEBUG
5b26741997-06-26Fredrik Hübinette (Hubbe) void *gc_check_for =0;
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  static void gdb_gc_stop_here(void *a) { fprintf(stderr,"One ref found.\n"); } #endif
4a578f1997-01-27Fredrik Hübinette (Hubbe) INT32 gc_check(void *a)
c94c371996-03-28Fredrik Hübinette (Hubbe) {
b8a6e71996-09-25Fredrik Hübinette (Hubbe) #ifdef DEBUG
5b26741997-06-26Fredrik Hübinette (Hubbe)  if(gc_check_for)
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  {
5b26741997-06-26Fredrik Hübinette (Hubbe)  if(gc_check_for == a)
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  { gdb_gc_stop_here(a);
5b26741997-06-26Fredrik Hübinette (Hubbe)  return -2;
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  }
5b26741997-06-26Fredrik Hübinette (Hubbe)  return -1;
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  } #endif
4a578f1997-01-27Fredrik Hübinette (Hubbe)  return getmark(a)->refs++;
c94c371996-03-28Fredrik Hübinette (Hubbe) } int gc_is_referenced(void *a) { struct marker *m; m=getmark(a); #ifdef DEBUG if(m->refs > *(INT32 *)a)
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  {
5b26741997-06-26Fredrik Hübinette (Hubbe)  gc_check_for=a; fprintf(stderr,"Too many ref counts found %d > %d (%lx)\n",m->refs, *(INT32 *)a, (long)a);
b8a6e71996-09-25Fredrik Hübinette (Hubbe) 
5b26741997-06-26Fredrik Hübinette (Hubbe)  fprintf(stderr,"Checking arrays\n");
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  gc_check_all_arrays();
5b26741997-06-26Fredrik Hübinette (Hubbe)  fprintf(stderr,"Checking multisets\n");
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  gc_check_all_multisets();
5b26741997-06-26Fredrik Hübinette (Hubbe)  fprintf(stderr,"Checking mappings\n");
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  gc_check_all_mappings();
5b26741997-06-26Fredrik Hübinette (Hubbe)  fprintf(stderr,"Checking programs\n");
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  gc_check_all_programs();
5b26741997-06-26Fredrik Hübinette (Hubbe)  fprintf(stderr,"Checking objects\n");
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  gc_check_all_objects();
5b26741997-06-26Fredrik Hübinette (Hubbe)  fprintf(stderr,"Checking callbacks\n");
4a578f1997-01-27Fredrik Hübinette (Hubbe)  call_callback(& gc_callbacks, (void *)0);
b8a6e71996-09-25Fredrik Hübinette (Hubbe) 
5b26741997-06-26Fredrik Hübinette (Hubbe)  gc_check_for=0;
c94c371996-03-28Fredrik Hübinette (Hubbe)  fatal("Ref counts are totally wrong!!!\n");
b8a6e71996-09-25Fredrik Hübinette (Hubbe)  }
c94c371996-03-28Fredrik Hübinette (Hubbe) #endif return m->refs < *(INT32 *)a; } int gc_mark(void *a) { struct marker *m; m=getmark(a); if(m->flags & GC_REFERENCED) { return 0; }else{ m->flags |= GC_REFERENCED; return 1; } } int gc_do_free(void *a) { struct marker *m; m=getmark(a); return !(m->flags & GC_REFERENCED); } /* Not all of these are primes, but they should be adequate */ static INT32 hashprimes[] = { 31, /* ~ 2^0 = 1 */ 31, /* ~ 2^1 = 2 */ 31, /* ~ 2^2 = 4 */ 31, /* ~ 2^3 = 8 */ 31, /* ~ 2^4 = 16 */ 31, /* ~ 2^5 = 32 */ 61, /* ~ 2^6 = 64 */ 127, /* ~ 2^7 = 128 */ 251, /* ~ 2^8 = 256 */ 541, /* ~ 2^9 = 512 */ 1151, /* ~ 2^10 = 1024 */ 2111, /* ~ 2^11 = 2048 */ 4327, /* ~ 2^12 = 4096 */ 8803, /* ~ 2^13 = 8192 */ 17903, /* ~ 2^14 = 16384 */ 32321, /* ~ 2^15 = 32768 */ 65599, /* ~ 2^16 = 65536 */ 133153, /* ~ 2^17 = 131072 */ 270001, /* ~ 2^18 = 264144 */ 547453, /* ~ 2^19 = 524288 */ 1109891, /* ~ 2^20 = 1048576 */ 2000143, /* ~ 2^21 = 2097152 */ 4561877, /* ~ 2^22 = 4194304 */ 9248339, /* ~ 2^23 = 8388608 */ 16777215, /* ~ 2^24 = 16777216 */ 33554431, /* ~ 2^25 = 33554432 */ 67108863, /* ~ 2^26 = 67108864 */ 134217727, /* ~ 2^27 = 134217728 */ 268435455, /* ~ 2^28 = 268435456 */ 536870911, /* ~ 2^29 = 536870912 */ 1073741823,/* ~ 2^30 = 1073741824 */ 2147483647,/* ~ 2^31 = 2147483648 */ };
a29e021996-10-15Fredrik Hübinette (Hubbe) void do_gc()
6930181996-02-25Fredrik Hübinette (Hubbe) {
890e5b1996-11-21Fredrik Hübinette (Hubbe)  static int in_gc = 0;
6930181996-02-25Fredrik Hübinette (Hubbe)  double tmp; INT32 tmp2;
c94c371996-03-28Fredrik Hübinette (Hubbe)  struct marker_chunk *m;
6930181996-02-25Fredrik Hübinette (Hubbe) 
890e5b1996-11-21Fredrik Hübinette (Hubbe)  if(in_gc) return; in_gc=1;
e78abd1996-11-21Fredrik Hübinette (Hubbe)  if(gc_evaluator_callback) { remove_callback(gc_evaluator_callback); gc_evaluator_callback=0; }
890e5b1996-11-21Fredrik Hübinette (Hubbe) 
6930181996-02-25Fredrik Hübinette (Hubbe)  tmp2=num_objects; #ifdef DEBUG if(t_flag) fprintf(stderr,"Garbage collecting ... ");
06983f1996-09-22Fredrik Hübinette (Hubbe)  if(num_objects < 0) fatal("Panic, less than zero objects!\n");
6930181996-02-25Fredrik Hübinette (Hubbe) #endif objects_alloced*=MULTIPLIER; objects_alloced += (double) num_allocs; objects_freed*=MULTIPLIER; objects_freed += (double) num_objects;
c94c371996-03-28Fredrik Hübinette (Hubbe)  /* init hash , hashsize will be a prime between num_objects/8 and * num_objects/4, this will assure that no re-hashing is needed. */ hashsize=my_log2(num_objects);
4a578f1997-01-27Fredrik Hübinette (Hubbe)  if(!d_flag) hashsize-=2;
c94c371996-03-28Fredrik Hübinette (Hubbe)  if(hashsize<0) hashsize=0; hashsize=hashprimes[hashsize]; hash=(struct marker **)xalloc(sizeof(struct marker **)*hashsize); MEMSET((char *)hash,0,sizeof(struct marker **)*hashsize); markers_left_in_chunk=0;
6930181996-02-25Fredrik Hübinette (Hubbe)  gc_check_all_arrays();
06983f1996-09-22Fredrik Hübinette (Hubbe)  gc_check_all_multisets();
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_check_all_mappings();
6930181996-02-25Fredrik Hübinette (Hubbe)  gc_check_all_programs(); gc_check_all_objects();
4a578f1997-01-27Fredrik Hübinette (Hubbe)  call_callback(& gc_callbacks, (void *)0);
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_mark_all_arrays();
06983f1996-09-22Fredrik Hübinette (Hubbe)  gc_mark_all_multisets();
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_mark_all_mappings(); gc_mark_all_programs(); gc_mark_all_objects();
4a578f1997-01-27Fredrik Hübinette (Hubbe)  if(d_flag) gc_mark_all_strings();
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_free_all_unreferenced_arrays();
06983f1996-09-22Fredrik Hübinette (Hubbe)  gc_free_all_unreferenced_multisets();
c94c371996-03-28Fredrik Hübinette (Hubbe)  gc_free_all_unreferenced_mappings(); gc_free_all_unreferenced_programs(); gc_free_all_unreferenced_objects(); /* Free hash table */ free((char *)hash);
9c6f7d1997-04-15Fredrik Hübinette (Hubbe)  while((m=chunk))
c94c371996-03-28Fredrik Hübinette (Hubbe)  { chunk=m->next; free((char *)m); }
06983f1996-09-22Fredrik Hübinette (Hubbe)  destruct_objects_to_destruct();
6930181996-02-25Fredrik Hübinette (Hubbe)  objects_freed -= (double) num_objects; tmp=(double)num_objects; tmp=tmp * GC_CONST/100.0 * (objects_alloced+1.0) / (objects_freed+1.0); if((int)tmp < alloc_threshold + num_allocs) { alloc_threshold=(int)tmp; }else{ alloc_threshold+=num_allocs; } if(alloc_threshold < MIN_ALLOC_THRESHOLD) alloc_threshold = MIN_ALLOC_THRESHOLD;
b95bef1996-03-29Fredrik Hübinette (Hubbe)  if(alloc_threshold > MAX_ALLOC_THRESHOLD) alloc_threshold = MAX_ALLOC_THRESHOLD;
6930181996-02-25Fredrik Hübinette (Hubbe)  num_allocs=0; #ifdef DEBUG if(t_flag) fprintf(stderr,"done (freed %ld of %ld objects).\n", (long)(tmp2-num_objects),(long)tmp2); #endif
a29e021996-10-15Fredrik Hübinette (Hubbe) 
bf45771996-12-05Fredrik Hübinette (Hubbe) #ifdef ALWAYS_GC
890e5b1996-11-21Fredrik Hübinette (Hubbe)  ADD_GC_CALLBACK(); #else
bf45771996-12-05Fredrik Hübinette (Hubbe)  if(d_flag > 3) ADD_GC_CALLBACK();
a29e021996-10-15Fredrik Hübinette (Hubbe) #endif
890e5b1996-11-21Fredrik Hübinette (Hubbe)  in_gc=0;
6930181996-02-25Fredrik Hübinette (Hubbe) }
c94c371996-03-28Fredrik Hübinette (Hubbe) #endif
6930181996-02-25Fredrik Hübinette (Hubbe)