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

ruby-changes:54010

From: normal <ko1@a...>
Date: Thu, 6 Dec 2018 03:58:49 +0900 (JST)
Subject: [ruby-changes:54010] normal:r66230 (trunk): thread_sync.c (mutex_ptr): handle mutexes held by parent threads in children

normal	2018-12-06 03:58:45 +0900 (Thu, 06 Dec 2018)

  New Revision: 66230

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=66230

  Log:
    thread_sync.c (mutex_ptr): handle mutexes held by parent threads in children
    
    Mutexes may be held by threads which only exist in the parent
    process, so their waitqueues may be populated with references
    to other dead threads.  We must reset them at fork.
    
    I am a moron for introducing this bug :<
    
    [ruby-core:90312] [Bug #15383]

  Modified files:
    trunk/test/ruby/test_thread.rb
    trunk/thread_sync.c
Index: test/ruby/test_thread.rb
===================================================================
--- test/ruby/test_thread.rb	(revision 66229)
+++ test/ruby/test_thread.rb	(revision 66230)
@@ -1239,6 +1239,27 @@ q.pop https://github.com/ruby/ruby/blob/trunk/test/ruby/test_thread.rb#L1239
     end
   end if Process.respond_to?(:fork)
 
+  def test_fork_while_parent_locked
+    skip 'needs fork' unless Process.respond_to?(:fork)
+    m = Thread::Mutex.new
+    failures = 0
+    run = true
+    thrs = 50.times.map do
+      Thread.new do
+        while run
+          pid = fork { m.synchronize {} }
+          m.synchronize {}
+          _, st = Process.waitpid2(pid)
+          m.synchronize { failures += 1 } unless st.success?
+        end
+      end
+    end
+    sleep 0.5
+    run = false
+    thrs.each(&:join)
+    assert_equal 0, failures, '[ruby-core:90312] [Bug #15383]'
+  end
+
   def test_subclass_no_initialize
     t = Module.new do
       break eval("class C\u{30b9 30ec 30c3 30c9} < Thread; self; end")
Index: thread_sync.c
===================================================================
--- thread_sync.c	(revision 66229)
+++ thread_sync.c	(revision 66230)
@@ -45,6 +45,7 @@ typedef struct rb_mutex_struct { https://github.com/ruby/ruby/blob/trunk/thread_sync.c#L45
     rb_thread_t *th;
     struct rb_mutex_struct *next_mutex;
     struct list_head waitq; /* protected by GVL */
+    rb_serial_t fork_gen;
 } rb_mutex_t;
 
 #if defined(HAVE_WORKING_FORK)
@@ -121,8 +122,18 @@ static rb_mutex_t * https://github.com/ruby/ruby/blob/trunk/thread_sync.c#L122
 mutex_ptr(VALUE obj)
 {
     rb_mutex_t *mutex;
+    rb_serial_t fork_gen = GET_VM()->fork_gen;
 
     TypedData_Get_Struct(obj, rb_mutex_t, &mutex_data_type, mutex);
+
+    if (mutex->fork_gen != fork_gen) {
+        /* forked children can't reach into parent thread stacks */
+        mutex->fork_gen = fork_gen;
+        list_head_init(&mutex->waitq);
+        mutex->next_mutex = 0;
+        mutex->th = 0;
+    }
+
     return mutex;
 }
 

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

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