From f3a4870b42fcbaefd051b3754738a869b87098e2 Mon Sep 17 00:00:00 2001 From: shyouhei Date: Sun, 11 Jan 2009 15:24:53 +0000 Subject: merge revision(s) 18392: * gc.c (gc_sweep, obj_free, run_final): defer finalizers of IO and Data. [ruby-dev:35578] * gc.c (rb_gc_call_finalizer_at_exit): self-referencing finalizers cannot be invoked. [ruby-dev:35681] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@21435 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- gc.c | 108 +++++++++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 38 deletions(-) (limited to 'gc.c') diff --git a/gc.c b/gc.c index b41df745a5..445041aa92 100644 --- a/gc.c +++ b/gc.c @@ -1052,7 +1052,16 @@ gc_mark_children(ptr, lev) } } -static void obj_free _((VALUE)); +static int obj_free _((VALUE)); + +static inline void +add_freelist(p) + RVALUE *p; +{ + p->as.free.flags = 0; + p->as.free.next = freelist; + freelist = p; +} static void finalize_list(p) @@ -1062,9 +1071,7 @@ finalize_list(p) RVALUE *tmp = p->as.free.next; run_final((VALUE)p); if (!FL_TEST(p, FL_SINGLETON)) { /* not freeing page */ - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; + add_freelist(p); } p = tmp; } @@ -1089,6 +1096,8 @@ free_unused_heaps() } } +#define T_DEFERRED 0x3a + void rb_gc_abort_threads(void); static void @@ -1132,26 +1141,28 @@ gc_sweep() 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((VALUE)p); - } - if (need_call_final && FL_TEST(p, FL_FINALIZE)) { - p->as.free.flags = FL_MARK; /* remain marked */ + if (p->as.basic.flags && + ((deferred = obj_free((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 { - p->as.free.flags = 0; - p->as.free.next = freelist; - freelist = p; + add_freelist(p); } n++; } - else if (RBASIC(p)->flags == FL_MARK) { + else if (BUILTIN_TYPE(p) == T_DEFERRED) { /* objects to be finalized */ /* do nothing remain marked */ } @@ -1197,16 +1208,21 @@ void rb_gc_force_recycle(p) VALUE p; { - RANY(p)->as.free.flags = 0; - RANY(p)->as.free.next = freelist; - freelist = RANY(p); + add_freelist(p); } -static void +static inline void +make_deferred(p) + RVALUE *p; +{ + p->as.basic.flags = (p->as.basic.flags & ~T_MASK) | T_DEFERRED; +} + +static int obj_free(obj) VALUE obj; { - switch (RANY(obj)->as.basic.flags & T_MASK) { + switch (BUILTIN_TYPE(obj)) { case T_NIL: case T_FIXNUM: case T_TRUE: @@ -1219,7 +1235,7 @@ obj_free(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.object.iv_tbl) { st_free_table(RANY(obj)->as.object.iv_tbl); @@ -1262,7 +1278,8 @@ obj_free(obj) RUBY_CRITICAL(free(DATA_PTR(obj))); } else if (RANY(obj)->as.data.dfree) { - (*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); + make_deferred(RANY(obj)); + return 1; } } break; @@ -1274,8 +1291,11 @@ obj_free(obj) break; case T_FILE: if (RANY(obj)->as.file.fptr) { - rb_io_fptr_finalize(RANY(obj)->as.file.fptr); - RUBY_CRITICAL(free(RANY(obj)->as.file.fptr)); + struct rb_io_t *fptr = RANY(obj)->as.file.fptr; + make_deferred(RANY(obj)); + RDATA(obj)->dfree = (void (*)(void*))rb_io_fptr_finalize; + RDATA(obj)->data = fptr; + return 1; } break; case T_ICLASS: @@ -1303,7 +1323,7 @@ obj_free(obj) RUBY_CRITICAL(free(RANY(obj)->as.node.u1.node)); break; } - return; /* no need to free iv_tbl */ + break; /* no need to free iv_tbl */ case T_SCOPE: if (RANY(obj)->as.scope.local_vars && @@ -1326,6 +1346,8 @@ obj_free(obj) rb_bug("gc_sweep(): unknown data type 0x%lx(0x%lx)", RANY(obj)->as.basic.flags & T_MASK, obj); } + + return 0; } void @@ -1671,6 +1693,7 @@ os_obj_of(of) case T_VARMAP: case T_SCOPE: case T_NODE: + case T_DEFERRED: continue; case T_CLASS: if (FL_TEST(p, FL_SINGLETON)) continue; @@ -1918,6 +1941,21 @@ rb_gc_finalize_deferred() } } +static int +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|FL_MARK)) == FL_FINALIZE) { + 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; + } + return ST_CONTINUE; +} + void rb_gc_call_finalizer_at_exit() { @@ -1926,20 +1964,14 @@ rb_gc_call_finalizer_at_exit() /* run finalizers */ if (need_call_final) { - p = deferred_final_list; - deferred_final_list = 0; - finalize_list(p); - for (i = 0; i < heaps_used; i++) { - p = heaps[i].slot; pend = p + heaps[i].limit; - while (p < pend) { - if (FL_TEST(p, FL_FINALIZE)) { - FL_UNSET(p, FL_FINALIZE); - p->as.basic.klass = 0; - run_final((VALUE)p); - } - p++; - } - } + do { + p = deferred_final_list; + deferred_final_list = 0; + finalize_list(p); + mark_tbl(finalizer_table, 0); + st_foreach(finalizer_table, chain_finalized_object, + (st_data_t)&deferred_final_list); + } while (deferred_final_list); } /* run data object's finalizers */ for (i = 0; i < heaps_used; i++) { @@ -2000,7 +2032,7 @@ id2ref(obj, objid) } if (!is_pointer_to_heap((void *)ptr)|| - (type = BUILTIN_TYPE(ptr)) >= T_BLKTAG || type == T_ICLASS) { + (type = BUILTIN_TYPE(ptr)) > T_SYMBOL || type == T_ICLASS) { rb_raise(rb_eRangeError, "0x%lx is not id value", p0); } if (BUILTIN_TYPE(ptr) == 0 || RBASIC(ptr)->klass == 0) { -- cgit v1.2.3