# -*- ruby -*- # # This library is used to create a child process and pipes # send and receive data. We can send ruby codes and receive # results using an instance of PRuby. # # ex) # PRuby.new{|r| # r.send("somecode") # "somecode" is executed in the child process. # timeout(5){ r.recv } # } # # r = PRuby.new # r.send("somecode") # result = r.recv # class PRuby CRLF = "\r\n" def initialize if( block_given? ) begin init_io yield(self) ensure terminate end else init_io end end def init_io @p2c_in,@p2c_out = IO.pipe() @c2p_in,@c2p_out = IO.pipe() @pid = fork{ @p2c_out.close @c2p_in.close child_loop() } @p2c_in.close @c2p_out.close at_exit{ if( !@p2c_out.closed? ) @p2c_out.print("killed", CRLF) @p2c_out.flush end } end def kill(sig) Process.kill(sig, @pid) end def wait Process.waitpid(@pid) end def closed? return @c2p_in.closed? end def close @c2p_in.close @p2c_out.close end def terminate close kill("SIGTERM") wait end def recv() if( num = @c2p_in.gets ) case num when /\d+/ num = num.chop.to_i else @p2c_out.close @c2p_in.close num = nil end if( num ) mval = @c2p_in.read(num) val = Marshal.load(mval) else val = nil end else val = nil end return val end def send(line) @p2c_out.print(line.size, CRLF) @p2c_out.print(line) @p2c_out.flush end def eval(line) send(line) return recv() end def child_loop at_exit{ if( !@c2p_out.closed? ) @c2p_out.print("killed", CRLF) @c2p_out.flush end } while( !@p2c_in.closed? && (num = @p2c_in.gets) ) case num when /\d+/ num = num.chop.to_i else num = nil end if( num ) script = @p2c_in.read(num) val = Kernel.module_eval(script) mval = Marshal.dump(val) @c2p_out.print(mval.size, CRLF) @c2p_out.print(mval) @c2p_out.flush else @c2p_out.close @p2c_in.close end end end end