Skip to content

Commit

Permalink
Ruby 1.9 compatibility fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
FooBarWidget committed Nov 6, 2009
1 parent c4e1f22 commit de366a0
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 19 deletions.
71 changes: 58 additions & 13 deletions lib/daemon_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -501,32 +501,58 @@ def run_command(command)
File.chmod(0666, tempfile_path)
tempfile.close

if self.class.fork_supported?
pid = safe_fork do
ObjectSpace.each_object(IO) do |obj|
obj.close rescue nil
if self.class.fork_supported? || Process.respond_to?(:spawn)
if Process.respond_to?(:spawn)
pid = Process.spawn(command,
:in => "/dev/null",
:out => tempfile_path,
:err => tempfile_path,
:close_others => true
)
else
pid = safe_fork do
ObjectSpace.each_object(IO) do |obj|
obj.close rescue nil
end
STDIN.reopen("/dev/null", "r")
STDOUT.reopen(tempfile_path, "w")
STDERR.reopen(tempfile_path, "w")
exec(command)
end
STDIN.reopen("/dev/null", "r")
STDOUT.reopen(tempfile_path, "w")
STDERR.reopen(tempfile_path, "w")
exec(command)
end

# run_command might be running in a timeout block (like
# in #start_without_locking).
begin
Process.waitpid(pid) rescue nil
interruptable_waitpid(pid)
rescue Errno::ECHILD
# Maybe a background thread or whatever waitpid()'ed
# this child process before we had the chance. There's
# no way to obtain the exit status now. Assume that
# it started successfully; if it didn't we'll know
# that later by checking the PID file and by pinging
# it.
return
rescue Timeout::Error
# If the daemon doesn't fork into the background
# in time, then kill it.
Process.kill('SIGTERM', pid) rescue nil
begin
Process.kill('SIGTERM', pid)
rescue SystemCallError
end
begin
Timeout.timeout(5, Timeout::Error) do
Process.waitpid(pid) rescue nil
begin
interruptable_waitpid(pid)
rescue SystemCallError
end
end
rescue Timeout::Error
Process.kill('SIGKILL', pid)
Process.waitpid(pid) rescue nil
begin
Process.kill('SIGKILL', pid)
interruptable_waitpid(pid)
rescue SystemCallError
end
end
raise
end
Expand Down Expand Up @@ -578,4 +604,23 @@ def safe_fork
return pid
end
end

if RUBY_VERSION < "1.9"
def interruptable_waitpid(pid)
Process.waitpid(pid)
end
else
# On Ruby 1.9, Thread#kill (which is called by timeout.rb) may
# not be able to interrupt Process.waitpid. So here we use a
# special version that's a bit less efficient but is at least
# interruptable.
def interruptable_waitpid(pid)
result = nil
while !result
result = Process.waitpid(pid, Process::WNOHANG)
sleep 0.01 if !result
end
return result
end
end
end
6 changes: 3 additions & 3 deletions spec/daemon_controller_spec.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
require File.join(File.dirname(__FILE__), "test_helper")
require File.expand_path(File.join(File.dirname(__FILE__), "test_helper"))
require 'daemon_controller'
require 'benchmark'
require 'socket'
Expand Down Expand Up @@ -181,8 +181,8 @@
result = Benchmark.measure do
@controller.stop
end
@controller.running?.should be_false
(0.3 .. 0.5).should === result.real
@controller.should_not be_running
(0.3 .. 0.6).should === result.real
end

it "raises StopTimeout if the daemon does not stop in time" do
Expand Down
6 changes: 3 additions & 3 deletions spec/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@ def exec_is_slow?
# 'go!' method has been called.
class WaitingThread < Thread
def initialize
@mutex = Mutex.new
@cond = ConditionVariable.new
@go = false
super do
@mutex = Mutex.new
@cond = ConditionVariable.new
@go = false
@mutex.synchronize do
while !@go
@cond.wait(@mutex)
Expand Down

0 comments on commit de366a0

Please sign in to comment.