Project

General

Profile

Actions

Bug #4950

closed

ほぼ同時に異なる種類のシグナルを受信すると片方のシグナルハンドラが実行されない

Added by nagachika (Tomoyuki Chikanaga) over 13 years ago. Updated over 13 years ago.

Status:
Closed
Assignee:
-
Target version:
ruby -v:
-
Backport:
[ruby-dev:44005]

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/4950

Author: 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"
end

puts "sleep start"
sleep 3
puts "sleep end"
p a

Signal.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/4950

Author: 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"
end

puts "sleep start"
sleep 3
puts "sleep end"
p a

Signal.trap のブロック内で puts してみると、一方のシグナルハンドラが終了時に遅れて実行されているようです。

--
// SASADA Koichi at atdot dot net

Actions #4

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.
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0