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/