永井@知能.九工大です.

暫く前から「 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