From 3661dae19c734f8c0c63db08b150c90c04ec338a Mon Sep 17 00:00:00 2001
From: normal <normal@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>
Date: Sat, 18 Jul 2015 01:29:25 +0000
Subject: [PATCH] test/ruby/test_process.rb: test thread+sigs work after failed
 exec

Preparation for possible upcoming changes to timer thread.  We need
to ensure signal handling and thread scheduling works after an exec
failure.

git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51289 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
---
 ChangeLog                 |  4 +++
 test/ruby/test_process.rb | 70 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 74 insertions(+)

diff --git a/ChangeLog b/ChangeLog
index 23ff695178..de79d76ede 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Sat Jul 18 10:29:03 2015  Eric Wong  <e@80x24.org>
+
+	* test/ruby/test_process.rb: test thread+sigs work after failed exec
+
 Sat Jul 18 07:20:18 2015  Jeremy Evans  <code@jeremyevans.net>
 
 	* test/socket/test_nonblock: use smaller buffer for sendmsg
diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb
index 00bbf9ee0b..80dc3446e5 100644
--- a/test/ruby/test_process.rb
+++ b/test/ruby/test_process.rb
@@ -2092,4 +2092,74 @@ EOS
       end
     }
   end
+
+  def test_signals_work_after_exec_fail
+    r, w = IO.pipe
+    pid = status = nil
+    Timeout.timeout(30) do
+      pid = fork do
+        r.close
+        begin
+          trap(:USR1) { w.syswrite("USR1\n"); exit 0 }
+          exec "/path/to/non/existent/#$$/#{rand}.ex"
+        rescue SystemCallError
+          w.syswrite("exec failed\n")
+        end
+        sleep
+        exit 1
+      end
+      w.close
+      assert_equal "exec failed\n", r.gets
+      Process.kill(:USR1, pid)
+      assert_equal "USR1\n", r.gets
+      assert_nil r.gets
+      _, status = Process.waitpid2(pid)
+    end
+    assert_predicate status, :success?
+  rescue Timeout::Error
+    begin
+      Process.kill(:KILL, pid)
+    rescue Errno::ESRCH
+    end
+    raise
+  ensure
+    w.close if w
+    r.close if r
+  end if defined?(fork)
+
+  def test_threading_works_after_exec_fail
+    r, w = IO.pipe
+    pid = status = nil
+    Timeout.timeout(30) do
+      pid = fork do
+        r.close
+        begin
+          exec "/path/to/non/existent/#$$/#{rand}.ex"
+        rescue SystemCallError
+          w.syswrite("exec failed\n")
+        end
+        run = true
+        th1 = Thread.new { i = 0; i += 1 while run; i }
+        th2 = Thread.new { j = 0; j += 1 while run && Thread.pass.nil?; j }
+        sleep 0.5
+        run = false
+        w.syswrite "#{th1.value} #{th2.value}\n"
+      end
+      w.close
+      assert_equal "exec failed\n", r.gets
+      vals = r.gets.chomp.split.map!(&:to_i)
+      assert_operator vals[0], :>, vals[1], vals.inspect
+      _, status = Process.waitpid2(pid)
+    end
+    assert_predicate status, :success?
+  rescue Timeout::Error
+    begin
+      Process.kill(:KILL, pid)
+    rescue Errno::ESRCH
+    end
+    raise
+  ensure
+    w.close if w
+    r.close if r
+  end if defined?(fork)
 end