diff options
author | danielsdeleo <dan@getchef.com> | 2014-03-31 10:24:50 -0700 |
---|---|---|
committer | danielsdeleo <dan@getchef.com> | 2014-03-31 10:24:50 -0700 |
commit | 6faa04e8c173e5c1f029a0d378c991a9a908dc36 (patch) | |
tree | e291ec19b3cab03688274122452b068df5fdf516 | |
parent | a6b9916767825b0902059e72025b7e649c61d7fd (diff) | |
download | mixlib-shellout-6faa04e8c173e5c1f029a0d378c991a9a908dc36.tar.gz |
Handle ESRCH when getting pgid of a zombie on OS X
-rw-r--r-- | CHANGELOG.md | 1 | ||||
-rw-r--r-- | lib/mixlib/shellout/unix.rb | 18 | ||||
-rw-r--r-- | spec/mixlib/shellout_spec.rb | 19 |
3 files changed, 37 insertions, 1 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bfb831..e1495ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,5 +6,6 @@ * Enabled travis. * Added error? to check if the command ran successfully. MIXLIB-18. * Remove GC.disable hack for non-ruby 1.8.8 +* Handle ESRCH from getpgid of a zombie on OS X ## Last Release: 1.3.0 (12/03/2013) diff --git a/lib/mixlib/shellout/unix.rb b/lib/mixlib/shellout/unix.rb index e8aa26e..03f619b 100644 --- a/lib/mixlib/shellout/unix.rb +++ b/lib/mixlib/shellout/unix.rb @@ -63,7 +63,7 @@ module Mixlib # CHEF-3390: Marshall.load on Ruby < 1.8.7p369 also has a GC bug related # to Marshall.load, so try disabling GC first. propagate_pre_exec_failure - @child_pgid = -Process.getpgid(@child_pid) + get_child_pgid @result = nil @execution_time = 0 @@ -107,6 +107,18 @@ module Mixlib private + def get_child_pgid + # The behavior of Process.getpgid (see also getpgid(2) ) when the + # argument is the pid of a zombie isn't well specified. On Linux it + # works, on OS X it returns ESRCH (which ruby turns into Errno::ESRCH). + # + # If the child dies very quickly, @child_pid may be a zombie, so handle + # ESRCH here. + @child_pgid = -Process.getpgid(@child_pid) + rescue Errno::ESRCH + @child_pgid = nil + end + def set_user if user Process.euid = uid @@ -137,6 +149,10 @@ module Mixlib # Process group id of the child. Returned as a negative value so you can # put it directly in arguments to kill, wait, etc. + # + # This may be nil if the child dies before the parent can query the + # system for its pgid (on some systems it is an error to get the pgid of + # a zombie). def child_pgid @child_pgid end diff --git a/spec/mixlib/shellout_spec.rb b/spec/mixlib/shellout_spec.rb index 42f2714..03bb47b 100644 --- a/spec/mixlib/shellout_spec.rb +++ b/spec/mixlib/shellout_spec.rb @@ -843,6 +843,25 @@ describe Mixlib::ShellOut do end end + context "when the child process dies immediately" do + let(:cmd) { [ 'exit' ] } + + it "handles ESRCH from getpgid of a zombie" do + Process.stub(:setsid) { exit!(4) } + + # there is a small race condition here if the child doesn't get + # scheduled and call exit! before the parent can call getpgid, so run + # this a few times to make sure we've created the reproduction case + # correctly. + 5.times do + s = Mixlib::ShellOut.new(cmd) + s.run_command # should not raise Errno::ESRCH + end + + end + + end + context 'with subprocess that takes longer than timeout' do def ruby_wo_shell(code) parts = %w[ruby] |