From: Nobuyoshi Nakada Date: 2008-07-20T08:27:35+09:00 Subject: [ruby-dev:35594] Re: [Bug:1.9] context switch may occur during freeing io なかだです。 At Fri, 18 Jul 2008 19:47:28 +0900, Yusuke ENDOH wrote in [ruby-dev:35578]: > 原因は、T_FILE が GC されるとき > > fptr_finalize > -> io_fflush > -> rb_thread_fd_writable > -> rb_thread_wait_fd_rw > -> do_select > -> BLOCKING_REGION > > と呼び出しが進んで、GC 中に他のスレッドが動き出してしまうためです。 T_DATAのdfreeとfptr_finalizeはdeferredに回しましょうか。 > この問題がなかったとしても、fptr_finalize で io_fflush するのは > ブロックする可能性があってまずい気がします。どうしたもんでしょう。 こっちはどうしましょうかねぇ。 Index: gc.c =================================================================== --- gc.c (revision 18132) +++ gc.c (working copy) @@ -1324,5 +1324,5 @@ gc_mark_children(rb_objspace_t *objspace } -static void obj_free(rb_objspace_t *, VALUE); +static int obj_free(rb_objspace_t *, VALUE); static void @@ -1402,9 +1402,7 @@ gc_sweep(rb_objspace_t *objspace) while (p < pend) { if (!(p->as.basic.flags & FL_MARK)) { - if (p->as.basic.flags) { - obj_free(objspace, (VALUE)p); - } - if (need_call_final && FL_TEST(p, FL_FINALIZE)) { - p->as.free.flags = FL_MARK; /* remain marked */ + 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 */ p->as.free.next = final_list; final_list = p; @@ -1470,5 +1468,5 @@ rb_gc_force_recycle(VALUE p) } -static void +static int obj_free(rb_objspace_t *objspace, VALUE obj) { @@ -1527,5 +1525,5 @@ obj_free(rb_objspace_t *objspace, VALUE } else if (RANY(obj)->as.data.dfree) { - (*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); + return 1; } } @@ -1542,5 +1540,5 @@ obj_free(rb_objspace_t *objspace, VALUE case T_FILE: if (RANY(obj)->as.file.fptr) { - rb_io_fptr_finalize(RANY(obj)->as.file.fptr); + return 1; } break; @@ -1571,5 +1569,5 @@ obj_free(rb_objspace_t *objspace, VALUE break; } - return; /* no need to free iv_tbl */ + break; /* no need to free iv_tbl */ case T_STRUCT: @@ -1584,4 +1582,6 @@ obj_free(rb_objspace_t *objspace, VALUE RANY(obj)->as.basic.flags & T_MASK, (void*)obj); } + RANY(obj)->as.basic.flags &= ~T_MASK; + return 0; } @@ -2010,4 +2010,12 @@ run_final(rb_objspace_t *objspace, VALUE objid = rb_obj_id(obj); /* make obj into id */ rb_thread_critical = Qtrue; + switch (RANY(obj)->as.basic.flags & T_MASK) { + case T_DATA: + (*RANY(obj)->as.data.dfree)(DATA_PTR(obj)); + break; + case T_FILE: + rb_io_fptr_finalize(RANY(obj)->as.file.fptr); + break; + } args[1] = 0; args[2] = (VALUE)rb_safe_level(); -- --- 僕の前にBugはない。 --- 僕の後ろにBugはできる。 中田 伸悦