From 60be3dc560d1bd61344c328ee6a939ec9cffa537 Mon Sep 17 00:00:00 2001 From: ko1 Date: Sun, 27 Jul 2008 05:59:32 +0000 Subject: * include/ruby/ruby.h: add a type T_DEFERRED. * gc.c: fix deferred finalizer system. finalize processes of T_DATA and T_FILE are executed after gc process. And fix to use BUILTIN_TYPE() instead of seeing flag. * thread.c, vm_core.h: add RUBY_VM_SET_FINALIZER_INTERRUPT() and check intterupt_flag at rb_thread_execute_interrupts(). * thread.c (mutex_mark): fix to mark next_mutex. * vm.c (rb_thread_mark): fix to mark keeping_mutexes. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@18231 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 15 +++++++ gc.c | 117 +++++++++++++++++++++++++++++++--------------------- include/ruby/ruby.h | 2 + thread.c | 16 +++++-- vm.c | 1 + vm_core.h | 3 +- 6 files changed, 103 insertions(+), 51 deletions(-) diff --git a/ChangeLog b/ChangeLog index bdf8e9942c..63b3b9f50d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +Sun Jul 27 14:48:37 2008 Koichi Sasada + + * include/ruby/ruby.h: add a type T_DEFERRED. + + * gc.c: fix deferred finalizer system. finalize processes of + T_DATA and T_FILE are executed after gc process. + And fix to use BUILTIN_TYPE() instead of seeing flag. + + * thread.c, vm_core.h: add RUBY_VM_SET_FINALIZER_INTERRUPT() + and check intterupt_flag at rb_thread_execute_interrupts(). + + * thread.c (mutex_mark): fix to mark next_mutex. + + * vm.c (rb_thread_mark): fix to mark keeping_mutexes. + Sun Jul 27 09:15:28 2008 Nobuyoshi Nakada * dln.h (dln_find_exe, dln_find_file): deprecated, use reentrant diff --git a/gc.c b/gc.c index c7edd8e773..f7f92d644b 100644 --- a/gc.c +++ b/gc.c @@ -578,7 +578,6 @@ assign_heap_slot(rb_objspace_t *objspace) objs--; } } - lo = 0; hi = heaps_used; @@ -1081,7 +1080,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) rb_mark_generic_ivar(ptr); } - switch (obj->as.basic.flags & T_MASK) { + switch (BUILTIN_TYPE(obj)) { case T_NIL: case T_FIXNUM: rb_bug("rb_gc_mark() called for broken object"); @@ -1224,7 +1223,7 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) } gc_mark(objspace, obj->as.basic.klass, lev); - switch (obj->as.basic.flags & T_MASK) { + switch (BUILTIN_TYPE(obj)) { case T_ICLASS: case T_CLASS: case T_MODULE: @@ -1316,18 +1315,27 @@ gc_mark_children(rb_objspace_t *objspace, VALUE ptr, int lev) } break; - case T_UNDEF: + case T_DEFERRED: break; default: rb_bug("rb_gc_mark(): unknown data type 0x%lx(%p) %s", - obj->as.basic.flags & T_MASK, obj, + BUILTIN_TYPE(obj), obj, is_pointer_to_heap(objspace, obj) ? "corrupted object" : "non object"); } } static int obj_free(rb_objspace_t *, VALUE); +static inline void +add_freelist(rb_objspace_t *objspace, RVALUE *p) +{ + VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); + p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; +} + static void finalize_list(rb_objspace_t *objspace, RVALUE *p) { @@ -1335,10 +1343,7 @@ finalize_list(rb_objspace_t *objspace, RVALUE *p) RVALUE *tmp = p->as.free.next; run_final(objspace, (VALUE)p); if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */ - VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; + add_freelist(objspace, p); } p = tmp; } @@ -1388,6 +1393,7 @@ gc_sweep(rb_objspace_t *objspace) 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; @@ -1400,25 +1406,28 @@ gc_sweep(rb_objspace_t *objspace) int n = 0; RVALUE *free = freelist; RVALUE *final = final_list; + int deferred; p = heaps[i].slot; pend = p + heaps[i].limit; while (p < pend) { if (!(p->as.basic.flags & FL_MARK)) { - if (p->as.basic.flags && obj_free(objspace, (VALUE)p) || - need_call_final && FL_TEST(p, FL_FINALIZE)) { - p->as.free.flags |= FL_MARK; /* remain marked */ + 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_DEFERRED; + RDATA(p)->dfree = 0; + } + p->as.free.flags |= FL_MARK; p->as.free.next = final_list; final_list = p; } else { - VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; + add_freelist(objspace, p); } n++; } - else if (RBASIC(p)->flags == FL_MARK) { + else if (BUILTIN_TYPE(p) == T_DEFERRED) { /* objects to be finalized */ /* do nothing remain marked */ } @@ -1455,25 +1464,24 @@ gc_sweep(rb_objspace_t *objspace) /* clear finalization list */ if (final_list) { deferred_final_list = final_list; - return; + RUBY_VM_SET_FINALIZER_INTERRUPT(GET_THREAD()); + } + else{ + free_unused_heaps(objspace); } - free_unused_heaps(objspace); } void rb_gc_force_recycle(VALUE p) { rb_objspace_t *objspace = &rb_objspace; - VALGRIND_MAKE_MEM_UNDEFINED((void*)p, sizeof(RVALUE)); - RANY(p)->as.free.flags = 0; - RANY(p)->as.free.next = freelist; - freelist = RANY(p); + add_freelist(objspace, (RVALUE *)p); } static int obj_free(rb_objspace_t *objspace, VALUE obj) { - switch (RANY(obj)->as.basic.flags & T_MASK) { + switch (BUILTIN_TYPE(obj)) { case T_NIL: case T_FIXNUM: case T_TRUE: @@ -1486,7 +1494,7 @@ obj_free(rb_objspace_t *objspace, VALUE obj) rb_free_generic_ivar((VALUE)obj); } - switch (RANY(obj)->as.basic.flags & T_MASK) { + switch (BUILTIN_TYPE(obj)) { case T_OBJECT: if (!(RANY(obj)->as.basic.flags & ROBJECT_EMBED) && RANY(obj)->as.object.as.heap.ivptr) { @@ -1527,9 +1535,14 @@ obj_free(rb_objspace_t *objspace, VALUE obj) xfree(DATA_PTR(obj)); } else if (RANY(obj)->as.data.dfree) { - RANY(obj)->as.basic.flags &= ~T_MASK; - RANY(obj)->as.basic.flags |= T_UNDEF; - return 1; + if (1) { + RANY(obj)->as.basic.flags &= ~T_MASK; + RANY(obj)->as.basic.flags |= T_DEFERRED; + return 1; + } + else { + (*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); + } } } break; @@ -1545,11 +1558,16 @@ obj_free(rb_objspace_t *objspace, VALUE obj) case T_FILE: if (RANY(obj)->as.file.fptr) { rb_io_t *fptr = RANY(obj)->as.file.fptr; - RANY(obj)->as.basic.flags &= ~T_MASK; - RANY(obj)->as.basic.flags |= T_UNDEF; - RDATA(obj)->dfree = (void (*)(void*))rb_io_fptr_finalize; - RDATA(obj)->data = fptr; - return 1; + if (1) { + RANY(obj)->as.basic.flags &= ~T_MASK; + RANY(obj)->as.basic.flags |= T_DEFERRED; + RDATA(obj)->dfree = (void (*)(void*))rb_io_fptr_finalize; + RDATA(obj)->data = fptr; + return 1; + } + else { + rb_io_fptr_finalize(fptr); + } } break; case T_RATIONAL: @@ -1587,14 +1605,14 @@ obj_free(rb_objspace_t *objspace, VALUE obj) } break; - case T_UNDEF: + case T_DEFERRED: break; default: rb_bug("gc_sweep(): unknown data type 0x%lx(%p)", - RANY(obj)->as.basic.flags & T_MASK, (void*)obj); + BUILTIN_TYPE(obj), (void*)obj); } - RANY(obj)->as.basic.flags &= ~T_MASK; + return 0; } @@ -1867,7 +1885,7 @@ os_obj_of(rb_objspace_t *objspace, VALUE of) case T_NONE: case T_ICLASS: case T_NODE: - case T_UNDEF: + case T_DEFERRED: continue; case T_CLASS: if (FL_TEST(p, FL_SINGLETON)) continue; @@ -2018,17 +2036,19 @@ static void run_final(rb_objspace_t *objspace, VALUE obj) { long i; - int status, critical_save = rb_thread_critical; + int status; VALUE args[3], table, objid; objid = rb_obj_id(obj); /* make obj into id */ - rb_thread_critical = Qtrue; - if ((RANY(obj)->as.basic.flags & T_MASK) == T_UNDEF) { - (*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); + + if (RDATA(obj)->dfree) { + (*RDATA(obj)->dfree)(DATA_PTR(obj)); } - args[1] = 0; - args[2] = (VALUE)rb_safe_level(); - if (finalizer_table && st_delete(finalizer_table, (st_data_t*)&obj, &table)) { + + if (finalizer_table && + st_delete(finalizer_table, (st_data_t*)&obj, &table)) { + args[1] = 0; + args[2] = (VALUE)rb_safe_level(); if (!args[1] && RARRAY_LEN(table) > 0) { args[1] = rb_obj_freeze(rb_ary_new3(1, objid)); } @@ -2039,15 +2059,14 @@ run_final(rb_objspace_t *objspace, VALUE obj) rb_protect(run_single_final, (VALUE)args, &status); } } - rb_thread_critical = critical_save; } static void gc_finalize_deferred(rb_objspace_t *objspace) { RVALUE *p = deferred_final_list; - deferred_final_list = 0; + if (p) { finalize_list(objspace, p); } @@ -2065,7 +2084,10 @@ chain_finalized_object(st_data_t key, st_data_t val, st_data_t arg) { RVALUE *p = (RVALUE *)key, **final_list = (RVALUE **)arg; if (p->as.basic.flags & FL_FINALIZE) { - p->as.free.flags = FL_MARK; /* remain marked */ + if (BUILTIN_TYPE(p) != T_DEFERRED) { + p->as.free.flags = FL_MARK | T_DEFERRED; /* remain marked */ + RDATA(p)->dfree = 0; + } p->as.free.next = *final_list; *final_list = p; } @@ -2345,6 +2367,7 @@ count_objects(int argc, VALUE *argv, VALUE os) COUNT_TYPE(T_UNDEF); COUNT_TYPE(T_NODE); COUNT_TYPE(T_ICLASS); + COUNT_TYPE(T_DEFERRED); #undef COUNT_TYPE default: type = INT2NUM(i); break; } diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index eb3d282917..db3253da42 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -302,6 +302,7 @@ enum ruby_value_type { RUBY_T_UNDEF = 0x1b, RUBY_T_NODE = 0x1c, RUBY_T_ICLASS = 0x1d, + RUBY_T_DEFERRED = 0x1e, RUBY_T_MASK = 0x1f }; @@ -330,6 +331,7 @@ enum ruby_value_type { #define T_COMPLEX RUBY_T_COMPLEX #define T_UNDEF RUBY_T_UNDEF #define T_NODE RUBY_T_NODE +#define T_DEFERRED RUBY_T_DEFERRED #define T_MASK RUBY_T_MASK #define BUILTIN_TYPE(x) (((struct RBasic*)(x))->flags & T_MASK) diff --git a/thread.c b/thread.c index 88f5b5225e..2279c4491e 100644 --- a/thread.c +++ b/thread.c @@ -935,8 +935,12 @@ void rb_thread_execute_interrupts(rb_thread_t *th) { if (th->raised_flag) return; + while (th->interrupt_flag) { enum rb_thread_status status = th->status; + int timer_interrupt = th->interrupt_flag & 0x01; + int finalizer_interrupt = th->interrupt_flag & 0x04; + th->status = THREAD_RUNNABLE; th->interrupt_flag = 0; @@ -963,10 +967,15 @@ rb_thread_execute_interrupts(rb_thread_t *th) } th->status = status; - /* thread pass */ - rb_thread_schedule(); + if (finalizer_interrupt) { + rb_gc_finalize_deferred(); + } + + if (timer_interrupt) { + EXEC_EVENT_HOOK(th, RUBY_EVENT_SWITCH, th->cfp->self, 0, 0); + rb_thread_schedule(); + } } - EXEC_EVENT_HOOK(th, RUBY_EVENT_SWITCH, th->cfp->self, 0, 0); } @@ -2494,6 +2503,7 @@ mutex_mark(void *ptr) { if (ptr) { mutex_t *mutex = ptr; + rb_gc_mark(mutex->next_mutex); if (mutex->th) { rb_gc_mark(mutex->th->self); } diff --git a/vm.c b/vm.c index 5778cfe42a..5cc4658290 100644 --- a/vm.c +++ b/vm.c @@ -1551,6 +1551,7 @@ rb_thread_mark(void *ptr) RUBY_MARK_UNLESS_NULL(th->last_status); RUBY_MARK_UNLESS_NULL(th->locking_mutex); + RUBY_MARK_UNLESS_NULL(th->keeping_mutexes); rb_mark_tbl(th->local_storage); diff --git a/vm_core.h b/vm_core.h index 48fde8d8d9..7ac6bb1ceb 100644 --- a/vm_core.h +++ b/vm_core.h @@ -690,12 +690,13 @@ extern rb_vm_t *ruby_current_vm; #define RUBY_VM_SET_INTERRUPT(th) ((th)->interrupt_flag |= 0x02) #define RUBY_VM_SET_TIMER_INTERRUPT(th) ((th)->interrupt_flag |= 0x01) +#define RUBY_VM_SET_FINALIZER_INTERRUPT(th) ((th)->interrupt_flag |= 0x04) #define RUBY_VM_INTERRUPTED(th) ((th)->interrupt_flag & 0x02) void rb_thread_execute_interrupts(rb_thread_t *); #define RUBY_VM_CHECK_INTS_TH(th) do { \ - if(th->interrupt_flag){ \ + if (th->interrupt_flag) { \ /* TODO: trap something event */ \ rb_thread_execute_interrupts(th); \ } \ -- cgit v1.2.3