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

ruby-changes:21978

From: nobu <ko1@a...>
Date: Tue, 13 Dec 2011 16:14:37 +0900 (JST)
Subject: [ruby-changes:21978] nobu:r34027 (trunk): * load.c (load_unlock): all threads requiring one file should

nobu	2011-12-13 16:13:31 +0900 (Tue, 13 Dec 2011)

  New Revision: 34027

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=34027

  Log:
    * load.c (load_unlock): all threads requiring one file should
      share same loading barrier, so it must be kept alive while those
      are waiting on it.  [ruby-core:41618] [Bug #5754]

  Modified files:
    trunk/ChangeLog
    trunk/internal.h
    trunk/load.c
    trunk/test/ruby/test_require.rb
    trunk/thread.c

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 34026)
+++ ChangeLog	(revision 34027)
@@ -1,3 +1,9 @@
+Tue Dec 13 16:13:29 2011  Nobuyoshi Nakada  <nobu@r...>
+
+	* load.c (load_unlock): all threads requiring one file should
+	  share same loading barrier, so it must be kept alive while those
+	  are waiting on it.  [ruby-core:41618] [Bug #5754]
+
 Tue Dec 13 07:30:14 2011  Aaron Patterson <aaron@t...>
 
 	* lib/webrick/httpresponse.rb (setup_header): 1xx responses
Index: load.c
===================================================================
--- load.c	(revision 34026)
+++ load.c	(revision 34027)
@@ -415,10 +415,12 @@
 	st_data_t key = (st_data_t)ftptr;
 	st_data_t data;
 	st_table *loading_tbl = get_loading_table();
+	VALUE barrier;
 
-	if (st_delete(loading_tbl, &key, &data)) {
-	    VALUE barrier = (VALUE)data;
-	    xfree((char *)key);
+	if (!st_lookup(loading_tbl, key, &data)) return;
+	barrier = (VALUE)data;
+	if (rb_barrier_waiting(barrier) ||
+	    (st_delete(loading_tbl, &key, &data) && (xfree((char *)key), 1))) {
 	    if (done)
 		rb_barrier_destroy(barrier);
 	    else
Index: thread.c
===================================================================
--- thread.c	(revision 34026)
+++ thread.c	(revision 34027)
@@ -3723,6 +3723,17 @@
     return rb_mutex_unlock(mutex);
 }
 
+int
+rb_barrier_waiting(VALUE self)
+{
+    VALUE mutex = GetBarrierPtr(self);
+    rb_mutex_t *m;
+
+    if (!mutex) return 0;
+    GetMutexPtr(mutex, m);
+    return m->cond_waiting;
+}
+
 /* variables for recursive traversals */
 static ID recursive_key;
 
Index: internal.h
===================================================================
--- internal.h	(revision 34026)
+++ internal.h	(revision 34027)
@@ -181,6 +181,7 @@
 void rb_clear_trace_func(void);
 VALUE rb_thread_backtrace(VALUE thval);
 VALUE rb_get_coverages(void);
+int rb_barrier_waiting(VALUE barrier);
 
 /* thread_pthread.c, thread_win32.c */
 void Init_native_thread(void);
Index: test/ruby/test_require.rb
===================================================================
--- test/ruby/test_require.rb	(revision 34026)
+++ test/ruby/test_require.rb	(revision 34027)
@@ -339,4 +339,60 @@
                       [], /\$LOADED_FEATURES is frozen; cannot append feature \(RuntimeError\)$/,
                       bug3756)
   end
+
+  class << self
+    attr_accessor :scratch
+  end
+
+  def test_race_excption
+    bug5754 = '[ruby-core:41618]'
+    tmp = Tempfile.new(%w"bug5754 .rb")
+    path = tmp.path
+    tmp.print <<-EOS
+TestRequire.scratch << :pre
+Thread.pass until t2 = TestRequire.scratch[1]
+Thread.pass until t2.stop?
+open(__FILE__, "w") {|f| f.puts "TestRequire.scratch << :post"}
+raise "con1"
+    EOS
+    tmp.close
+
+    start = false
+    fin = false
+
+    TestRequire.scratch = scratch = []
+    t1_res = nil
+    t2_res = nil
+
+    t1 = Thread.new do
+      begin
+        require(path)
+      rescue RuntimeError
+      end
+
+      t1_res = require(path)
+
+      Thread.pass until fin
+      scratch << :t1
+    end
+
+    t2 = Thread.new do
+      Thread.pass until scratch[0]
+      begin
+        scratch << t2
+        t2_res = require(path)
+        scratch << :t2
+      ensure
+        fin = true
+      end
+    end
+
+    assert_nothing_raised(ThreadError, bug5754) {t1.join}
+    assert_nothing_raised(ThreadError, bug5754) {t2.join}
+
+    assert_equal([false, true], [t1_res, t2_res], bug5754)
+    assert_equal([:pre, t2, :post, :t2, :t1], scratch, bug5754)
+
+    tmp.close(true)
+  end
 end

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

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