summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-09-01 17:16:03 +0000
committernagachika <nagachika@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2014-09-01 17:16:03 +0000
commit06042f854ff815c6287bce132ed8e23d2a600a93 (patch)
tree89831d237e39fbba5732a80ce4bf568829cd6e3e
parent478a0180c4713da8b32438e668fb69765423b269 (diff)
merge revision(s) r45911,r45912,r45917,r45918,r45919: [Backport #9820]
* 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/branches/ruby_2_1@47345 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog5
-rw-r--r--signal.c66
-rw-r--r--test/ruby/test_process.rb25
-rw-r--r--test/ruby/test_signal.rb11
-rw-r--r--thread.c9
-rw-r--r--version.h8
6 files changed, 106 insertions, 18 deletions
diff --git a/ChangeLog b/ChangeLog
index 63cbc95006..326fc7ba0c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Tue Sep 2 02:08:12 2014 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * signal.c (rb_f_kill): directly enqueue an ignored signal to self,
+ except for SIGSEGV and SIGBUS. [ruby-dev:48203] [Bug #9820]
+
Sun Aug 31 01:13:21 2014 Koichi Sasada <ko1@atdot.net>
* gc.c: change full GC timing to keep lower memory usage.
diff --git a/signal.c b/signal.c
index 6c587ae851..1524885eb5 100644
--- a/signal.c
+++ b/signal.c
@@ -343,6 +343,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
@@ -429,6 +432,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++) {
@@ -437,8 +442,42 @@ 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
+#ifdef SIGKILL
+ case SIGKILL:
+#endif
+#ifdef SIGSTOP
+ case SIGSTOP:
+#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());
@@ -570,11 +609,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);
diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb
index f6e44fadad..a71a2d6dce 100644
--- a/test/ruby/test_process.rb
+++ b/test/ruby/test_process.rb
@@ -1193,6 +1193,23 @@ class TestProcess < Test::Unit::TestCase
def test_status_kill
return unless Process.respond_to?(:kill)
+ return unless Signal.list.include?("KILL")
+
+ # assume the system supports signal if SIGQUIT is available
+ expected = Signal.list.include?("QUIT") ? [false, true, false, nil] : [true, false, false, true]
+
+ with_tmpchdir do
+ write_file("foo", "Process.kill(:KILL, $$); exit(42)")
+ system(RUBY, "foo")
+ s = $?
+ assert_equal(expected,
+ [s.exited?, s.signaled?, s.stopped?, s.success?],
+ "[s.exited?, s.signaled?, s.stopped?, s.success?]")
+ end
+ end
+
+ def test_status_quit
+ return unless Process.respond_to?(:kill)
return unless Signal.list.include?("QUIT")
with_tmpchdir do
@@ -1206,16 +1223,14 @@ class TestProcess < Test::Unit::TestCase
end
t = Time.now
s = $?
- assert_equal([false, true, false],
- [s.exited?, s.signaled?, s.stopped?],
- "[s.exited?, s.signaled?, s.stopped?]")
+ assert_equal([false, true, false, nil],
+ [s.exited?, s.signaled?, s.stopped?, s.success?],
+ "[s.exited?, s.signaled?, s.stopped?, s.success?]")
assert_send(
[["#<Process::Status: pid #{ s.pid } SIGQUIT (signal #{ s.termsig })>",
"#<Process::Status: pid #{ s.pid } SIGQUIT (signal #{ s.termsig }) (core dumped)>"],
:include?,
s.inspect])
- assert_equal(false, s.exited?)
- assert_equal(nil, s.success?)
EnvUtil.diagnostic_reports("QUIT", RUBY, pid, t)
end
end
diff --git a/test/ruby/test_signal.rb b/test/ruby/test_signal.rb
index 60b886cec9..e329df9a34 100644
--- a/test/ruby/test_signal.rb
+++ b/test/ruby/test_signal.rb
@@ -268,4 +268,15 @@ EOS
}
}
end if Process.respond_to?(:kill) and Signal.list.key?('HUP')
+
+ def test_ignored_interrupt
+ bug9820 = '[ruby-dev:48203] [Bug #9820]'
+ assert_separately(['-', bug9820], <<-'end;') # begin
+ bug = ARGV.shift
+ trap(:INT, "IGNORE")
+ assert_nothing_raised(SignalException, bug) do
+ Process.kill(:INT, $$)
+ end
+ end;
+ end if Process.respond_to?(:kill)
end
diff --git a/thread.c b/thread.c
index b51698fc24..d9df90272e 100644
--- a/thread.c
+++ b/thread.c
@@ -5320,13 +5320,12 @@ ruby_kill(rb_pid_t pid, int sig)
{
int err;
rb_thread_t *th = GET_THREAD();
- rb_vm_t *vm = GET_VM();
/*
* When target pid is self, many caller assume signal will be
* delivered immediately and synchronously.
*/
- if ((sig != 0) && (th == vm->main_thread) && (pid == getpid())) {
+ {
GVL_UNLOCK_BEGIN();
native_mutex_lock(&th->interrupt_lock);
err = kill(pid, sig);
@@ -5334,9 +5333,7 @@ ruby_kill(rb_pid_t pid, int sig)
native_mutex_unlock(&th->interrupt_lock);
GVL_UNLOCK_END();
}
- else {
- err = kill(pid, sig);
- }
- if (err < 0)
+ if (err < 0) {
rb_sys_fail(0);
+ }
}
diff --git a/version.h b/version.h
index a68c8cdb54..d00d06a0a3 100644
--- a/version.h
+++ b/version.h
@@ -1,10 +1,10 @@
#define RUBY_VERSION "2.1.2"
-#define RUBY_RELEASE_DATE "2014-08-31"
-#define RUBY_PATCHLEVEL 216
+#define RUBY_RELEASE_DATE "2014-09-02"
+#define RUBY_PATCHLEVEL 217
#define RUBY_RELEASE_YEAR 2014
-#define RUBY_RELEASE_MONTH 8
-#define RUBY_RELEASE_DAY 31
+#define RUBY_RELEASE_MONTH 9
+#define RUBY_RELEASE_DAY 2
#include "ruby/version.h"