Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Index: gc.c
- ===================================================================
- --- gc.c (revision 19984)
- +++ gc.c (working copy)
- @@ -281,7 +281,7 @@
- int limit;
- };
- -#define HEAP_MIN_SLOTS 10000
- +#define HEAP_MIN_SLOTS 100000
- #define FREE_MIN 4096
- struct gc_list {
- @@ -395,11 +395,45 @@
- /*#define HEAP_SIZE 0x800 */
- #define HEAP_OBJ_LIMIT (HEAP_SIZE / sizeof(struct RVALUE))
- +#define GC_NOTIFY 1
- extern st_table *rb_class_tbl;
- int ruby_disable_gc_stress = 0;
- +
- +
- +
- +#include <sys/types.h>
- +#include <sys/mman.h>
- +#include <fcntl.h>
- +
- +#define TO_ADD_TO_FREE_LIST_SIZE 4000000
- +#define HEAPS_TO_FREE_SIZE 3000
- +enum CHILD_STATE { idle, child_in_gc, gc_just_finished, gc_wait_for_child_next_pass};
- +typedef struct
- +{
- + enum CHILD_STATE child_state;
- + RVALUE* to_add_to_free_list[TO_ADD_TO_FREE_LIST_SIZE];
- + struct heaps_slot* heaps_to_free[HEAPS_TO_FREE_SIZE];
- +
- +} shared_stuff_t, *shared_stuff_p;
- +
- +shared_stuff_p shared_area = 0;
- +int child_gc_pid = 0;
- +
- +/* TODO wait for the child pid on exit */
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- +
- static void run_final(rb_objspace_t *objspace, VALUE obj);
- static int garbage_collect(rb_objspace_t *objspace);
- @@ -546,6 +580,7 @@
- if ((ruby_gc_stress && !ruby_disable_gc_stress) ||
- (malloc_increase+size) > malloc_limit) {
- garbage_collect(objspace);
- + malloc_increase = 0;
- }
- mem = malloc(size);
- if (!mem) {
- @@ -889,9 +924,11 @@
- VALUE obj;
- if ((ruby_gc_stress && !ruby_disable_gc_stress) || !freelist) {
- - if (!heaps_increment(objspace) && !garbage_collect(objspace)) {
- - during_gc = 0;
- - rb_memerror();
- + if (!heaps_increment(objspace)) {
- + if(!garbage_collect(objspace)) {
- + during_gc = 0;
- + rb_memerror();
- + }
- }
- }
- @@ -1621,95 +1658,59 @@
- static void
- gc_sweep(rb_objspace_t *objspace)
- {
- - RVALUE *p, *pend, *final_list;
- - size_t freed = 0;
- - size_t i;
- - size_t live = 0, free_min = 0, do_heap_free = 0;
- + RVALUE *p, *pend;
- + size_t i; /* TODO were there more here we needed to worry about? */
- + size_t live = 0;
- + int where_at_in_to_add_to_free_list = 0;
- + int heaps_to_free_where_at = 0;
- + int total_added_to_to_free_list;
- - do_heap_free = (heaps_used * HEAP_OBJ_LIMIT) * 0.65;
- - free_min = (heaps_used * HEAP_OBJ_LIMIT) * 0.2;
- -
- - if (free_min < FREE_MIN) {
- - do_heap_free = heaps_used * HEAP_OBJ_LIMIT;
- - free_min = FREE_MIN;
- - }
- -
- - freelist = 0;
- - final_list = deferred_final_list;
- - deferred_final_list = 0;
- for (i = 0; i < heaps_used; i++) {
- - int free_num = 0, final_num = 0;
- - RVALUE *free = freelist;
- - RVALUE *final = final_list;
- - int deferred;
- + int free_num = 0;
- p = heaps[i].slot; pend = p + heaps[i].limit;
- +
- + total_added_to_to_free_list = 0;
- while (p < pend) {
- if (!(p->as.basic.flags & FL_MARK)) {
- - if (p->as.basic.flags &&
- - ((deferred = obj_free(objspace, (VALUE)p)) ||
- - ((FL_TEST(p, FL_FINALIZE)) && need_call_final))) {
- - if (!deferred) {
- - p->as.free.flags = T_ZOMBIE;
- - RDATA(p)->dfree = 0;
- + if (p->as.basic.flags) {
- + free_num++; /* for now only count those that we honestly free this time */
- + total_added_to_to_free_list++;
- + if(where_at_in_to_add_to_free_list < TO_ADD_TO_FREE_LIST_SIZE - 2)
- + {
- + shared_area->to_add_to_free_list[where_at_in_to_add_to_free_list++] = p;
- }
- - p->as.free.flags |= FL_MARK;
- - p->as.free.next = final_list;
- - final_list = p;
- - final_num++;
- +
- }
- - else {
- - add_freelist(objspace, p);
- - free_num++;
- - }
- }
- - else if (BUILTIN_TYPE(p) == T_ZOMBIE) {
- + else if (BUILTIN_TYPE(p) == T_ZOMBIE) {
- /* objects to be finalized */
- /* do nothing remain marked */
- }
- else {
- - RBASIC(p)->flags &= ~FL_MARK;
- - live++;
- + //live++;
- }
- p++;
- }
- - if (final_num + free_num == heaps[i].limit && freed > do_heap_free) {
- - RVALUE *pp;
- +
- + if (free_num == heaps[i].limit) {
- + if(heaps_to_free_where_at < (HEAPS_TO_FREE_SIZE - 2))
- + {
- + /* TODO do not list them on the to be freed list or they will be added to the freelist when collected */
- + //printf("marking heap to be totally freed %d\n", heaps[i].membase); /* this has the right number*/
- + shared_area->heaps_to_free[heaps_to_free_where_at++] = heaps[i].membase; /* TODO do we still add these to the to free list though? */
- + }
- + }
- + } /* foreach heap */
- - for (pp = final_list; pp != final; pp = pp->as.free.next) {
- - RDATA(pp)->dmark = (void *)&heaps[i];
- - pp->as.free.flags |= FL_SINGLETON; /* freeing page mark */
- - }
- - heaps[i].limit = final_num;
- + if(where_at_in_to_add_to_free_list == TO_ADD_TO_FREE_LIST_SIZE - 2)
- + if (GC_NOTIFY) printf("PROBABLY WASTED free list size wanted %d, size is %d\n", where_at_in_to_add_to_free_list, TO_ADD_TO_FREE_LIST_SIZE);
- - freelist = free; /* cancel this page from freelist */
- - }
- - else {
- - freed += free_num;
- - }
- - }
- - GC_PROF_SET_MALLOC_INFO;
- - if (malloc_increase > malloc_limit) {
- - malloc_limit += (malloc_increase - malloc_limit) * (double)live / (live + freed);
- - if (malloc_limit < GC_MALLOC_LIMIT) malloc_limit = GC_MALLOC_LIMIT;
- - }
- - malloc_increase = 0;
- - if (freed < free_min) {
- - set_heaps_increment(objspace);
- - heaps_increment(objspace);
- - }
- - during_gc = 0;
- -
- - /* clear finalization list */
- - if (final_list) {
- - GC_PROF_SET_HEAP_INFO;
- - deferred_final_list = final_list;
- - RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD());
- - }
- - else{
- - free_unused_heaps(objspace);
- - GC_PROF_SET_HEAP_INFO;
- - }
- + /* add some null terminators */
- + shared_area->to_add_to_free_list[where_at_in_to_add_to_free_list] = 0;
- + shared_area->heaps_to_free[heaps_to_free_where_at] = 0;
- +
- + return;
- }
- void
- @@ -1855,7 +1856,6 @@
- return 0;
- }
- -#define GC_NOTIFY 0
- void rb_vm_mark(void *ptr);
- @@ -1902,9 +1902,178 @@
- void rb_gc_mark_encodings(void);
- +
- +static void
- +gc_free_from_child()
- +{
- + RVALUE *p;
- + int where_at_in_to_add_to_free_list = 0;
- + int deferred;
- + rb_objspace_t *objspace = &rb_objspace;
- + p = shared_area->to_add_to_free_list[0];
- + while(p != 0) {
- + if( (deferred = obj_free(objspace, (VALUE)p)) ||
- + ((FL_TEST(p, FL_FINALIZE)) && need_call_final))
- + {
- + if (!deferred) {
- + p->as.free.flags = T_ZOMBIE;
- + RDATA(p)->dfree = 0;
- + }
- + p->as.free.flags |= FL_MARK;
- + p->as.free.next = deferred_final_list;
- + deferred_final_list = p;
- + }else
- + add_freelist(objspace, (RVALUE *)p);
- +
- + p = shared_area->to_add_to_free_list[++where_at_in_to_add_to_free_list];
- + }
- +
- + /* free heaps -- TODO
- + if(shared_area->heaps_to_free[0])
- + {
- + struct heaps_slot *a = shared_area->heaps_to_free[0];
- + int here = 0;
- + struct heaps_slot *p2 = shared_area->heaps_to_free[here];
- + while(p2)
- + {
- + p2 = shared_area->heaps_to_free[++here];
- + //p2->limit = 0;
- + }
- + //free_unused_heaps(objspace);
- + } */
- +
- +}
- +
- +static void init_shared_memory() {
- +#ifndef _DARWIN_C_SOURCE
- + int fd;
- +#endif
- + if( child_gc_pid) // todo take out
- + {
- + printf("ERROR CHILD IS %d -- which means it was initialized twice! unexpected\n", child_gc_pid);
- + _exit(EXIT_FAILURE);
- + }
- +
- +#ifdef _DARWIN_C_SOURCE
- + shared_area=(shared_stuff_p)mmap(0,
- + sizeof(shared_stuff_t),
- + PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANON,
- + -1,
- + 0
- + );
- +#else
- + fd=open("/dev/zero",
- + O_RDWR
- + );
- +
- + if(fd==-1)
- + {
- + printf("unable to get file handle for attempted shared memory--exiting!\n");
- + _exit(EXIT_FAILURE);
- + }
- +
- + shared_area=(shared_stuff_p)mmap(0,
- + sizeof(shared_stuff_t),
- + PROT_READ|PROT_WRITE,MAP_SHARED,
- + fd,
- + 0
- + );
- +#endif
- +
- + if(shared_area==(shared_stuff_p)-1)
- + {
- + printf("shared memory allocation failure! %s\n", strerror(errno));
- + _exit(EXIT_FAILURE);
- + }
- + shared_area->child_state = idle;
- +}
- +
- static int
- garbage_collect(rb_objspace_t *objspace)
- {
- + pid_t w;
- + int status;
- +
- + if(shared_area==0){
- + init_shared_memory();
- + }
- +
- + int saved_child_state = shared_area->child_state;
- + if (dont_gc || during_gc || (saved_child_state == child_in_gc)) {
- +
- + // we should add if we're dont_gc or during_gc and !freelist, else wait for child
- + if(!freelist && (dont_gc || during_gc))
- + {
- + set_heaps_increment(objspace);
- + heaps_increment(objspace);
- + return Qtrue;
- + } else
- + {
- + // we should wait - cause waitpid to be called below
- + saved_child_state = gc_wait_for_child_next_pass;
- + }
- + }
- +
- +
- + if(saved_child_state == gc_just_finished || saved_child_state == gc_wait_for_child_next_pass)
- + {
- + during_gc++;
- + if(GC_NOTIFY)
- + if(saved_child_state == gc_just_finished)
- + printf("receiving WELL a child collecting thread\n");
- + else
- + printf("receiving POORLY a child collecting thread \n");
- + // reap child process
- + w = waitpid(child_gc_pid, &status, 0);
- + child_gc_pid = 0;
- + if (w == -1) { perror("waitpid"); exit(EXIT_FAILURE); }
- + gc_free_from_child();
- + if (!freelist) {
- + // our collecting from child was unsuccessful
- + if (!heaps_increment(objspace)) {
- + set_heaps_increment(objspace);
- + heaps_increment(objspace);
- + }
- +
- + }
- + shared_area->child_state = idle;
- + during_gc = 0;
- + return Qtrue;
- + }
- +
- +
- + if(shared_area->child_state == child_in_gc)
- + {
- + printf("attempted to start two children on accident: bug\n");
- + raise(SIGTERM);
- + }
- +
- + /* now the case of there was no child running - start the child */
- + if (GC_NOTIFY) fflush(stdout);
- + if(child_gc_pid)
- + {
- + printf("err -- looks like child exists already\n");
- + raise(SIGTERM);
- + }
- + shared_area->child_state = child_in_gc;
- + int childs_pid = fork();
- + if(childs_pid != 0)
- + {
- + // parent:
- + child_gc_pid = childs_pid;
- + if (!freelist) {
- + if (!heaps_increment(objspace)) {
- + /* At this point we can either add more [and possibly grow forever] or
- + we can call GC again and wait on our newly created child thread */
- + return garbage_collect(objspace);
- + }
- +
- + }
- + return Qtrue;
- +
- + }
- +
- + // child:
- struct gc_list *list;
- rb_thread_t *th = GET_THREAD();
- INIT_GC_PROF_PARAMS;
- @@ -1915,15 +2084,6 @@
- return Qfalse;
- }
- - if (dont_gc || during_gc) {
- - if (!freelist) {
- - if (!heaps_increment(objspace)) {
- - set_heaps_increment(objspace);
- - heaps_increment(objspace);
- - }
- - }
- - return Qtrue;
- - }
- during_gc++;
- objspace->count++;
- @@ -1976,7 +2136,10 @@
- GC_PROF_TIMER_STOP;
- if (GC_NOTIFY) printf("end garbage_collect()\n");
- - return Qtrue;
- +
- + shared_area->child_state = gc_just_finished;
- + _exit(EXIT_SUCCESS);
- + return Qtrue; // we never get here
- }
- int
- @@ -2376,6 +2539,8 @@
- rb_gc(void)
- {
- rb_objspace_t *objspace = &rb_objspace;
- + if(shared_area && (shared_area->child_state == child_in_gc))
- + shared_area->child_state = gc_wait_for_child_next_pass; // allow two calls to GC.start to force a GC
- garbage_collect(objspace);
- gc_finalize_deferred(objspace);
- }
Add Comment
Please, Sign In to add comment