summaryrefslogtreecommitdiff
path: root/signal.c
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-05-10 16:10:32 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-05-10 16:10:32 +0000
commit77af38d0a5bd759bc332b817485212614ace7f1c (patch)
tree42057f18dbbec13a5f057fbc02783e9087e6e538 /signal.c
parent23fce7548248e75741f80d43cab8f812e00611b4 (diff)
signal.c: directly enqueue
* signal.c (rb_f_kill): directly enqueue an ignored signal to self, except for SIGSEGV and SIGBUS. [ruby-dev:48203] [Bug #9820] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@45911 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'signal.c')
-rw-r--r--signal.c60
1 files changed, 57 insertions, 3 deletions
diff --git a/signal.c b/signal.c
index 7dc4247220..82c9125c90 100644
--- a/signal.c
+++ b/signal.c
@@ -350,6 +350,9 @@ ruby_default_signal(int sig)
raise(sig);
}
+static int signal_ignored(int sig);
+static void signal_enque(int sig);
+
/*
* call-seq:
* Process.kill(signal, pid, ...) -> fixnum
@@ -436,6 +439,8 @@ rb_f_kill(int argc, VALUE *argv)
break;
}
+ if (argc <= 1) return INT2FIX(0);
+
if (sig < 0) {
sig = -sig;
for (i=1; i<argc; i++) {
@@ -444,8 +449,36 @@ rb_f_kill(int argc, VALUE *argv)
}
}
else {
+ const rb_pid_t self = (GET_THREAD() == GET_VM()->main_thread) ? getpid() : -1;
+ int wakeup = 0;
+
for (i=1; i<argc; i++) {
- ruby_kill(NUM2PIDT(argv[i]), sig);
+ rb_pid_t pid = NUM2PIDT(argv[i]);
+
+ if ((sig != 0) && (self != -1) && (pid == self)) {
+ /*
+ * When target pid is self, many caller assume signal will be
+ * delivered immediately and synchronously.
+ */
+ switch (sig) {
+ case SIGSEGV:
+#ifdef SIGBUS
+ case SIGBUS:
+#endif
+ ruby_kill(pid, sig);
+ break;
+ default:
+ if (signal_ignored(sig)) break;
+ signal_enque(sig);
+ wakeup = 1;
+ }
+ }
+ else if (kill(pid, sig) < 0) {
+ rb_sys_fail(0);
+ }
+ }
+ if (wakeup) {
+ rb_threadptr_check_signal(GET_VM()->main_thread);
}
}
rb_thread_execute_interrupts(rb_thread_current());
@@ -578,11 +611,32 @@ ruby_nativethread_signal(int signum, sighandler_t handler)
#endif
#endif
-static RETSIGTYPE
-sighandler(int sig)
+static int
+signal_ignored(int sig)
+{
+#ifdef POSIX_SIGNAL
+ struct sigaction old;
+ (void)VALGRIND_MAKE_MEM_DEFINED(&old, sizeof(old));
+ if (sigaction(sig, NULL, &old) < 0) return FALSE;
+ return old.sa_handler == SIG_IGN;
+#else
+ sighandler_t old = signal(sig, SIG_DFL);
+ signal(sig, old);
+ return old == SIG_IGN;
+#endif
+}
+
+static void
+signal_enque(int sig)
{
ATOMIC_INC(signal_buff.cnt[sig]);
ATOMIC_INC(signal_buff.size);
+}
+
+static RETSIGTYPE
+sighandler(int sig)
+{
+ signal_enque(sig);
rb_thread_wakeup_timer_thread();
#if !defined(BSD_SIGNAL) && !defined(POSIX_SIGNAL)
ruby_signal(sig, sighandler);