dumping ground for random patches and texts
 help / color / mirror / Atom feed
* [PATCH] ensure Process.kill(:STOP, $$) is resumable
@ 2015-07-17  9:22 Eric Wong
  0 siblings, 0 replies; only message in thread
From: Eric Wong @ 2015-07-17  9:22 UTC (permalink / raw)
  To: spew

Self-inflicted signals are delivered immediately.  This is fine
for most signals which are catchable, but SIGSTOP and SIGKILL
are special and cannot be caught by a userspace process.

SIGKILL is easy, the process will die immediately and we won't
care for it.  However, SIGSTOP is tricky because we cannot know
when it is delivered.  Try to improve the situation by allowing
the OS to reschedule our thread by calling native_thread_yield().

* thread.c (ruby_kill): do not sleep forever on SIGSTOP
---
 test/ruby/test_process.rb | 23 +++++++++++++++++++++++
 thread.c                  | 16 +++++++++++++++-
 2 files changed, 38 insertions(+), 1 deletion(-)

diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb
index 00bbf9e..fa84a9f 100644
--- a/test/ruby/test_process.rb
+++ b/test/ruby/test_process.rb
@@ -1341,6 +1341,29 @@ class TestProcess < Test::Unit::TestCase
     end
   end
 
+  def test_status_stop_self_resumable
+    skip "kill not supported" unless Process.respond_to?(:kill)
+    skip "fork not supported" unless Process.respond_to?(:fork)
+    skip "SIGSTOP not supported" unless Signal.list.include?("STOP")
+    skip "WUNTRACED not defined" unless Process.const_defined?(:WUNTRACED)
+    pid = nil
+    Timeout.timeout(30) do
+      pid = fork do
+        Process.kill(:STOP, $$)
+        exit(42)
+      end
+      _, s = Process.waitpid2(pid, Process::WUNTRACED)
+      assert_predicate s, :stopped?
+      Process.kill(:CONT, pid)
+      _, s = Process.waitpid2(pid)
+      assert_predicate s, :exited?
+      assert_equal 42, s.exitstatus
+    end
+  rescue Timeout::Error
+    Process.kill(:KILL, pid) if pid
+    raise
+  end
+
   def test_wait_without_arg
     with_tmpchdir do
       write_file("foo", "sleep 0.1")
diff --git a/thread.c b/thread.c
index 1d550ef..f0da75d 100644
--- a/thread.c
+++ b/thread.c
@@ -5262,6 +5262,11 @@ ruby_kill(rb_pid_t pid, int sig)
 {
     int err;
     rb_thread_t *th = GET_THREAD();
+#ifdef SIGSTOP
+    int sigstop = sig == SIGSTOP;
+#else
+    int sigstop = 0;
+#endif
 
     /*
      * When target pid is self, many caller assume signal will be
@@ -5271,7 +5276,16 @@ ruby_kill(rb_pid_t pid, int sig)
 	GVL_UNLOCK_BEGIN();
 	native_mutex_lock(&th->interrupt_lock);
 	err = kill(pid, sig);
-	native_cond_wait(&th->interrupt_cond, &th->interrupt_lock);
+	if (sigstop) {
+	    /*
+	     * best effort to try to receive SIGSTOP ASAP,
+	     * maybe we need to yield several more times.
+	     */
+	    native_thread_yield();
+	}
+	else { /* sig is SIGKILL, SIGSEGV, or SIGBUS: wait to die */
+	    native_cond_wait(&th->interrupt_cond, &th->interrupt_lock);
+	}
 	native_mutex_unlock(&th->interrupt_lock);
 	GVL_UNLOCK_END();
     }
-- 
EW


^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2015-07-17  9:22 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-17  9:22 [PATCH] ensure Process.kill(:STOP, $$) is resumable Eric Wong

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).