Sha256: b397eaf0f00ba87eeb8c036300cd7bbc05356277d88949bdbdd63e322041007a

Contents?: true

Size: 1.88 KB

Versions: 3

Compression:

Stored size: 1.88 KB

Contents

# A helper class that allows you to run a block inside of a fork, and then get the result from that block.
#
# == Example:
#
#   forker = Spork::Forker.new do
#     sleep 3
#     "success"
#   end
#
#   forker.result # => "success"
class Spork::Forker

  # Raised if the fork died (was killed) before it sent it's response back.
  class ForkDiedException < Exception; end
  def initialize(&block)
    return unless block_given?
    @child_io, @server_io = UNIXSocket.socketpair
    @child_pid = Kernel.fork do
      begin
        @server_io.close
        Marshal.dump(yield, @child_io)
        # wait for the parent to acknowledge receipt of the result.
        master_response = Marshal.load(@child_io)
      rescue EOFError
        nil
      rescue SystemExit => e
        puts "Error: exit code #{e.status}" unless e.status == 0
      rescue Exception => e
        puts "Exception encountered: #{e.inspect}\nbacktrace:\n#{e.backtrace * %(\n)}"
      end

      # terminate, skipping any at_exit blocks.
      exit!(0)
    end
    @child_io.close
  end

  # Wait for the fork to finish running, and then return its return value.
  #
  # If the fork was aborted, then result returns nil.
  def result
    return @result if defined?(@result) || ! running?
    result_thread = Thread.new do
      begin
        @result = Marshal.load(@server_io)
        Marshal.dump('ACK', @server_io)
      rescue EOFError
        @result = nil
      rescue ForkDiedException
      end
    end
    Process.wait(@child_pid)
    result_thread.raise(ForkDiedException) if result_thread.status == "sleep"
    @child_pid = nil
    @result
  end

  # abort the current running fork
  def abort
    if running?
      Process.kill(Signal.list['TERM'], @child_pid)
      @child_pid = nil
      true
    end
  end

  def running?
    return false unless @child_pid
    Process.getpgid(@child_pid)
    true
  rescue Errno::ESRCH
    false
  end
end

Version data entries

3 entries across 3 versions & 1 rubygems

Version Path
spork-1.0.0rc4 lib/spork/forker.rb
spork-1.0.0rc4-x86-mswin32 lib/spork/forker.rb
spork-1.0.0rc4-x86-mingw32 lib/spork/forker.rb