[前][次][番号順一覧][スレッド一覧]

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/

[前][次][番号順一覧][スレッド一覧]