From: Hidetoshi NAGAI Date: 2005-02-18T12:13:27+09:00 Subject: [ruby-dev:25713] pthread trouble on sighandler 永井@知能.九工大です. 暫く前から「 enable-pthread の Ruby 上で Tk インタープリタを 複数動かしている状況で,bgerror によるエラーダイアログが 表示されている際に Interrupt をかけると SEGV で落ちる」という 結構マイナーな状況 (^_^; の問題の解消を試みていたのですが, Ruby の sighandler で,Ruby インタープリタが動いている native thread 以外でのシグナルを無視することしか 確実な回避方法はなさそうです. # Tk に限らず,pthread サポートのライブラリを使用する際には # 同様の問題が生じるのではないかと思います. Ruby レベルでのハンドラでは無視でも問題ないのではないかと 思うのですが,場合によっては C レベルで native thread 対応の sighandler を独自に登録することもありうると考えて, それ用の関数も用意してみたパッチが添付のものです. 本当に「無視」で問題ないかについてはあまり自信はないのですが, いかがなものでしょうか? Index: intern.h =================================================================== RCS file: /var/cvs/src/ruby/intern.h,v retrieving revision 1.163 diff -u -r1.163 intern.h --- intern.h 16 Dec 2004 15:01:49 -0000 1.163 +++ intern.h 18 Feb 2005 03:02:02 -0000 @@ -398,8 +398,12 @@ VALUE rb_f_kill _((int, VALUE*)); void rb_gc_mark_trap_list _((void)); #ifdef POSIX_SIGNAL -#define posix_signal ruby_posix_signal +#define ruby_posix_signal posix_signal void posix_signal _((int, RETSIGTYPE (*)(int))); +#ifdef HAVE_NATIVETHREAD +#define ruby_posix_nativethread_signal posix_nativethread_signal +void posix_nativethread_signal _((int, RETSIGTYPE (*)(int))); +#endif #endif void rb_trap_exit _((void)); void rb_trap_exec _((void)); Index: signal.c =================================================================== RCS file: /var/cvs/src/ruby/signal.c,v retrieving revision 1.55 diff -u -r1.55 signal.c --- signal.c 30 Nov 2004 17:28:16 -0000 1.55 +++ signal.c 18 Feb 2005 03:02:02 -0000 @@ -303,6 +303,7 @@ int safe; } trap_list[NSIG]; static rb_atomic_t trap_pending_list[NSIG]; +static char rb_trap_accept_nativethread[NSIG]; rb_atomic_t rb_trap_pending; rb_atomic_t rb_trap_immediate; int rb_prohibit_interrupt = 1; @@ -334,6 +335,8 @@ { struct sigaction sigact, old; + rb_trap_accept_nativethread[signum] = 0; + sigact.sa_handler = handler; sigemptyset(&sigact.sa_mask); sigact.sa_flags = 0; @@ -360,8 +363,30 @@ { ruby_signal(signum, handler); } -#else -#define ruby_signal(sig,handler) signal((sig),(handler)) + +#ifdef HAVE_NATIVETHREAD +static sighandler_t +ruby_nativethread_signal(signum, handler) + int signum; + sighandler_t handler; +{ + ruby_signal(signum, handler); + rb_trap_accept_nativethread[signum] = 1; +} + +void +posix_nativethread_signal(signum, handler) + int signum; + sighandler_t handler; +{ + ruby_nativethread_signal(signum, handler); +} +#endif +#else /* !POSIX_SIGNAL */ +#define ruby_signal(sig,handler) {rb_trap_accept_nativethread[signum] = 0; signal((sig),(handler));} +#ifdef HAVE_NATIVETHREAD +#define ruby_nativethread_signal(sig,handler) {signal((sig),(handler));rb_trap_accept_nativethread[signum] = 1;} +#endif #endif static void signal_exec _((int sig)); @@ -413,6 +438,13 @@ rb_bug("trap_handler: Bad signal %d", sig); } +#ifdef HAVE_NATIVETHREAD + if (!is_ruby_native_thread() && !rb_trap_accept_nativethread[sig]) { + /* ignore signals on non-Ruby native thread */ + return; + } +#endif + #if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL) ruby_signal(sig, sighandler); #endif @@ -770,6 +802,27 @@ ruby_signal(signum, old); } } + +#ifdef HAVE_NATIVETHREAD +static void +install_nativethread_sighandler(signum, handler) + int signum; + sighandler_t handler; +{ + sighandler_t old; + int old_st; + + old_st = rb_trap_accept_nativethread[signum]; + old = ruby_nativethread_signal(signum, handler); + if (old != SIG_DFL) { + if (old_st) { + ruby_nativethread_signal(signum, old); + } else { + ruby_signal(signum, old); + } + } +} +#endif static void init_sigchld(sig) -- 永井 秀利 (九工大 知能情報) nagai@ai.kyutech.ac.jp