Module: PosixPsutil::POSIX

Included in:
Process
Defined in:
lib/posixpsutil/common.rb

Overview

this module places helper functions used in all posix platform Process implementions

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.pid_exists(pid) ⇒ Object

Check whether pid exists in the current process table.“”“



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/posixpsutil/common.rb', line 94

def pid_exists(pid)
  return false if pid < 0
  # According to "man 2 kill" PID 0 has a special meaning:
  # it refers to <<every process in the process group of the
  # calling process>> so we don't want to go any further.
  # If we get here it means this UNIX platform *does* have
  # a process with id 0.
  return true if pid == 0

  ::Process.kill(0, pid)
  return true
  rescue Errno::ESRCH # No such process
    return false
  rescue Errno::EPERM
    # EPERM clearly means there's a process to deny access to
    return true
  rescue RangeError # the given pid is invalid.
    return false
end

Instance Method Details

#check_timeout(delay, stop_at, timeout) ⇒ Object



126
127
128
129
130
131
132
# File 'lib/posixpsutil/common.rb', line 126

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

#wait_pid(pid, timeout = nil) ⇒ Object

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.



124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
# File 'lib/posixpsutil/common.rb', line 124

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