From: wanabe Date: 2009-06-02T20:41:02+09:00 Subject: [ruby-dev:38562] Re: [Bug #595] Fiber ignores ensure clause ワナベと申します。 かなり前のチケットですが、題名の件についてパッチを書きました。 もしまだどなたもパッチを書かれていないようならご検討ください。 Index: thread.c =================================================================== --- thread.c (リビジョン 23617) +++ thread.c (作業コピー) @@ -293,6 +293,8 @@ static void rb_mutex_unlock_all(mutex_t *mutex, rb_thread_t *th); +void rb_fiber_terminate_all(rb_thread_t *th); + void rb_thread_terminate_all(void) { @@ -310,6 +312,7 @@ thread_debug("rb_thread_terminate_all (main thread: %p)\n", (void *)th); st_foreach(vm->living_threads, terminate_i, (st_data_t)th); + rb_fiber_terminate_all(th); while (!rb_thread_alone()) { PUSH_TAG(); @@ -1210,6 +1213,7 @@ thread_debug("rb_thread_execute_interrupts: %ld\n", err); if (err == eKillSignal || err == eTerminateSignal) { + rb_fiber_terminate_all(th); th->errinfo = INT2FIX(TAG_FATAL); TH_JUMP_TAG(th, TAG_FATAL); } Index: cont.c =================================================================== --- cont.c (リビジョン 23617) +++ cont.c (作業コピー) @@ -534,6 +534,7 @@ case 0: return Qnil; case 1: + case -1: return argv[0]; default: return rb_ary_new4(argc, argv); @@ -946,6 +947,36 @@ return fib->status != TERMINATED ? Qtrue : Qfalse; } +static VALUE +terminate_all_i(VALUE fibval) +{ + if (rb_fiber_alive_p(fibval)) { + VALUE value = rb_exc_new2(rb_eSystemExit, "terminate"); + return fiber_switch(fibval, -1, &value, 0); + } +} + +void +rb_fiber_terminate_all(rb_thread_t *th) +{ + VALUE fibval; + rb_fiber_t *fib, *root_fib; + rb_thread_t *_th = GET_THREAD(); + + rb_thread_set_current(th); + fibval = th->root_fiber; + if (!RTEST(fibval)) return; + GetFiberPtr(fibval, root_fib); + + fib = root_fib->prev_fiber; + while (fib != root_fib) { + rb_rescue2(terminate_all_i, fib->cont.self, + 0, 0, rb_eSystemExit); + fib = fib->prev_fiber; + } + rb_thread_set_current(_th); +} + /* * call-seq: * fiber.resume(args, ...) -> obj -- ワナベ