Bug #4950
closedほぼ同時に異なる種類のシグナルを受信すると片方のシグナルハンドラが実行されない
Description
以下のようなスクリプトを実行すると [1,2] か [2,1] が表示されることが期待されますが、
実際には [1] が表示されます(稀に [2] になることもあります)。
a = []
trap(:INT) { a.push(1) }
trap(:TERM) { a.push(2) }
pid = $$
fork do
sleep 0.5
puts "send start"
Process.kill(:INT, pid)
Process.kill(:TERM, pid)
puts "send end"
end
puts "sleep start"
sleep 3
puts "sleep end"
p a
Signal.trap のブロック内で puts してみると、一方のシグナルハンドラが終了時に遅れて実行されているようです。
Updated by nagachika (Tomoyuki Chikanaga) over 13 years ago
シグナルがメインスレッドで処理されるまで配送を遅延しているので、タイマースレッドが polling をやめてしまうと配送が滞留するという問題みたいでした。
以下のように polling する条件に追加すると期待したような動作になりました。どうでしょうか。
diff --git a/thread_pthread.c b/thread_pthread.c
index 4f66c4e..016c3e9 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -1085,7 +1085,7 @@ thread_timer(void *p)
FD_ZERO(&rfds);
FD_SET(timer_thread_pipe[0], &rfds);
- if (gvl->waiting > 0 || need_polling) {
- if (gvl->waiting > 0 || need_polling || rb_signal_buff_size() > 0) {
timeout.tv_sec = 0;
timeout.tv_usec = TIME_QUANTUM_USEC;
Updated by ko1 (Koichi Sasada) over 13 years ago
- ruby -v changed from ruby 1.9.3dev (2011-06-30 trunk 32335) [x86_64-darwin10.8.0] to -
ささだです.
ちょうど小崎さんに同じ問題を指摘されて,しかも解決策も提示して頂いたの
で,パッチを作っていました.これで動きます(デバッグプリント込み).
http://www.atdot.net/sp/view/w8gmnl/readonly
ただ,make test で,copy_stream のテストが刺さる,という問題が解決できず
にいます.
at_exit { p :foo }
megacontent = "abc" * 12345678
#File.open("megasrc", "w") {|f| f << megacontent }
Thread.new { sleep p(rand*0.2); Process.kill(:INT, $$) }
r1, w1 = IO.pipe
r2, w2 = IO.pipe
t1 = Thread.new { w1 << megacontent; w1.close }
t2 = Thread.new { r2.read; r2.close }
IO.copy_stream(r1, w2) rescue nil
w2.close
r1.close
t1.join
t2.join
うーん,なぜだろう.rb_interrupt() までは呼ばれているようなのですが.
(2011/07/01 0:18), Tomoyuki Chikanaga wrote:
Issue #4950 has been updated by Tomoyuki Chikanaga.
シグナルがメインスレッドで処理されるまで配送を遅延しているので、タイマースレッドが polling をやめてしまうと配送が滞留するという問題みたいでした。
以下のように polling する条件に追加すると期待したような動作になりました。どうでしょうか。diff --git a/thread_pthread.c b/thread_pthread.c
index 4f66c4e..016c3e9 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -1085,7 +1085,7 @@ thread_timer(void *p)
FD_ZERO(&rfds);
FD_SET(timer_thread_pipe[0], &rfds);
- if (gvl->waiting > 0 || need_polling) {
- if (gvl->waiting > 0 || need_polling || rb_signal_buff_size() > 0) {
timeout.tv_sec = 0;
timeout.tv_usec = TIME_QUANTUM_USEC;
Bug #4950: ほぼ同時に異なる種類のシグナルを受信すると片方のシグナルハンドラが実行されない
http://redmine.ruby-lang.org/issues/4950Author: Tomoyuki Chikanaga
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: 1.9.3
ruby -v: ruby 1.9.3dev (2011-06-30 trunk 32335) [x86_64-darwin10.8.0]以下のようなスクリプトを実行すると [1,2] か [2,1] が表示されることが期待されますが、
実際には [1] が表示されます(稀に [2] になることもあります)。a = []
trap(:INT) { a.push(1) }
trap(:TERM) { a.push(2) }pid = $$
fork do
sleep 0.5
puts "send start"
Process.kill(:INT, pid)
Process.kill(:TERM, pid)
puts "send end"
endputs "sleep start"
sleep 3
puts "sleep end"
p aSignal.trap のブロック内で puts してみると、一方のシグナルハンドラが終了時に遅れて実行されているようです。
--
// SASADA Koichi at atdot dot net
Updated by ko1 (Koichi Sasada) over 13 years ago
ささだです.
ちょうど小崎さんに同じ問題を指摘されて,しかも解決策も提示して頂いたの
で,パッチを作っていました.これで動きます(デバッグプリント込み).
http://www.atdot.net/sp/view/w8gmnl/readonly
ただ,make test で,copy_stream のテストが刺さる,という問題が解決できず
にいます.
at_exit { p :foo }
megacontent = "abc" * 12345678
#File.open("megasrc", "w") {|f| f << megacontent }
Thread.new { sleep p(rand*0.2); Process.kill(:INT, $$) }
r1, w1 = IO.pipe
r2, w2 = IO.pipe
t1 = Thread.new { w1 << megacontent; w1.close }
t2 = Thread.new { r2.read; r2.close }
IO.copy_stream(r1, w2) rescue nil
w2.close
r1.close
t1.join
t2.join
うーん,なぜだろう.rb_interrupt() までは呼ばれているようなのですが.
(2011/07/01 0:18), Tomoyuki Chikanaga wrote:
Issue #4950 has been updated by Tomoyuki Chikanaga.
シグナルがメインスレッドで処理されるまで配送を遅延しているので、タイマースレッドが polling をやめてしまうと配送が滞留するという問題みたいでした。
以下のように polling する条件に追加すると期待したような動作になりました。どうでしょうか。diff --git a/thread_pthread.c b/thread_pthread.c
index 4f66c4e..016c3e9 100644
--- a/thread_pthread.c
+++ b/thread_pthread.c
@@ -1085,7 +1085,7 @@ thread_timer(void *p)
FD_ZERO(&rfds);
FD_SET(timer_thread_pipe[0], &rfds);
- if (gvl->waiting > 0 || need_polling) {
- if (gvl->waiting > 0 || need_polling || rb_signal_buff_size() > 0) {
timeout.tv_sec = 0;
timeout.tv_usec = TIME_QUANTUM_USEC;
Bug #4950: ほぼ同時に異なる種類のシグナルを受信すると片方のシグナルハンドラが実行されない
http://redmine.ruby-lang.org/issues/4950Author: Tomoyuki Chikanaga
Status: Open
Priority: Normal
Assignee:
Category: core
Target version: 1.9.3
ruby -v: ruby 1.9.3dev (2011-06-30 trunk 32335) [x86_64-darwin10.8.0]以下のようなスクリプトを実行すると [1,2] か [2,1] が表示されることが期待されますが、
実際には [1] が表示されます(稀に [2] になることもあります)。a = []
trap(:INT) { a.push(1) }
trap(:TERM) { a.push(2) }pid = $$
fork do
sleep 0.5
puts "send start"
Process.kill(:INT, pid)
Process.kill(:TERM, pid)
puts "send end"
endputs "sleep start"
sleep 3
puts "sleep end"
p aSignal.trap のブロック内で puts してみると、一方のシグナルハンドラが終了時に遅れて実行されているようです。
--
// SASADA Koichi at atdot dot net
Updated by ko1 (Koichi Sasada) over 13 years ago
- Status changed from Open to Closed
- % Done changed from 0 to 100
This issue was solved with changeset r32345.
Tomoyuki, thank you for reporting this issue.
Your contribution to Ruby is greatly appreciated.
May Ruby be with you.
- thread.c (rb_threadptr_check_signal): only wake up main thread.
- thread.c (rb_threadptr_execute_interrupts_common): check signal
deliverly if it is main thread.
fixes [ruby-dev:44005] [Ruby 1.9 - Bug #4950] - bootstraptest/test_fork.rb: add a test for above.
- signal.c (rb_get_next_signal): skip if signal_buff is empty.
(check signal_buff.size first) - vm_core.h: remove unused variable rb_thread_t::exec_signal.
- thread.c (rb_thread_check_trap_pending): check
rb_signal_buff_size() because rb_thread_t::exec_signal
is no longer available.