lib/posixpsutil/common.rb
def wait_pid(pid, timeout=nil)

  def check_timeout(delay, stop_at, timeout)
    if timeout
      raise Timeout::Error.new("when waiting for (pid=#{pid})") if Time.now >= stop_at
    end
    sleep(delay)
    delay * 2 < 0.04 ? delay * 2 : 0.04
  end

  if timeout
    waitcall = proc { ::Process.wait(pid, ::Process::WNOHANG)}
    stop_at = Time.now + timeout
  else
    waitcall = proc { ::Process.wait(pid)}
  end

  delay = 0.0001
  loop do
    begin
      retpid = waitcall.call()
    rescue Errno::EINTR
      delay = check_timeout(delay, stop_at, timeout)
      next
    rescue Errno::ECHILD
      # This has two meanings:
      # - pid is not a child of Process.pid in which case
      #   we keep polling until it's gone
      # - pid never existed in the first place
      # In both cases we'll eventually return nil as we
      # can't determine its exit status code.
      loop do
        return nil unless pid_exists(pid)
        delay = check_timeout(delay, stop_at, timeout)
      end
    end

    unless retpid
      # WNOHANG was used, pid is still running
      delay = check_timeout(delay, stop_at, timeout)
      next
    end

    # process exited due to a signal; return the integer of
    # that signal
    if $?.signaled?
      return $?.termsig
    # process exited using exit(2) system call; return the
    # integer exit(2) system call has been called with
    elsif $?.exited?
      return $?.exitstatus
    else
      # should never happen
      raise RuntimeError.new("unknown process exit status")
    end
  end
end
def wait_pid(pid, timeout=nil)

  def check_timeout(delay, stop_at, timeout)
    if timeout
      raise Timeout::Error.new("when waiting for (pid=#{pid})") if Time.now >= stop_at
    end
    sleep(delay)
    delay * 2 < 0.04 ? delay * 2 : 0.04
  end

  if timeout
    waitcall = proc { ::Process.wait(pid, ::Process::WNOHANG)}
    stop_at = Time.now + timeout
  else
    waitcall = proc { ::Process.wait(pid)}
  end

  delay = 0.0001
  loop do
    begin
      retpid = waitcall.call()
    rescue Errno::EINTR
      delay = check_timeout(delay, stop_at, timeout)
      next
    rescue Errno::ECHILD
      # This has two meanings:
      # - pid is not a child of Process.pid in which case
      #   we keep polling until it's gone
      # - pid never existed in the first place
      # In both cases we'll eventually return nil as we
      # can't determine its exit status code.
      loop do
        return nil unless pid_exists(pid)
        delay = check_timeout(delay, stop_at, timeout)
      end
    end

    unless retpid
      # WNOHANG was used, pid is still running
      delay = check_timeout(delay, stop_at, timeout)
      next
    end

    # process exited due to a signal; return the integer of
    # that signal
    if $?.signaled?
      return $?.termsig
    # process exited using exit(2) system call; return the
    # integer exit(2) system call has been called with
    elsif $?.exited?
      return $?.exitstatus
    else
      # should never happen
      raise RuntimeError.new("unknown process exit status")
    end
  end
end
Wait for process with pid 'pid' to terminate and return its
 exit status code as an integer.

 If pid is not a children of Process.pid (current process) just
 waits until the process disappears and return nil.

 If pid does not exist at all return nil immediately.

 Raise Timeout::Error on timeout expired.