Last active
December 14, 2015 20:18
-
-
Save clicube/5142446 to your computer and use it in GitHub Desktop.
Process::Process class
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module Process | |
class ProcessError < StandardError; end | |
class Process | |
attr_reader :pid | |
def initialize(*args, &block) | |
raise ArgumentError.new("block must be given") unless block_given? | |
@parent_pid = ::Process.pid | |
@pid = fork{ block.call *args } | |
@watching_thread = ::Process.detach(@pid) # avoid to be a zombie | |
end | |
def signal sig | |
::Process.kill sig, @pid | |
true | |
rescue Errno::ESRCH | |
false | |
end | |
def exist? | |
signal 0 | |
end | |
def kill | |
signal :KILL | |
end | |
def term | |
signal :TERM | |
end | |
def child? | |
@parent_pid == ::Process.pid | |
end | |
def alive? | |
if @watching_thread.alive? | |
true | |
elsif child? | |
false | |
else | |
exist? | |
end | |
end | |
def join limit=nil | |
raise ProcessError.new("not a child process") unless child? | |
retval = limit ? @watching_thread.join(limit) : @watching_thread.join | |
retval ? self : nil | |
end | |
alias :wait :join | |
def value | |
raise ProcessError.new("not a child process") unless child? | |
@watching_thread.value | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'test/unit' | |
require 'timeout' | |
require_relative 'process' | |
class TestProcess < Test::Unit::TestCase | |
def test_process_initialize | |
assert_nothing_raised{ | |
Process::Process.new{ :nop } | |
} | |
assert_raise(ArgumentError){ | |
Process::Process.new | |
} | |
end | |
def test_process_block_is_processed | |
pout, pin = IO.pipe | |
p = Process::Process.new{ pin.write "a" } | |
buf = nil | |
assert_nothing_raised(TimeoutError){ | |
timeout(1){ buf = pout.read(1) } | |
} | |
assert_equal "a", buf | |
end | |
def test_process_pid | |
p = Process::Process.new{ :nop } | |
assert p.pid.is_a? Integer | |
assert p.pid > 1 | |
assert_not_equal Process.pid, p.pid | |
end | |
def test_process_signal_and_exist? | |
p = Process::Process.new{ sleep 1 } | |
assert_equal true, p.exist? | |
retval = p.signal :TERM | |
assert_equal true, retval | |
sleep 0.1 | |
assert_equal false, p.exist? | |
retval = p.signal :TERM | |
assert_equal false, retval | |
end | |
def test_process_term | |
p = Process::Process.new{ sleep 1 } | |
retval = p.term | |
assert_equal true, retval | |
sleep 0.1 | |
assert_equal false, p.exist? | |
retval = p.term | |
assert_equal false, retval | |
end | |
def test_process_kill | |
p = Process::Process.new{ sleep 1 } | |
retval = p.kill | |
assert_equal true, retval | |
sleep 0.1 | |
assert_equal false, p.exist? | |
retval = p.kill | |
assert_equal false, retval | |
end | |
def test_process_child? | |
p = Process::Process.new{ sleep 1 } | |
assert_equal true, p.child? | |
pout, pin = IO.pipe | |
fork{ pin.write( p.child? ? "T" : "F" ) } | |
result = nil | |
timeout(1){ result = pout.read(1) } | |
assert_equal "F", result | |
end | |
def test_process_alive? | |
p = Process::Process.new{ sleep 1 } | |
assert_equal true, p.alive? | |
p.term | |
sleep 0.1 | |
assert_equal false, p.alive? | |
p = Process::Process.new{ sleep 1 } | |
pout, pin = IO.pipe | |
fork{ pin.write( p.alive? ? "T" : "F" ) } | |
result = nil | |
timeout(1){ result = pout.read(1) } | |
assert_equal "T", result | |
p.term | |
sleep 0.1 | |
fork{ pin.write( p.alive? ? "T" : "F" ) } | |
result = nil | |
timeout(1){ result = pout.read(1) } | |
assert_equal "F", result | |
end | |
def test_process_join | |
p = Process::Process.new{ sleep 1 } | |
assert_raise(TimeoutError){ | |
timeout(0.1){ p.join } | |
} | |
p = Process::Process.new{ sleep 0.1 } | |
retval = nil | |
timeout(1){ retval = p.join } | |
assert_equal p, retval | |
p = Process::Process.new{ :nop } | |
retval = nil | |
timeout(1){ retval = p.join } | |
assert_equal p, retval | |
p = Process::Process.new{ sleep 2 } | |
retval = true | |
timeout(1){ retval = p.join(0) } | |
assert_equal nil, retval | |
p = Process::Process.new{ sleep 1 } | |
pout, pin = IO.pipe | |
fork do | |
result = "P" | |
begin | |
p.join | |
rescue Process::ProcessError | |
result = "E" | |
rescue | |
end | |
pin.write result | |
end | |
result = nil | |
timeout(1){ result = pout.read(1) } | |
assert_equal "E", result | |
end | |
def test_process_value | |
p = Process::Process.new{ sleep 1 } | |
assert_raise(TimeoutError){ | |
timeout(0.1){ p.value } | |
} | |
p = Process::Process.new{ sleep 0.1; exit 0} | |
retval = nil | |
timeout(1){ retval = p.value } | |
assert retval.is_a? Process::Status | |
assert_equal true, retval.success? | |
p = Process::Process.new{ sleep 0.1; exit 1} | |
retval = nil | |
timeout(1){ retval = p.value } | |
assert retval.is_a? Process::Status | |
assert_equal false, retval.success? | |
p = Process::Process.new{ sleep 1 } | |
pout, pin = IO.pipe | |
fork do | |
result = "P" | |
begin | |
p.value | |
rescue Process::ProcessError | |
result = "E" | |
rescue | |
end | |
pin.write result | |
end | |
result = nil | |
timeout(1){ result = pout.read(1) } | |
assert_equal "E", result | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment