dumping ground for random patches and texts
 help / color / mirror / Atom feed
* [PATCH] make Process.kill(:STOP, $$) resumable
@ 2015-07-17  9:59 Eric Wong
  0 siblings, 0 replies; 3+ messages in thread
From: Eric Wong @ 2015-07-17  9:59 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.

Thus, we must rely on sighandler->timer_thread to signal
th->interrupt_cond when SIGCONT.

* signal.c (Init_signal): install sighandler for SIGCONT
* test/ruby/test_process.rb (test_stop_self_resumable): new test
---
 signal.c                  |  3 +++
 test/ruby/test_process.rb | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/signal.c b/signal.c
index 40caaa6..bc3ab4d 100644
--- a/signal.c
+++ b/signal.c
@@ -1456,6 +1456,9 @@ Init_signal(void)
 #ifdef SIGUSR2
     install_sighandler(SIGUSR2, sighandler);
 #endif
+#ifdef SIGCONT
+    install_sighandler(SIGCONT, sighandler);
+#endif
 
     if (!ruby_enable_coredump) {
 #ifdef SIGBUS
diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb
index 00bbf9e..d42a096 100644
--- a/test/ruby/test_process.rb
+++ b/test/ruby/test_process.rb
@@ -1341,6 +1341,43 @@ class TestProcess < Test::Unit::TestCase
     end
   end
 
+  def test_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)
+
+    (0..1).each do |n|
+      begin
+        pid = nil
+        Timeout.timeout(30) do
+          pid = fork do
+            # 2nd time we run this test, try with an explicit SIGCONT handler
+            case n
+            when 1
+              trap(:CONT) { n = 0 }
+            when 2
+              n = 0
+              trap(:CONT, 'IGNORE')
+            end
+
+            Process.kill(:STOP, $$)
+            exit(42 + n)
+          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
+    end
+  end
+
   def test_wait_without_arg
     with_tmpchdir do
       write_file("foo", "sleep 0.1")
-- 
EW


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH] make Process.kill(:STOP, $$) resumable
@ 2015-07-17 17:51 Eric Wong
  0 siblings, 0 replies; 3+ messages in thread
From: Eric Wong @ 2015-07-17 17:51 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.

Thus, we must rely on sighandler->timer_thread to signal
th->interrupt_cond when SIGCONT.

* signal.c (Init_signal): install sighandler for SIGCONT
* test/ruby/test_process.rb (test_stop_self_resumable): new test
---
 signal.c                  |  3 +++
 test/ruby/test_process.rb | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/signal.c b/signal.c
index 40caaa6..bc3ab4d 100644
--- a/signal.c
+++ b/signal.c
@@ -1456,6 +1456,9 @@ Init_signal(void)
 #ifdef SIGUSR2
     install_sighandler(SIGUSR2, sighandler);
 #endif
+#ifdef SIGCONT
+    install_sighandler(SIGCONT, sighandler);
+#endif
 
     if (!ruby_enable_coredump) {
 #ifdef SIGBUS
diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb
index 00bbf9e..d42a096 100644
--- a/test/ruby/test_process.rb
+++ b/test/ruby/test_process.rb
@@ -1341,6 +1341,43 @@ class TestProcess < Test::Unit::TestCase
     end
   end
 
+  def test_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)
+
+    (0..1).each do |n|
+      begin
+        pid = nil
+        Timeout.timeout(30) do
+          pid = fork do
+            # 2nd time we run this test, try with an explicit SIGCONT handler
+            case n
+            when 1
+              trap(:CONT) { n = 0 }
+            when 2
+              n = 0
+              trap(:CONT, 'IGNORE')
+            end
+
+            Process.kill(:STOP, $$)
+            exit(42 + n)
+          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
+    end
+  end
+
   def test_wait_without_arg
     with_tmpchdir do
       write_file("foo", "sleep 0.1")
-- 
EW


^ permalink raw reply related	[flat|nested] 3+ messages in thread

* [PATCH] make Process.kill(:STOP, $$) resumable
@ 2015-07-17 17:51 Eric Wong
  0 siblings, 0 replies; 3+ messages in thread
From: Eric Wong @ 2015-07-17 17:51 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.

Thus, we must rely on sighandler->timer_thread to signal
th->interrupt_cond when SIGCONT resumes the process.

* signal.c (Init_signal): install sighandler for SIGCONT
* test/ruby/test_process.rb (test_stop_self_resumable): new test
---
 signal.c                  |  3 +++
 test/ruby/test_process.rb | 37 +++++++++++++++++++++++++++++++++++++
 2 files changed, 40 insertions(+)

diff --git a/signal.c b/signal.c
index 40caaa6..bc3ab4d 100644
--- a/signal.c
+++ b/signal.c
@@ -1456,6 +1456,9 @@ Init_signal(void)
 #ifdef SIGUSR2
     install_sighandler(SIGUSR2, sighandler);
 #endif
+#ifdef SIGCONT
+    install_sighandler(SIGCONT, sighandler);
+#endif
 
     if (!ruby_enable_coredump) {
 #ifdef SIGBUS
diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb
index 00bbf9e..d42a096 100644
--- a/test/ruby/test_process.rb
+++ b/test/ruby/test_process.rb
@@ -1341,6 +1341,43 @@ class TestProcess < Test::Unit::TestCase
     end
   end
 
+  def test_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)
+
+    (0..1).each do |n|
+      begin
+        pid = nil
+        Timeout.timeout(30) do
+          pid = fork do
+            # 2nd time we run this test, try with an explicit SIGCONT handler
+            case n
+            when 1
+              trap(:CONT) { n = 0 }
+            when 2
+              n = 0
+              trap(:CONT, 'IGNORE')
+            end
+
+            Process.kill(:STOP, $$)
+            exit(42 + n)
+          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
+    end
+  end
+
   def test_wait_without_arg
     with_tmpchdir do
       write_file("foo", "sleep 0.1")
-- 
EW


^ permalink raw reply related	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2015-07-17 17:51 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-07-17  9:59 [PATCH] make Process.kill(:STOP, $$) resumable Eric Wong
  -- strict thread matches above, loose matches on Subject: below --
2015-07-17 17:51 Eric Wong
2015-07-17 17:51 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).