ruby-changes:50866
From: ko1 <ko1@a...>
Date: Tue, 3 Apr 2018 19:21:53 +0900 (JST)
Subject: [ruby-changes:50866] ko1:r63073 (trunk): Fix Fiber with Thread issue on Windows [Bug #14642]
ko1 2018-04-03 19:21:47 +0900 (Tue, 03 Apr 2018) New Revision: 63073 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=63073 Log: Fix Fiber with Thread issue on Windows [Bug #14642] * cont.c (rb_threadptr_root_fiber_setup): divide into two functions: * rb_threadptr_root_fiber_setup_by_parent(): called by the parent thread. * rb_threadptr_root_fiber_setup_by_child(): called by the created thread. `rb_threadptr_root_fiber_setup()` is called by the parent thread and set fib->fib_handle by ConvertThreadToFiber() on the parent thread on Windows enveironment. This means that root_fib->fib_handle of child thread is initialized with parent thread's Fiber handle. Furthermore, second call of `ConvertThreadToFiber()` for the same thread fails. This patch solves this weird situateion. However, maybe we can make more clean code. * thread.c (thread_start_func_2): call `rb_threadptr_root_fiber_setup_by_child()` at thread initialize routine. * vm.c (th_init): call `rb_threadptr_root_fiber_setup_by_parent()`. Modified files: trunk/cont.c trunk/test/ruby/test_fiber.rb trunk/thread.c trunk/vm.c Index: cont.c =================================================================== --- cont.c (revision 63072) +++ cont.c (revision 63073) @@ -1464,6 +1464,18 @@ rb_fiber_start(void) https://github.com/ruby/ruby/blob/trunk/cont.c#L1464 VM_UNREACHABLE(rb_fiber_start); } +#ifdef _WIN32 +static HANDLE +win32_convert_thread_to_fiber(void) +{ + HANDLE fib_handle = ConvertThreadToFiber(0); + if (!fib_handle) { + rb_bug("rb_threadptr_root_fiber_setup_by_child: ConvertThreadToFiber() failed - %s\n", rb_w32_strerror(-1)); + } + return fib_handle; +} +#endif + static rb_fiber_t * root_fiber_alloc(rb_thread_t *th) { @@ -1480,7 +1492,7 @@ root_fiber_alloc(rb_thread_t *th) https://github.com/ruby/ruby/blob/trunk/cont.c#L1492 #if FIBER_USE_NATIVE #ifdef _WIN32 if (fib->fib_handle == 0) { - fib->fib_handle = ConvertThreadToFiber(0); + fib->fib_handle = win32_convert_thread_to_fiber(); } #endif #endif @@ -1488,7 +1500,7 @@ root_fiber_alloc(rb_thread_t *th) https://github.com/ruby/ruby/blob/trunk/cont.c#L1500 } void -rb_threadptr_root_fiber_setup(rb_thread_t *th) +rb_threadptr_root_fiber_setup_by_parent(rb_thread_t *th) { rb_fiber_t *fib = ruby_mimmalloc(sizeof(rb_fiber_t)); MEMZERO(fib, rb_fiber_t, 1); @@ -1497,10 +1509,20 @@ rb_threadptr_root_fiber_setup(rb_thread_ https://github.com/ruby/ruby/blob/trunk/cont.c#L1509 fib->cont.saved_ec.thread_ptr = th; fiber_status_set(fib, FIBER_RESUMED); /* skip CREATED */ th->ec = &fib->cont.saved_ec; +} + +void +rb_threadptr_root_fiber_setup_by_child(rb_thread_t *th) +{ #if FIBER_USE_NATIVE #ifdef _WIN32 + rb_fiber_t *fib = th->ec->fiber_ptr; + if (fib->fib_handle == 0) { - fib->fib_handle = ConvertThreadToFiber(0); + fib->fib_handle = win32_convert_thread_to_fiber(); + } + else { + rb_bug("rb_threadptr_root_fiber_setup_by_child: fib_handle is not NULL."); } #endif #endif Index: vm.c =================================================================== --- vm.c (revision 63072) +++ vm.c (revision 63073) @@ -2425,7 +2425,7 @@ rb_execution_context_mark(const rb_execu https://github.com/ruby/ruby/blob/trunk/vm.c#L2425 } void rb_fiber_mark_self(rb_fiber_t *fib); -void rb_threadptr_root_fiber_setup(rb_thread_t *th); +void rb_threadptr_root_fiber_setup_by_parent(rb_thread_t *th); void rb_threadptr_root_fiber_release(rb_thread_t *th); static void @@ -2533,7 +2533,7 @@ static void https://github.com/ruby/ruby/blob/trunk/vm.c#L2533 th_init(rb_thread_t *th, VALUE self) { th->self = self; - rb_threadptr_root_fiber_setup(th); + rb_threadptr_root_fiber_setup_by_parent(th); /* allocate thread stack */ #ifdef USE_SIGALTSTACK Index: test/ruby/test_fiber.rb =================================================================== --- test/ruby/test_fiber.rb (revision 63072) +++ test/ruby/test_fiber.rb (revision 63073) @@ -378,4 +378,13 @@ class TestFiber < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_fiber.rb#L378 assert_match(/terminated/, f.to_s) assert_match(/resumed/, Fiber.current.to_s) end + + def assert_create_fiber_in_new_thread + ret = Thread.new{ + Thread.new{ + Fiber.new{Fiber.yield :ok}.resume + }.join + }.join + assert_euqal :ok, ret, '[Bug #14642]' + end end Index: thread.c =================================================================== --- thread.c (revision 63072) +++ thread.c (revision 63073) @@ -643,6 +643,7 @@ thread_do_start(rb_thread_t *th, VALUE a https://github.com/ruby/ruby/blob/trunk/thread.c#L643 } void rb_ec_clear_current_thread_trace_func(const rb_execution_context_t *ec); +void rb_threadptr_root_fiber_setup_by_child(rb_thread_t *th); static int thread_start_func_2(rb_thread_t *th, VALUE *stack_start, VALUE *register_stack_start) @@ -662,6 +663,7 @@ thread_start_func_2(rb_thread_t *th, VAL https://github.com/ruby/ruby/blob/trunk/thread.c#L663 rb_bug("thread_start_func_2 must not be used for main thread"); ruby_thread_set_native(th); + rb_threadptr_root_fiber_setup_by_child(th); th->ec->machine.stack_start = stack_start; #ifdef __ia64 -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/