[ruby-dev:25734] Re: pthread trouble on sighandler
From:
Hidetoshi NAGAI <nagai@...>
Date:
2005-02-21 06:09:19 UTC
List:
ruby-dev #25734
永井@知能.九工大です.
From: Yukihiro Matsumoto <matz@ruby-lang.org>
Subject: [ruby-dev:25721] Re: pthread trouble on sighandler
Date: Sat, 19 Feb 2005 10:19:32 +0900
Message-ID: <1108775957.264706.21833.nullmailer@x31.priv.netlab.jp>
> そういうことです。コミットしてくださいますか。
はい,承知しました.
ただ,その後にちょっと手を入れてしまってますので,
添付のもので問題がなければコミットさせていただきます.
追加で手を入れた部分は,
・sighandler() 以外の sigbus() 等でも ruby 外の native thread を
無視するように設定.
・ハンドラの登録状態を得る Signal.accept_nativethread?(sig) を追加.
ただし,「受理可として登録されたか否か」を返しているだけなので,
本当に複数の native thread のシグナルを扱えるのかどうかは
登録されたハンドラ次第となる.
という部分です.
ちなみに標準のハンドラ (trap メソッドで登録した場合を含む) では
Signal.accept_nativethread?(sig) ==> false です.
------------------------------------------------------------------------
* signal.c: Standard signal handlers ignore signals on non-Ruby native
threads. When a handler is entried with ruby_signal() (like as the
standard signal handlers), the handler for the signal is marked as
it cannot accept non-Ruby native threads. If a handler can treat all
signals on all native threads, please use ruby_nativethread_signal()
to entry it. Signal.accept_nativethreads?(sig) returns current
status for `sig'. If a handler for a signal `sig' is entried with
ruby_nativethread_signal(), Signal.accept_nativethreads?(sig)
returns `true'. The status `false' means either of `cannot accept'
or `ignore' non-Ruby native threads. Note that the status doesn't
guarantee the handler's ability.
------------------------------------------------------------------------
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 21 Feb 2005 05:56:38 -0000
@@ -400,6 +400,11 @@
#ifdef POSIX_SIGNAL
#define posix_signal ruby_posix_signal
void posix_signal _((int, RETSIGTYPE (*)(int)));
+#ifdef HAVE_NATIVETHREAD
+#define posix_nativethread_signal ruby_posix_nativethread_signal
+void posix_nativethread_signal _((int, RETSIGTYPE (*)(int)));
+VALUE rb_accept_nativethreads_p _((VALUE, VALUE));
+#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 21 Feb 2005 05:56:38 -0000
@@ -303,6 +303,7 @@
int safe;
} trap_list[NSIG];
static rb_atomic_t trap_pending_list[NSIG];
+static char rb_trap_accept_nativethreads[NSIG];
rb_atomic_t rb_trap_pending;
rb_atomic_t rb_trap_immediate;
int rb_prohibit_interrupt = 1;
@@ -320,6 +321,55 @@
#endif /* MACOS_UNUSE_SIGNAL */
}
+VALUE
+rb_accept_nativethreads_p(obj, sig)
+ VALUE obj;
+ VALUE sig;
+{
+#ifndef HAVE_NATIVETHREAD
+ return Qfalse;
+#else
+ int signum = -1;
+ char *s;
+
+ switch (TYPE(sig)) {
+ case T_FIXNUM:
+ signum = FIX2INT(sig);
+ break;
+
+ case T_SYMBOL:
+ s = rb_id2name(SYM2ID(sig));
+ if (!s) rb_raise(rb_eArgError, "bad signal");
+ goto str_signal;
+
+ case T_STRING:
+ s = RSTRING(sig)->ptr;
+
+ str_signal:
+ if (strncmp("SIG", s, 3) == 0)
+ s += 3;
+ signum = signm2signo(s);
+ if (signum == 0 && strcmp(s, "EXIT") != 0)
+ rb_raise(rb_eArgError, "unsupported signal SIG%s", s);
+ }
+
+ if (signum < 0 || signum > NSIG) {
+ rb_raise(rb_eArgError, "invalid signal number (%d)", signum);
+ }
+#if defined(HAVE_SETITIMER)
+ if (signum == SIGVTALRM) {
+ rb_raise(rb_eArgError, "SIGVTALRM reserved for Thread; cannot set handler");
+ }
+#endif
+
+ if (rb_trap_accept_nativethreads[signum]) {
+ return Qtrue;
+ } else {
+ return Qfalse;
+ }
+#endif
+}
+
#ifdef __dietlibc__
#define sighandler_t sh_t
#endif
@@ -334,6 +384,8 @@
{
struct sigaction sigact, old;
+ rb_trap_accept_nativethreads[signum] = 0;
+
sigact.sa_handler = handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
@@ -360,8 +412,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_nativethreads[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_nativethreads[sig] = 0; signal((sig),(handler));}
+#ifdef HAVE_NATIVETHREAD
+#define ruby_nativethread_signal(sig,handler) {signal((sig),(handler));rb_trap_accept_nativethreads[sig] = 1;}
+#endif
#endif
static void signal_exec _((int sig));
@@ -408,13 +482,23 @@
#else
#define IN_MAIN_CONTEXT(f, a) f(a)
#endif
-
if (sig >= NSIG) {
rb_bug("trap_handler: Bad signal %d", sig);
}
+#ifdef HAVE_NATIVETHREAD
+ if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) {
+ /* ignore signals on non-Ruby native thread */
+ return;
+ }
+#endif
+
#if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL)
- ruby_signal(sig, sighandler);
+ if (rb_trap_accept_nativethreads[sig]) {
+ ruby_nativethread_signal(sig, sighandler);
+ } else {
+ ruby_signal(sig, sighandler);
+ }
#endif
if (trap_list[sig].cmd == 0 && ATOMIC_TEST(rb_trap_immediate)) {
@@ -433,6 +517,13 @@
sigbus(sig)
int sig;
{
+#ifdef HAVE_NATIVETHREAD
+ if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) {
+ /* ignore signals on non-Ruby native thread */
+ return;
+ }
+#endif
+
rb_bug("Bus Error");
}
#endif
@@ -443,6 +534,13 @@
sigsegv(sig)
int sig;
{
+#ifdef HAVE_NATIVETHREAD
+ if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) {
+ /* ignore signals on non-Ruby native thread */
+ return;
+ }
+#endif
+
rb_bug("Segmentation fault");
}
#endif
@@ -508,6 +606,13 @@
sigexit(sig)
int sig;
{
+#ifdef HAVE_NATIVETHREAD
+ if (!is_ruby_native_thread() && !rb_trap_accept_nativethreads[sig]) {
+ /* ignore signals on non-Ruby native thread */
+ return;
+ }
+#endif
+
rb_exit(0);
}
@@ -771,6 +876,27 @@
}
}
+#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_nativethreads[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)
int sig;
@@ -859,6 +985,8 @@
rb_define_global_function("trap", sig_trap, -1);
rb_define_module_function(mSignal, "trap", sig_trap, -1);
rb_define_module_function(mSignal, "list", sig_list, 0);
+ rb_define_module_function(mSignal, "accept_nativethreads?",
+ rb_accept_nativethreads_p, 1);
install_sighandler(SIGINT, sighandler);
#ifdef SIGHUP
--
永井 秀利 (九工大 知能情報)
nagai@ai.kyutech.ac.jp