[#42564] [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — Makoto Kishimoto <redmine@...>

Feature #4043: グローバル関数current_classの提案

15 messages 2010/11/11
[#42774] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — Yukihiro Matsumoto <matz@...> 2010/12/16

まつもと ゆきひろです

[#42834] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — "KISHIMOTO, Makoto" <ksmakoto@...4u.or.jp> 2010/12/21

きしもとです

[#42835] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — Yukihiro Matsumoto <matz@...> 2010/12/21

まつもと ゆきひろです

[#42838] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — "KISHIMOTO, Makoto" <ksmakoto@...4u.or.jp> 2010/12/21

きしもとです

[#42845] Re: [Ruby 1.9-Feature#4043][Open] グローバル関数current_classの提案 — Yukihiro Matsumoto <matz@...> 2010/12/21

まつもと ゆきひろです

[#42577] Rubyのバグレポートのガイドライン — "Shota Fukumori (sora_h)" <sorah@...>

sora_hです。

11 messages 2010/11/15
[#42588] Re: Rubyのバグレポートのガイドライン — Yugui <yugui@...> 2010/11/18

2010/11/15 Shota Fukumori (sora_h) <sorah@tubusu.net>:

[#42638] Enumerable#categorize — Tanaka Akira <akr@...>

enumerable から hash を生成するメソッドとして

25 messages 2010/11/27
[#42643] Re: Enumerable#categorize — Yukihiro Matsumoto <matz@...> 2010/11/27

まつもと ゆきひろです

[ruby-dev:42560] [Ruby 1.9-Bug#4027] Signal.trap で busy loop に陥る

From: Tomoyuki Chikanaga <redmine@...>
Date: 2010-11-10 16:33:27 UTC
List: ruby-dev #42560
チケット #4027 が更新されました。 (by Tomoyuki Chikanaga)

ファイル sigmask.patch 追加

元々の signal_buff の数が合わなくないのはまだ原因がわかりませんが、
シグナルマスクの処理について調べていて間違っていそうなところをみつけました。

まずささださんが指摘されていた rb_get_next_signal() で rb_enable_interrupt() でシグナルマスクを
外している点ですが、rb_get_next_signal() はタイマースレッドからのみ呼ばれるのでこれは問題なさそうです。

しかしメインスレッドその他の Thread に対応するスレッドのシグナルマスクは SIGSEGV と SIGVTALRM のみ
外されているはずなのに、全て外されていました。
このため sighandler() がタイマースレッドでなくメインスレッドで実行されています。
これは以下のような流れでおきています。
 * init_sigchld で初期状態(空マスク)の sigmask が trap_last_sigmask に保存される
 * タイマースレッドの起動(rb_thread_create_timer_thread)でメインスレッドはマスクがセットされる
 * その後ファイルロード中に例外が生成された時に rb_trap_restore_mask() が呼ばれて trap_last_sigmask に
   保存された空マスクがセットされるためシグナルマスクが外れる

また、Signal.trap でハンドラをセットした時に、そのシグナルのシグナルマスクが外されています。
sigaction によるシグナルハンドラの実行はタイマースレッドにまかせているはずなのでこれは不要だと思います。
また例外発生時に rb_trap_restore_mask を読んでいるのも、trap() で例外が発生しても trap_ensure() で
シグナルマスクを戻す処理は行なわれているので不要なような気がします。元々どういう理由で呼ばれているのか
わからなかったので自信ないですけど。

というわけで添付のようなパッチを作成してみました。

ところがこれを当てると make test-all で Failure が 2つ増えます。
いずれも ruby のプロセスをシグナルで止めた時に終了ステータスが $?.signaled? == true でなく
$?.exited? == true になるためです。
これはどう直せばいいのかわかりません。

  1) Failure:
test_should_propagate_signaled(TestBeginEndBlock) [/Users/nagachika/opt/ruby-trunk/src/ruby-trunk/test/ruby/test_beginendblock.rb:108]:
Expected 0 to be nil.

  2) Failure:
test_status_kill(TestProcess) [/Users/nagachika/opt/ruby-trunk/src/ruby-trunk/test/ruby/test_process.rb:1073]:
[s.exited?, s.signaled?, s.stopped?].
<[false, true, false]> expected but was
<[true, false, false]>.

また、sighandler() がメインスレッドから呼ばれるのは Process.spawn を実行するとまだおきてしまいます。
process.c の before_fork/after_fork で fork の時に一時的にタイマースレッドを止めてシグナルマスクを外すためです。
こちらもどうしていいものかわからないです。
fork してそのまま動き続けるようなものはどうしようもないような気がしますが、spawn するものは
fork 後に sigprogmask で外すようにするなどでなんとかならないものでしょうか。
あーでもタイマースレッドの再起動で結局一時的に外してしまいますね……

なお、このせいで sighandler にメインスレッドとタイマースレッドで同時に実行してしまって
signal_buff のカウンタがおかしくなったのかも、とも思ったのですが、ATOMIC_INC 部分を disassemble してみると
それぞれ incl の1命令で実行されているので、仮に並列に実行されても加算もれすることはなさそうです。
プロセッサによってはダメだったりするんでしょうか。

----------------------------------------
http://redmine.ruby-lang.org/issues/show/4027

----------------------------------------
http://redmine.ruby-lang.org

Attachments (1)

sigmask.patch (2.34 KB, text/x-diff)
Index: eval_intern.h
===================================================================
--- eval_intern.h	(revision 29738)
+++ eval_intern.h	(working copy)
@@ -210,7 +210,6 @@
 void rb_thread_terminate_all(void);
 VALUE rb_vm_top_self();
 VALUE rb_vm_cbase(void);
-void rb_trap_restore_mask(void);
 
 #ifndef CharNext		/* defined as CharNext[AW] on Windows. */
 #define CharNext(p) ((p) + mblen(p, RUBY_MBCHAR_MAXSIZE))
Index: vm_eval.c
===================================================================
--- vm_eval.c	(revision 29738)
+++ vm_eval.c	(working copy)
@@ -1439,7 +1439,6 @@
 	VALUE desc = rb_inspect(tag);
 	rb_raise(rb_eArgError, "uncaught throw %s", RSTRING_PTR(desc));
     }
-    rb_trap_restore_mask();
     th->errinfo = NEW_THROW_OBJECT(tag, 0, TAG_THROW);
 
     JUMP_TAG(TAG_THROW);
Index: eval.c
===================================================================
--- eval.c	(revision 29738)
+++ eval.c	(working copy)
@@ -438,8 +438,6 @@
 	JUMP_TAG(TAG_FATAL);
     }
 
-    rb_trap_restore_mask();
-
     if (tag != TAG_FATAL) {
 	EXEC_EVENT_HOOK(th, RUBY_EVENT_RAISE, th->cfp->self, 0, 0);
     }
Index: signal.c
===================================================================
--- signal.c	(revision 29738)
+++ signal.c	(working copy)
@@ -538,14 +538,6 @@
     return signal_buff.size;
 }
 
-#if USE_TRAP_MASK
-# ifdef HAVE_SIGPROCMASK
-static sigset_t trap_last_mask;
-# else
-static int trap_last_mask;
-# endif
-#endif
-
 #if HAVE_PTHREAD_H
 #include <pthread.h>
 #endif
@@ -880,13 +872,6 @@
     vm->trap_list[sig].cmd = command;
     vm->trap_list[sig].safe = rb_safe_level();
     /* enable at least specified signal. */
-#if USE_TRAP_MASK
-#ifdef HAVE_SIGPROCMASK
-    sigdelset(&arg->mask, sig);
-#else
-    arg->mask &= ~sigmask(sig);
-#endif
-#endif
     return oldcmd;
 }
 
@@ -896,19 +881,10 @@
 {
     /* enable interrupt */
     pthread_sigmask(SIG_SETMASK, &arg->mask, NULL);
-    trap_last_mask = arg->mask;
     return 0;
 }
 #endif
 
-void
-rb_trap_restore_mask(void)
-{
-#if USE_TRAP_MASK
-    pthread_sigmask(SIG_SETMASK, &trap_last_mask, NULL);
-#endif
-}
-
 /*
  * call-seq:
  *   Signal.trap( signal, command ) -> obj
@@ -1031,12 +1007,6 @@
     } else {
 	GET_VM()->trap_list[sig].cmd = 0;
     }
-
-#if USE_TRAP_MASK
-    sigdelset(&mask, sig);
-    pthread_sigmask(SIG_SETMASK, &mask, NULL);
-    trap_last_mask = mask;
-#endif
 }
 #endif
 

In This Thread

Prev Next