Module: Process
- Defined in:
- process.c,
process.c
Overview
Module Process
represents a process in the underlying operating system. Its methods support management of the current process and its child processes.
Process Creation
Each of the following methods executes a given command in a new process or subshell, or multiple commands in new processes and/or subshells. The choice of process or subshell depends on the form of the command; see Argument command_line or exe_path.
-
Process.spawn, Kernel#spawn: Executes the command; returns the new pid without waiting for completion.
-
Process.exec: Replaces the current process by executing the command.
In addition:
-
Method Kernel#system executes a given command-line (string) in a subshell; returns
true
,false
, ornil
. -
Method Kernel#‘ executes a given command-line (string) in a subshell; returns its $stdout string.
-
Module Open3 supports creating child processes with access to their $stdin, $stdout, and $stderr streams.
Execution Environment
Optional leading argument env
is a hash of name/value pairs, where each name is a string and each value is a string or nil
; each name/value pair is added to ENV in the new process.
Process.spawn( 'ruby -e "p ENV[\"Foo\"]"')
Process.spawn({'Foo' => '0'}, 'ruby -e "p ENV[\"Foo\"]"')
Output:
"0"
The effect is usually similar to that of calling ENV#update with argument env
, where each named environment variable is created or updated (if the value is non-nil
), or deleted (if the value is nil
).
However, some modifications to the calling process may remain if the new process fails. For example, hard resource limits are not restored.
Argument command_line
or exe_path
The required string argument is one of the following:
-
command_line
if it begins with a shell reserved word or special built-in, or if it contains one or more meta characters. -
exe_path
otherwise.
Argument command_line
String argument command_line
is a command line to be passed to a shell; it must begin with a shell reserved word, begin with a special built-in, or contain meta characters:
system('if true; then echo "Foo"; fi') # => true # Shell reserved word.
system('echo') # => true # Built-in.
system('date > /tmp/date.tmp') # => true # Contains meta character.
system('date > /nop/date.tmp') # => false
system('date > /nop/date.tmp', exception: true) # Raises RuntimeError.
The command line may also contain arguments and options for the command:
system('echo "Foo"') # => true
Output:
Foo
See Execution Shell for details about the shell.
Argument exe_path
Argument exe_path
is one of the following:
-
The string path to an executable to be called.
-
A 2-element array containing the path to an executable to be called, and the string to be used as the name of the executing process.
Example:
system('/usr/bin/date') # => true # Path to date on Unix-style system.
system('foo') # => nil # Command failed.
Output:
Mon Aug 28 11:43:10 AM CDT 2023
Execution Options
Optional trailing argument options
is a hash of execution options.
Working Directory (:chdir
)
By default, the working directory for the new process is the same as that of the current process:
Dir.chdir('/var')
Process.spawn('ruby -e "puts Dir.pwd"')
Output:
/var
Use option :chdir
to set the working directory for the new process:
Process.spawn('ruby -e "puts Dir.pwd"', {chdir: '/tmp'})
Output:
/tmp
The working directory of the current process is not changed:
Dir.pwd # => "/var"
File Redirection (File Descriptor)
Use execution options for file redirection in the new process.
The key for such an option may be an integer file descriptor (fd), specifying a source, or an array of fds, specifying multiple sources.
An integer source fd may be specified as:
-
n: Specifies file descriptor n.
There are these shorthand symbols for fds:
-
:in
: Specifies file descriptor 0 (STDIN). -
:out
: Specifies file descriptor 1 (STDOUT). -
:err
: Specifies file descriptor 2 (STDERR).
The value given with a source is one of:
-
n: Redirects to fd n in the parent process.
-
filepath
: Redirects from or to the file atfilepath
viaopen(filepath, mode, 0644)
, wheremode
is'r'
for source:in
, or'w'
for source:out
or:err
. -
[filepath]
: Redirects from the file atfilepath
viaopen(filepath, 'r', 0644)
. -
[filepath, mode]
: Redirects from or to the file atfilepath
viaopen(filepath, mode, 0644)
. -
[filepath, mode, perm]
: Redirects from or to the file atfilepath
viaopen(filepath, mode, perm)
. -
[:child, fd]
: Redirects to the redirectedfd
. -
:close
: Closes the file descriptor in child process.
See Access Modes and File Permissions.
Environment Variables (:unsetenv_others
)
By default, the new process inherits environment variables from the parent process; use execution option key :unsetenv_others
with value true
to clear environment variables in the new process.
Any changes specified by execution option env
are made after the new process inherits or clears its environment variables; see Execution Environment.
File-Creation Access (:umask
)
Use execution option :umask
to set the file-creation access for the new process; see Access Modes:
command = 'ruby -e "puts sprintf(\"0%o\", File.umask)"'
= {:umask => 0644}
Process.spawn(command, )
Output:
0644
Process Groups (:pgroup
and :new_pgroup
)
By default, the new process belongs to the same process group as the parent process.
To specify a different process group. use execution option :pgroup
with one of the following values:
-
true
: Create a new process group for the new process. -
pgid: Create the new process in the process group whose id is pgid.
On Windows only, use execution option :new_pgroup
with value true
to create a new process group for the new process.
Resource Limits
Use execution options to set resource limits.
The keys for these options are symbols of the form :rlimit_resource_name
, where resource_name is the downcased form of one of the string resource names described at method Process.setrlimit. For example, key :rlimit_cpu
corresponds to resource limit 'CPU'
.
The value for such as key is one of:
-
An integer, specifying both the current and maximum limits.
-
A 2-element array of integers, specifying the current and maximum limits.
File Descriptor Inheritance
By default, the new process inherits file descriptors from the parent process.
Use execution option :close_others => true
to modify that inheritance by closing non-standard fds (3 and greater) that are not otherwise redirected.
Execution Shell
On a Unix-like system, the shell invoked is /bin/sh
; otherwise the shell invoked is determined by environment variable ENV['RUBYSHELL']
, if defined, or ENV['COMSPEC']
otherwise.
Except for the COMSPEC
case, the entire string command_line
is passed as an argument to shell option -c.
The shell performs normal shell expansion on the command line:
spawn('echo C*') # => 799139
Process.wait # => 799139
Output:
CONTRIBUTING.md COPYING COPYING.ja
What’s Here
Current-Process Getters
-
::argv0: Returns the process name as a frozen string.
-
::egid: Returns the effective group ID.
-
::euid: Returns the effective user ID.
-
::getpgrp: Return the process group ID.
-
::getrlimit: Returns the resource limit.
-
::gid: Returns the (real) group ID.
-
::pid: Returns the process ID.
-
::ppid: Returns the process ID of the parent process.
-
::uid: Returns the (real) user ID.
Current-Process Setters
-
::egid=: Sets the effective group ID.
-
::euid=: Sets the effective user ID.
-
::gid=: Sets the (real) group ID.
-
::setproctitle: Sets the process title.
-
::setpgrp: Sets the process group ID of the process to zero.
-
::setrlimit: Sets a resource limit.
-
::setsid: Establishes the process as a new session and process group leader, with no controlling tty.
-
::uid=: Sets the user ID.
Current-Process Execution
-
::abort: Immediately terminates the process.
-
::daemon: Detaches the process from its controlling terminal and continues running it in the background as system daemon.
-
::exec: Replaces the process by running a given external command.
-
::exit: Initiates process termination by raising exception SystemExit (which may be caught).
-
::exit!: Immediately exits the process.
-
::warmup: Notifies the Ruby virtual machine that the boot sequence for the application is completed, and that the VM may begin optimizing the application.
Child Processes
-
::detach: Guards against a child process becoming a zombie.
-
::fork: Creates a child process.
-
::kill: Sends a given signal to processes.
-
::spawn: Creates a child process.
-
::wait, ::waitpid: Waits for a child process to exit; returns its process ID.
-
::wait2, ::waitpid2: Waits for a child process to exit; returns its process ID and status.
-
::waitall: Waits for all child processes to exit; returns their process IDs and statuses.
Process Groups
-
::getpgid: Returns the process group ID for a process.
-
::getpriority: Returns the scheduling priority for a process, process group, or user.
-
::getsid: Returns the session ID for a process.
-
::groups: Returns an array of the group IDs in the supplemental group access list for this process.
-
::groups=: Sets the supplemental group access list to the given array of group IDs.
-
::initgroups: Initializes the supplemental group access list.
-
::last_status: Returns the status of the last executed child process in the current thread.
-
::maxgroups: Returns the maximum number of group IDs allowed in the supplemental group access list.
-
::maxgroups=: Sets the maximum number of group IDs allowed in the supplemental group access list.
-
::setpgid: Sets the process group ID of a process.
-
::setpriority: Sets the scheduling priority for a process, process group, or user.
Timing
-
::clock_getres: Returns the resolution of a system clock.
-
::clock_gettime: Returns the time from a system clock.
-
::times: Returns a Process::Tms object containing times for the current process and its child processes.
Defined Under Namespace
Modules: GID, Sys, UID Classes: Status, Tms, Waiter
Constant Summary collapse
- WNOHANG =
see Process.wait
INT2FIX(0)
- WUNTRACED =
see Process.wait
INT2FIX(0)
- PRIO_PROCESS =
see Process.setpriority
INT2FIX(PRIO_PROCESS)
- PRIO_PGRP =
see Process.setpriority
INT2FIX(PRIO_PGRP)
- PRIO_USER =
see Process.setpriority
INT2FIX(PRIO_USER)
- RLIM_SAVED_MAX =
see Process.setrlimit
v
- RLIM_INFINITY =
see Process.setrlimit
inf
- RLIM_SAVED_CUR =
see Process.setrlimit
v
- RLIMIT_AS =
Maximum size of the process’s virtual memory (address space) in bytes.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_AS)
- RLIMIT_CORE =
Maximum size of the core file.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_CORE)
- RLIMIT_CPU =
CPU time limit in seconds.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_CPU)
- RLIMIT_DATA =
Maximum size of the process’s data segment.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_DATA)
- RLIMIT_FSIZE =
Maximum size of files that the process may create.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_FSIZE)
- RLIMIT_MEMLOCK =
Maximum number of bytes of memory that may be locked into RAM.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_MEMLOCK)
- RLIMIT_MSGQUEUE =
Specifies the limit on the number of bytes that can be allocated for POSIX message queues for the real user ID of the calling process.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_MSGQUEUE)
- RLIMIT_NICE =
Specifies a ceiling to which the process’s nice value can be raised.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_NICE)
- RLIMIT_NOFILE =
Specifies a value one greater than the maximum file descriptor number that can be opened by this process.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_NOFILE)
- RLIMIT_NPROC =
The maximum number of processes that can be created for the real user ID of the calling process.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_NPROC)
- RLIMIT_NPTS =
The maximum number of pseudo-terminals that can be created for the real user ID of the calling process.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_NPTS)
- RLIMIT_RSS =
Specifies the limit (in pages) of the process’s resident set.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_RSS)
- RLIMIT_RTPRIO =
Specifies a ceiling on the real-time priority that may be set for this process.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_RTPRIO)
- RLIMIT_RTTIME =
Specifies limit on CPU time this process scheduled under a real-time scheduling policy can consume.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_RTTIME)
- RLIMIT_SBSIZE =
Maximum size of the socket buffer.
INT2FIX(RLIMIT_SBSIZE)
- RLIMIT_SIGPENDING =
Specifies a limit on the number of signals that may be queued for the real user ID of the calling process.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_SIGPENDING)
- RLIMIT_STACK =
Maximum size of the stack, in bytes.
see the system getrlimit(2) manual for details.
INT2FIX(RLIMIT_STACK)
- CLOCK_REALTIME =
see Process.clock_gettime
RUBY_CLOCK_REALTIME
- CLOCK_MONOTONIC =
see Process.clock_gettime
RUBY_CLOCK_MONOTONIC
- CLOCK_PROCESS_CPUTIME_ID =
see Process.clock_gettime
RUBY_CLOCK_PROCESS_CPUTIME_ID
- CLOCK_THREAD_CPUTIME_ID =
see Process.clock_gettime
RUBY_CLOCK_THREAD_CPUTIME_ID
- CLOCK_VIRTUAL =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_VIRTUAL)
- CLOCK_PROF =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_PROF)
- CLOCK_REALTIME_FAST =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_REALTIME_FAST)
- CLOCK_REALTIME_PRECISE =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_REALTIME_PRECISE)
- CLOCK_REALTIME_COARSE =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_REALTIME_COARSE)
- CLOCK_REALTIME_ALARM =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_REALTIME_ALARM)
- CLOCK_MONOTONIC_FAST =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_MONOTONIC_FAST)
- CLOCK_MONOTONIC_PRECISE =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_MONOTONIC_PRECISE)
- CLOCK_MONOTONIC_RAW =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_MONOTONIC_RAW)
- CLOCK_MONOTONIC_RAW_APPROX =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_MONOTONIC_RAW_APPROX)
- CLOCK_MONOTONIC_COARSE =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_MONOTONIC_COARSE)
- CLOCK_BOOTTIME =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_BOOTTIME)
- CLOCK_BOOTTIME_ALARM =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_BOOTTIME_ALARM)
- CLOCK_UPTIME =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_UPTIME)
- CLOCK_UPTIME_FAST =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_UPTIME_FAST)
- CLOCK_UPTIME_PRECISE =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_UPTIME_PRECISE)
- CLOCK_UPTIME_RAW =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_UPTIME_RAW)
- CLOCK_UPTIME_RAW_APPROX =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_UPTIME_RAW_APPROX)
- CLOCK_SECOND =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_SECOND)
- CLOCK_TAI =
see Process.clock_gettime
CLOCKID2NUM(CLOCK_TAI)
Class Method Summary collapse
-
._fork ⇒ Integer
An internal API for fork.
-
.abort(*a, _) ⇒ Object
Terminates execution immediately, effectively by calling
Kernel.exit(false)
. -
.argv0 ⇒ Object
Returns the name of the script being executed.
-
.clock_getres(clock_id, unit = :float_second) ⇒ Numeric
Returns a clock resolution as determined by POSIX function clock_getres():.
-
.clock_gettime(clock_id, unit = :float_second) ⇒ Numeric
Returns a clock time as determined by POSIX function clock_gettime():.
-
.daemon(nochdir = nil, noclose = nil) ⇒ 0
Detaches the current process from its controlling terminal and runs it in the background as system daemon; returns zero.
-
.detach(pid) ⇒ Object
Avoids the potential for a child process to become a zombie process.
-
.egid ⇒ Object
Returns the effective group ID for the current process:.
- .egid= ⇒ Object
-
.euid ⇒ Object
Returns the effective user ID for the current process.
-
.euid=(new_euid) ⇒ Object
Sets the effective user ID for the current process.
-
.exec(*a, _) ⇒ Object
Replaces the current process by doing one of the following:.
-
.exit(*a, _) ⇒ Object
Initiates termination of the Ruby script by raising SystemExit; the exception may be caught.
-
.exit!(*args) ⇒ Object
Exits the process immediately; no exit handlers are called.
-
.fork ⇒ Object
Creates a child process.
-
.getpgid(pid) ⇒ Integer
Returns the process group ID for the given process ID
pid
:. -
.getpgrp ⇒ Integer
Returns the process group ID for the current process:.
-
.getpriority(kind, id) ⇒ Integer
Returns the scheduling priority for specified process, process group, or user.
-
.getrlimit(resource) ⇒ Array
Returns a 2-element array of the current (soft) limit and maximum (hard) limit for the given
resource
. -
.getsid(pid = nil) ⇒ Integer
Returns the session ID of the given process ID
pid
, or of the current process if not given:. -
.gid ⇒ Object
Returns the (real) group ID for the current process:.
-
.gid=(new_gid) ⇒ Object
Sets the group ID for the current process to
new_gid
:. -
.groups ⇒ Array
Returns an array of the group IDs in the supplemental group access list for the current process:.
-
.groups=(new_groups) ⇒ Object
Sets the supplemental group access list to the given array of group IDs.
-
.initgroups(username, gid) ⇒ Array
Sets the supplemental group access list; the new list includes:.
-
.kill(signal, *ids) ⇒ Object
Sends a signal to each process specified by
ids
(which must specify at least one ID); returns the count of signals sent. -
.last_status ⇒ Process::Status?
Returns a Process::Status object representing the most recently exited child process in the current thread, or
nil
if none:. -
.maxgroups ⇒ Integer
Returns the maximum number of group IDs allowed in the supplemental group access list:.
-
.maxgroups=(new_max) ⇒ Object
Sets the maximum number of group IDs allowed in the supplemental group access list.
-
.pid ⇒ Integer
Returns the process ID of the current process:.
-
.ppid ⇒ Integer
Returns the process ID of the parent of the current process:.
-
.setpgid(pid, pgid) ⇒ 0
Sets the process group ID for the process given by process ID
pid
topgid
. -
.setpgrp ⇒ 0
Equivalent to
setpgid(0, 0)
. -
.setpriority(kind, integer, priority) ⇒ 0
See Process.getpriority.
-
.setproctitle(string) ⇒ String
Sets the process title that appears on the ps(1) command.
-
.setrlimit(resource, cur_limit, max_limit = cur_limit) ⇒ nil
Sets limits for the current process for the given
resource
tocur_limit
(soft limit) andmax_limit
(hard limit); returnsnil
. -
.setsid ⇒ Integer
Establishes the current process as a new session and process group leader, with no controlling tty; returns the session ID:.
-
.spawn(*args) ⇒ Object
Creates a new child process by doing one of the following in that process:.
-
.times ⇒ Object
Returns a Process::Tms structure that contains user and system CPU times for the current process, and for its children processes:.
-
.uid ⇒ Object
Returns the (real) user ID of the current process.
-
.uid=(new_uid) ⇒ Object
Sets the (user) user ID for the current process to
new_uid
:. -
.wait(pid = -1, flags = 0) ⇒ Integer
Waits for a suitable child process to exit, returns its process ID, and sets
$?
to a Process::Status object containing information on that process. -
.wait2(pid = -1, flags = 0) ⇒ Array
Like Process.waitpid, but returns an array containing the child process
pid
and Process::Statusstatus
:. -
.waitall ⇒ Array
Waits for all children, returns an array of 2-element arrays; each subarray contains the integer pid and Process::Status status for one of the reaped child processes:.
-
.wait(pid = -1, flags = 0) ⇒ Integer
Waits for a suitable child process to exit, returns its process ID, and sets
$?
to a Process::Status object containing information on that process. -
.wait2(pid = -1, flags = 0) ⇒ Array
Like Process.waitpid, but returns an array containing the child process
pid
and Process::Statusstatus
:. -
.warmup ⇒ true
Notify the Ruby virtual machine that the boot sequence is finished, and that now is a good time to optimize the application.
Instance Method Summary collapse
-
#argv0 ⇒ Object
private
Returns the name of the script being executed.
-
#clock_getres(clock_id, unit = :float_second) ⇒ Numeric
private
Returns a clock resolution as determined by POSIX function clock_getres():.
-
#clock_gettime(clock_id, unit = :float_second) ⇒ Numeric
private
Returns a clock time as determined by POSIX function clock_gettime():.
-
#daemon(nochdir = nil, noclose = nil) ⇒ 0
private
Detaches the current process from its controlling terminal and runs it in the background as system daemon; returns zero.
-
#detach(pid) ⇒ Object
private
Avoids the potential for a child process to become a zombie process.
-
#egid ⇒ Object
private
Returns the effective group ID for the current process:.
- #egid= ⇒ Object private
-
#euid ⇒ Object
private
Returns the effective user ID for the current process.
-
#euid=(new_euid) ⇒ Object
private
Sets the effective user ID for the current process.
-
#getpgid(pid) ⇒ Integer
private
Returns the process group ID for the given process ID
pid
:. -
#getpgrp ⇒ Integer
private
Returns the process group ID for the current process:.
-
#getpriority(kind, id) ⇒ Integer
private
Returns the scheduling priority for specified process, process group, or user.
-
#getrlimit(resource) ⇒ Array
private
Returns a 2-element array of the current (soft) limit and maximum (hard) limit for the given
resource
. -
#getsid(pid = nil) ⇒ Integer
private
Returns the session ID of the given process ID
pid
, or of the current process if not given:. -
#gid ⇒ Object
private
Returns the (real) group ID for the current process:.
-
#gid=(new_gid) ⇒ Object
private
Sets the group ID for the current process to
new_gid
:. -
#groups ⇒ Array
private
Returns an array of the group IDs in the supplemental group access list for the current process:.
-
#groups=(new_groups) ⇒ Object
private
Sets the supplemental group access list to the given array of group IDs.
-
#initgroups(username, gid) ⇒ Array
private
Sets the supplemental group access list; the new list includes:.
-
#kill(signal, *ids) ⇒ Object
private
Sends a signal to each process specified by
ids
(which must specify at least one ID); returns the count of signals sent. -
#maxgroups ⇒ Integer
private
Returns the maximum number of group IDs allowed in the supplemental group access list:.
-
#maxgroups=(new_max) ⇒ Object
private
Sets the maximum number of group IDs allowed in the supplemental group access list.
-
#pid ⇒ Integer
private
Returns the process ID of the current process:.
-
#ppid ⇒ Integer
private
Returns the process ID of the parent of the current process:.
-
#setpgid(pid, pgid) ⇒ 0
private
Sets the process group ID for the process given by process ID
pid
topgid
. -
#setpgrp ⇒ 0
private
Equivalent to
setpgid(0, 0)
. -
#setpriority(kind, integer, priority) ⇒ 0
private
See Process.getpriority.
-
#setproctitle(string) ⇒ String
private
Sets the process title that appears on the ps(1) command.
-
#setrlimit(resource, cur_limit, max_limit = cur_limit) ⇒ nil
private
Sets limits for the current process for the given
resource
tocur_limit
(soft limit) andmax_limit
(hard limit); returnsnil
. -
#setsid ⇒ Integer
private
Establishes the current process as a new session and process group leader, with no controlling tty; returns the session ID:.
-
#times ⇒ Object
private
Returns a Process::Tms structure that contains user and system CPU times for the current process, and for its children processes:.
-
#uid ⇒ Object
private
Returns the (real) user ID of the current process.
-
#uid=(new_uid) ⇒ Object
private
Sets the (user) user ID for the current process to
new_uid
:. -
#wait(pid = -1, flags = 0) ⇒ Integer
private
Waits for a suitable child process to exit, returns its process ID, and sets
$?
to a Process::Status object containing information on that process. -
#wait2(pid = -1, flags = 0) ⇒ Array
private
Like Process.waitpid, but returns an array containing the child process
pid
and Process::Statusstatus
:. -
#waitall ⇒ Array
private
Waits for all children, returns an array of 2-element arrays; each subarray contains the integer pid and Process::Status status for one of the reaped child processes:.
-
#wait(pid = -1, flags = 0) ⇒ Integer
private
Waits for a suitable child process to exit, returns its process ID, and sets
$?
to a Process::Status object containing information on that process. -
#wait2(pid = -1, flags = 0) ⇒ Array
private
Like Process.waitpid, but returns an array containing the child process
pid
and Process::Statusstatus
:. -
#warmup ⇒ true
private
Notify the Ruby virtual machine that the boot sequence is finished, and that now is a good time to optimize the application.
Class Method Details
._fork ⇒ Integer
An internal API for fork. Do not call this method directly. Currently, this is called via Kernel#fork, Process.fork, and IO.popen with "-"
.
This method is not for casual code but for application monitoring libraries. You can add custom code before and after fork events by overriding this method.
Note: Process.daemon may be implemented using fork(2) BUT does not go through this method. Thus, depending on your reason to hook into this method, you may also want to hook into that one. See this issue for a more detailed discussion of this.
4307 4308 4309 4310 4311 4312 |
# File 'process.c', line 4307
VALUE
rb_proc__fork(VALUE _obj)
{
rb_pid_t pid = proc_fork_pid();
return PIDT2NUM(pid);
}
|
.abort ⇒ Object .abort(msg = nil) ⇒ Object
Terminates execution immediately, effectively by calling Kernel.exit(false)
.
If string argument msg
is given, it is written to STDERR prior to termination; otherwise, if an exception was raised, prints its message and backtrace.
4576 4577 4578 4579 4580 4581 |
# File 'process.c', line 4576
static VALUE
f_abort(int c, const VALUE *a, VALUE _)
{
rb_f_abort(c, a);
UNREACHABLE_RETURN(Qnil);
}
|
.argv0 ⇒ Object
Returns the name of the script being executed. The value is not affected by assigning a new value to $0.
This method first appeared in Ruby 2.1 to serve as a global variable free means to get the script name.
2803 2804 2805 2806 2807 |
# File 'ruby.c', line 2803
static VALUE
proc_argv0(VALUE process)
{
return rb_orig_progname;
}
|
.clock_getres(clock_id, unit = :float_second) ⇒ Numeric
Returns a clock resolution as determined by POSIX function clock_getres():
Process.clock_getres(:CLOCK_REALTIME) # => 1.0e-09
See Process.clock_gettime for the values of clock_id
and unit
.
Examples:
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond) # => 0.001
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond) # => 1.0e-06
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 1.0e-09
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :microsecond) # => 0
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :millisecond) # => 0
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond) # => 1
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :second) # => 0
In addition to the values for unit
supported in Process.clock_gettime, this method supports :hertz
, the integer number of clock ticks per second (which is the reciprocal of :float_second
):
Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz) # => 100.0
Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 0.01
Accuracy: Note that the returned resolution may be inaccurate on some platforms due to underlying bugs. Inaccurate resolutions have been reported for various clocks including :CLOCK_MONOTONIC
and :CLOCK_MONOTONIC_RAW
on Linux, macOS, BSD or AIX platforms, when using ARM processors, or when using virtualization.
8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 |
# File 'process.c', line 8509
static VALUE
rb_clock_getres(int argc, VALUE *argv, VALUE _)
{
int ret;
struct timetick tt;
timetick_int_t numerators[2];
timetick_int_t denominators[2];
int num_numerators = 0;
int num_denominators = 0;
#ifdef HAVE_CLOCK_GETRES
clockid_t c;
#endif
VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
VALUE clk_id = argv[0];
if (SYMBOL_P(clk_id)) {
#ifdef CLOCK_REALTIME
if (clk_id == RUBY_CLOCK_REALTIME) {
c = CLOCK_REALTIME;
goto getres;
}
#endif
#ifdef CLOCK_MONOTONIC
if (clk_id == RUBY_CLOCK_MONOTONIC) {
c = CLOCK_MONOTONIC;
goto getres;
}
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
c = CLOCK_PROCESS_CPUTIME_ID;
goto getres;
}
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
c = CLOCK_THREAD_CPUTIME_ID;
goto getres;
}
#endif
#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
tt.giga_count = 0;
tt.count = 1000;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
tt.giga_count = 1;
tt.count = 0;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
tt.count = 1;
tt.giga_count = 0;
denominators[num_denominators++] = get_clk_tck();
goto success;
}
#endif
#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
tt.giga_count = 0;
tt.count = 1000;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
tt.count = 1;
tt.giga_count = 0;
denominators[num_denominators++] = get_clk_tck();
goto success;
}
#endif
#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
tt.count = 1;
tt.giga_count = 0;
denominators[num_denominators++] = CLOCKS_PER_SEC;
goto success;
}
#endif
#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
const mach_timebase_info_data_t *info = get_mach_timebase_info();
tt.count = 1;
tt.giga_count = 0;
numerators[num_numerators++] = info->numer;
denominators[num_denominators++] = info->denom;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
}
else if (NUMERIC_CLOCKID) {
#if defined(HAVE_CLOCK_GETRES)
struct timespec ts;
c = NUM2CLOCKID(clk_id);
getres:
ret = clock_getres(c, &ts);
if (ret == -1)
clock_failed("getres", errno, clk_id);
tt.count = (int32_t)ts.tv_nsec;
tt.giga_count = ts.tv_sec;
denominators[num_denominators++] = 1000000000;
goto success;
#endif
}
else {
rb_unexpected_type(clk_id, T_SYMBOL);
}
clock_failed("getres", EINVAL, clk_id);
success:
if (unit == ID2SYM(id_hertz)) {
return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
}
else {
return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
}
}
|
.clock_gettime(clock_id, unit = :float_second) ⇒ Numeric
Returns a clock time as determined by POSIX function clock_gettime():
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID) # => 198.650379677
Argument clock_id
should be a symbol or a constant that specifies the clock whose time is to be returned; see below.
Optional argument unit
should be a symbol that specifies the unit to be used in the returned clock time; see below.
Argument clock_id
Argument clock_id
specifies the clock whose time is to be returned; it may be a constant such as Process::CLOCK_REALTIME
, or a symbol shorthand such as :CLOCK_REALTIME
.
The supported clocks depend on the underlying operating system; this method supports the following clocks on the indicated platforms (raises Errno::EINVAL if called with an unsupported clock):
-
:CLOCK_BOOTTIME
: Linux 2.6.39. -
:CLOCK_BOOTTIME_ALARM
: Linux 3.0. -
:CLOCK_MONOTONIC
: SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000. -
:CLOCK_MONOTONIC_COARSE
: Linux 2.6.32. -
:CLOCK_MONOTONIC_FAST
: FreeBSD 8.1. -
:CLOCK_MONOTONIC_PRECISE
: FreeBSD 8.1. -
:CLOCK_MONOTONIC_RAW
: Linux 2.6.28, macOS 10.12. -
:CLOCK_MONOTONIC_RAW_APPROX
: macOS 10.12. -
:CLOCK_PROCESS_CPUTIME_ID
: SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12. -
:CLOCK_PROF
: FreeBSD 3.0, OpenBSD 2.1. -
:CLOCK_REALTIME
: SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12, Windows-8/Server-2012. Time.now is recommended over +:CLOCK_REALTIME:. -
:CLOCK_REALTIME_ALARM
: Linux 3.0. -
:CLOCK_REALTIME_COARSE
: Linux 2.6.32. -
:CLOCK_REALTIME_FAST
: FreeBSD 8.1. -
:CLOCK_REALTIME_PRECISE
: FreeBSD 8.1. -
:CLOCK_SECOND
: FreeBSD 8.1. -
:CLOCK_TAI
: Linux 3.10. -
:CLOCK_THREAD_CPUTIME_ID
: SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12. -
:CLOCK_UPTIME
: FreeBSD 7.0, OpenBSD 5.5. -
:CLOCK_UPTIME_FAST
: FreeBSD 8.1. -
:CLOCK_UPTIME_PRECISE
: FreeBSD 8.1. -
:CLOCK_UPTIME_RAW
: macOS 10.12. -
:CLOCK_UPTIME_RAW_APPROX
: macOS 10.12. -
:CLOCK_VIRTUAL
: FreeBSD 3.0, OpenBSD 2.1.
Note that SUS stands for Single Unix Specification. SUS contains POSIX and clock_gettime is defined in the POSIX part. SUS defines :CLOCK_REALTIME
as mandatory but :CLOCK_MONOTONIC
, :CLOCK_PROCESS_CPUTIME_ID
, and :CLOCK_THREAD_CPUTIME_ID
are optional.
Certain emulations are used when the given clock_id
is not supported directly:
-
Emulations for
:CLOCK_REALTIME
:-
:GETTIMEOFDAY_BASED_CLOCK_REALTIME
: Use gettimeofday() defined by SUS (deprecated in SUSv4). The resolution is 1 microsecond. -
:TIME_BASED_CLOCK_REALTIME
: Use time() defined by ISO C. The resolution is 1 second.
-
-
Emulations for
:CLOCK_MONOTONIC
:-
:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
: Use mach_absolute_time(), available on Darwin. The resolution is CPU dependent. -
:TIMES_BASED_CLOCK_MONOTONIC
: Use the result value of times() defined by POSIX, thus:Upon successful completion, times() shall return the elapsed real time, in clock ticks, since an arbitrary point in the past (for example, system start-up time).
For example, GNU/Linux returns a value based on jiffies and it is monotonic. However, 4.4BSD uses gettimeofday() and it is not monotonic. (FreeBSD uses
:CLOCK_MONOTONIC
instead, though.)The resolution is the clock tick. “getconf CLK_TCK” command shows the clock ticks per second. (The clock ticks-per-second is defined by HZ macro in older systems.) If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and cannot represent over 497 days.
-
-
Emulations for
:CLOCK_PROCESS_CPUTIME_ID
:-
:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
: Use getrusage() defined by SUS. getrusage() is used with RUSAGE_SELF to obtain the time only for the calling process (excluding the time for child processes). The result is addition of user time (ru_utime) and system time (ru_stime). The resolution is 1 microsecond. -
:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
: Use times() defined by POSIX. The result is addition of user time (tms_utime) and system time (tms_stime). tms_cutime and tms_cstime are ignored to exclude the time for child processes. The resolution is the clock tick. “getconf CLK_TCK” command shows the clock ticks per second. (The clock ticks per second is defined by HZ macro in older systems.) If it is 100, the resolution is 10 millisecond. -
:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
: Use clock() defined by ISO C. The resolution is1/CLOCKS_PER_SEC
.CLOCKS_PER_SEC
is the C-level macro defined by time.h. SUS definesCLOCKS_PER_SEC
as 1000000; other systems may define it differently. IfCLOCKS_PER_SEC
is 1000000 (as in SUS), the resolution is 1 microsecond. IfCLOCKS_PER_SEC
is 1000000 and clock_t is a 32-bit integer type, it cannot represent over 72 minutes.
-
Argument unit
Optional argument unit
(default :float_second
) specifies the unit for the returned value.
-
:float_microsecond
: Number of microseconds as a float. -
:float_millisecond
: Number of milliseconds as a float. -
:float_second
: Number of seconds as a float. -
:microsecond
: Number of microseconds as an integer. -
:millisecond
: Number of milliseconds as an integer. -
:nanosecond
: Number of nanoseconds as an integer. -
::second
: Number of seconds as an integer.
Examples:
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond)
# => 203605054.825
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond)
# => 203643.696848
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_second)
# => 203.762181929
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :microsecond)
# => 204123212
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :millisecond)
# => 204298
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond)
# => 204602286036
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :second)
# => 204
The underlying function, clock_gettime(), returns a number of nanoseconds. Float object (IEEE 754 double) is not enough to represent the return value for :CLOCK_REALTIME
. If the exact nanoseconds value is required, use :nanosecond
as the unit
.
The origin (time zero) of the returned value is system-dependent, and may be, for example, system start up time, process start up time, the Epoch, etc.
The origin in :CLOCK_REALTIME
is defined as the Epoch: 1970-01-01 00:00:00 UTC
; some systems count leap seconds and others don’t, so the result may vary across systems.
8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 |
# File 'process.c', line 8282
static VALUE
rb_clock_gettime(int argc, VALUE *argv, VALUE _)
{
int ret;
struct timetick tt;
timetick_int_t numerators[2];
timetick_int_t denominators[2];
int num_numerators = 0;
int num_denominators = 0;
VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
VALUE clk_id = argv[0];
#ifdef HAVE_CLOCK_GETTIME
clockid_t c;
#endif
if (SYMBOL_P(clk_id)) {
#ifdef CLOCK_REALTIME
if (clk_id == RUBY_CLOCK_REALTIME) {
c = CLOCK_REALTIME;
goto gettime;
}
#endif
#ifdef CLOCK_MONOTONIC
if (clk_id == RUBY_CLOCK_MONOTONIC) {
c = CLOCK_MONOTONIC;
goto gettime;
}
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
c = CLOCK_PROCESS_CPUTIME_ID;
goto gettime;
}
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
c = CLOCK_THREAD_CPUTIME_ID;
goto gettime;
}
#endif
/*
* Non-clock_gettime clocks are provided by symbol clk_id.
*/
#ifdef HAVE_GETTIMEOFDAY
/*
* GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
* CLOCK_REALTIME if clock_gettime is not available.
*/
#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
struct timeval tv;
ret = gettimeofday(&tv, 0);
if (ret != 0)
rb_sys_fail("gettimeofday");
tt.giga_count = tv.tv_sec;
tt.count = (int32_t)tv.tv_usec * 1000;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
time_t t;
t = time(NULL);
if (t == (time_t)-1)
rb_sys_fail("time");
tt.giga_count = t;
tt.count = 0;
denominators[num_denominators++] = 1000000000;
goto success;
}
#ifdef HAVE_TIMES
#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
struct tms buf;
clock_t c;
unsigned_clock_t uc;
c = times(&buf);
if (c == (clock_t)-1)
rb_sys_fail("times");
uc = (unsigned_clock_t)c;
tt.count = (int32_t)(uc % 1000000000);
tt.giga_count = (uc / 1000000000);
denominators[num_denominators++] = get_clk_tck();
goto success;
}
#endif
#ifdef RUSAGE_SELF
#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
struct rusage usage;
int32_t usec;
ret = getrusage(RUSAGE_SELF, &usage);
if (ret != 0)
rb_sys_fail("getrusage");
tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
if (1000000 <= usec) {
tt.giga_count++;
usec -= 1000000;
}
tt.count = usec * 1000;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#ifdef HAVE_TIMES
#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
struct tms buf;
unsigned_clock_t utime, stime;
if (times(&buf) == (clock_t)-1)
rb_sys_fail("times");
utime = (unsigned_clock_t)buf.tms_utime;
stime = (unsigned_clock_t)buf.tms_stime;
tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
if (1000000000 <= tt.count) {
tt.count -= 1000000000;
tt.giga_count++;
}
denominators[num_denominators++] = get_clk_tck();
goto success;
}
#endif
#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
clock_t c;
unsigned_clock_t uc;
errno = 0;
c = clock();
if (c == (clock_t)-1)
rb_sys_fail("clock");
uc = (unsigned_clock_t)c;
tt.count = (int32_t)(uc % 1000000000);
tt.giga_count = uc / 1000000000;
denominators[num_denominators++] = CLOCKS_PER_SEC;
goto success;
}
#ifdef __APPLE__
if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
const mach_timebase_info_data_t *info = get_mach_timebase_info();
uint64_t t = mach_absolute_time();
tt.count = (int32_t)(t % 1000000000);
tt.giga_count = t / 1000000000;
numerators[num_numerators++] = info->numer;
denominators[num_denominators++] = info->denom;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
}
else if (NUMERIC_CLOCKID) {
#if defined(HAVE_CLOCK_GETTIME)
struct timespec ts;
c = NUM2CLOCKID(clk_id);
gettime:
ret = clock_gettime(c, &ts);
if (ret == -1)
clock_failed("gettime", errno, clk_id);
tt.count = (int32_t)ts.tv_nsec;
tt.giga_count = ts.tv_sec;
denominators[num_denominators++] = 1000000000;
goto success;
#endif
}
else {
rb_unexpected_type(clk_id, T_SYMBOL);
}
clock_failed("gettime", EINVAL, clk_id);
success:
return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
}
|
.daemon(nochdir = nil, noclose = nil) ⇒ 0
Detaches the current process from its controlling terminal and runs it in the background as system daemon; returns zero.
By default:
-
Changes the current working directory to the root directory.
-
Redirects $stdin, $stdout, and $stderr to the null device.
If optional argument nochdir
is true
, does not change the current working directory.
If optional argument noclose
is true
, does not redirect $stdin, $stdout, or $stderr.
6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 |
# File 'process.c', line 6972
static VALUE
proc_daemon(int argc, VALUE *argv, VALUE _)
{
int n, nochdir = FALSE, noclose = FALSE;
switch (rb_check_arity(argc, 0, 2)) {
case 2: noclose = TO_BOOL(argv[1], "noclose");
case 1: nochdir = TO_BOOL(argv[0], "nochdir");
}
prefork();
n = rb_daemon(nochdir, noclose);
if (n < 0) rb_sys_fail("daemon");
return INT2FIX(n);
}
|
.detach(pid) ⇒ Object
Avoids the potential for a child process to become a zombie process. Process.detach prevents this by setting up a separate Ruby thread whose sole job is to reap the status of the process pid when it terminates.
This method is needed only when the parent process will never wait for the child process.
This example does not reap the second child process; that process appears as a zombie in the process status (ps
) output:
pid = Process.spawn('ruby', '-e', 'exit 13') # => 312691
sleep(1)
# Find zombies.
system("ps -ho pid,state -p #{pid}")
Output:
312716 Z
This example also does not reap the second child process, but it does detach the process so that it does not become a zombie:
pid = Process.spawn('ruby', '-e', 'exit 13') # => 313213
thread = Process.detach(pid)
sleep(1)
# => #<Process::Waiter:0x00007f038f48b838 run>
system("ps -ho pid,state -p #{pid}") # Finds no zombies.
The waiting thread can return the pid of the detached child process:
thread.join.pid # => 313262
1601 1602 1603 1604 1605 |
# File 'process.c', line 1601
static VALUE
proc_detach(VALUE obj, VALUE pid)
{
return rb_detach_process(NUM2PIDT(pid));
}
|
.egid ⇒ Integer .Process::GID.eid ⇒ Integer .Process::Sys.geteid ⇒ Integer
Returns the effective group ID for the current process:
Process.egid # => 500
Not available on all platforms.
7362 7363 7364 7365 7366 7367 7368 |
# File 'process.c', line 7362
static VALUE
proc_getegid(VALUE obj)
{
rb_gid_t egid = getegid();
return GIDT2NUM(egid);
}
|
.egid= ⇒ Object
.euid ⇒ Integer .Process::UID.eid ⇒ Integer .Process::Sys.geteuid ⇒ Integer
Returns the effective user ID for the current process.
Process.euid # => 501
7236 7237 7238 7239 7240 7241 |
# File 'process.c', line 7236
static VALUE
proc_geteuid(VALUE obj)
{
rb_uid_t euid = geteuid();
return UIDT2NUM(euid);
}
|
.euid=(new_euid) ⇒ Object
Sets the effective user ID for the current process.
Not available on all platforms.
7276 7277 7278 7279 7280 7281 7282 |
# File 'process.c', line 7276
static VALUE
proc_seteuid_m(VALUE mod, VALUE euid)
{
check_uid_switch();
proc_seteuid(OBJ2UID(euid));
return euid;
}
|
.exec([env, ], options = {}) ⇒ Object .exec([env, ], *args, options = {}) ⇒ Object
Replaces the current process by doing one of the following:
-
Passing string
command_line
to the shell. -
Invoking the executable at
exe_path
.
This method has potential security vulnerabilities if called with untrusted input; see Command Injection.
The new process is created using the exec system call; it may inherit some of its environment from the calling program (possibly including open file descriptors).
Argument env
, if given, is a hash that affects ENV
for the new process; see Execution Environment.
Argument options
is a hash of options for the new process; see Execution Options.
The first required argument is one of the following:
-
command_line
if it is a string, and if it begins with a shell reserved word or special built-in, or if it contains one or more meta characters. -
exe_path
otherwise.
Argument command_line
String argument command_line
is a command line to be passed to a shell; it must begin with a shell reserved word, begin with a special built-in, or contain meta characters:
exec('if true; then echo "Foo"; fi') # Shell reserved word.
exec('echo') # Built-in.
exec('date > date.tmp') # Contains meta character.
The command line may also contain arguments and options for the command:
exec('echo "Foo"')
Output:
Foo
See Execution Shell for details about the shell.
Raises an exception if the new process could not execute.
Argument exe_path
Argument exe_path
is one of the following:
-
The string path to an executable to be called.
-
A 2-element array containing the path to an executable and the string to be used as the name of the executing process.
Example:
exec('/usr/bin/date')
Output:
Sat Aug 26 09:38:00 AM CDT 2023
Ruby invokes the executable directly, with no shell and no shell expansion:
exec('doesnt_exist') # Raises Errno::ENOENT
If one or more args
is given, each is an argument or option to be passed to the executable:
exec('echo', 'C*')
exec('echo', 'hello', 'world')
Output:
C*
hello world
Raises an exception if the new process could not execute.
3134 3135 3136 3137 3138 3139 |
# File 'process.c', line 3134
static VALUE
f_exec(int c, const VALUE *a, VALUE _)
{
rb_f_exec(c, a);
UNREACHABLE_RETURN(Qnil);
}
|
.exit(status = true) ⇒ Object .exit(status = true) ⇒ Object
Initiates termination of the Ruby script by raising SystemExit; the exception may be caught. Returns exit status status
to the underlying operating system.
Values true
and false
for argument status
indicate, respectively, success and failure; The meanings of integer values are system-dependent.
Example:
begin
exit
puts 'Never get here.'
rescue SystemExit
puts 'Rescued a SystemExit exception.'
end
puts 'After begin block.'
Output:
Rescued a SystemExit exception.
After begin block.
Just prior to final termination, Ruby executes any at-exit procedures (see Kernel::at_exit) and any object finalizers (see ObjectSpace::define_finalizer).
Example:
at_exit { puts 'In at_exit function.' }
ObjectSpace.define_finalizer('string', proc { puts 'In finalizer.' })
exit
Output:
In at_exit function.
In finalizer.
4528 4529 4530 4531 4532 4533 |
# File 'process.c', line 4528
static VALUE
f_exit(int c, const VALUE *a, VALUE _)
{
rb_f_exit(c, a);
UNREACHABLE_RETURN(Qnil);
}
|
.exit!(status = false) ⇒ Object .exit!(status = false) ⇒ Object
Exits the process immediately; no exit handlers are called. Returns exit status status
to the underlying operating system.
Process.exit!(true)
Values true
and false
for argument status
indicate, respectively, success and failure; The meanings of integer values are system-dependent.
4437 4438 4439 4440 4441 4442 4443 4444 4445 4446 4447 4448 4449 4450 4451 |
# File 'process.c', line 4437
static VALUE
rb_f_exit_bang(int argc, VALUE *argv, VALUE obj)
{
int istatus;
if (rb_check_arity(argc, 0, 1) == 1) {
istatus = exit_status_code(argv[0]);
}
else {
istatus = EXIT_FAILURE;
}
_exit(istatus);
UNREACHABLE_RETURN(Qnil);
}
|
.fork { ... } ⇒ Integer? .fork ⇒ Integer?
Creates a child process.
With a block given, runs the block in the child process; on block exit, the child terminates with a status of zero:
puts "Before the fork: #{Process.pid}"
fork do
puts "In the child process: #{Process.pid}"
end # => 382141
puts "After the fork: #{Process.pid}"
Output:
Before the fork: 420496
After the fork: 420496
In the child process: 420520
With no block given, the fork
call returns twice:
-
Once in the parent process, returning the pid of the child process.
-
Once in the child process, returning
nil
.
Example:
puts "This is the first line before the fork (pid #{Process.pid})"
puts fork
puts "This is the second line after the fork (pid #{Process.pid})"
Output:
This is the first line before the fork (pid 420199)
420223
This is the second line after the fork (pid 420199)
This is the second line after the fork (pid 420223)
In either case, the child process may exit using Kernel.exit! to avoid the call to Kernel#at_exit.
To avoid zombie processes, the parent process should call either:
-
Process.wait, to collect the termination statuses of its children.
-
Process.detach, to register disinterest in their status.
The thread calling fork
is the only thread in the created child process; fork
doesn’t copy other threads.
Note that method fork
is available on some platforms, but not on others:
Process.respond_to?(:fork) # => true # Would be false on some.
If not, you may use ::spawn instead of fork
.
4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384 4385 4386 4387 4388 4389 4390 4391 |
# File 'process.c', line 4374
static VALUE
rb_f_fork(VALUE obj)
{
rb_pid_t pid;
pid = rb_call_proc__fork();
if (pid == 0) {
if (rb_block_given_p()) {
int status;
rb_protect(rb_yield, Qundef, &status);
ruby_stop(status);
}
return Qnil;
}
return PIDT2NUM(pid);
}
|
.getpgid(pid) ⇒ Integer
5152 5153 5154 5155 5156 5157 5158 5159 5160 |
# File 'process.c', line 5152
static VALUE
proc_getpgid(VALUE obj, VALUE pid)
{
rb_pid_t i;
i = getpgid(NUM2PIDT(pid));
if (i < 0) rb_sys_fail(0);
return PIDT2NUM(i);
}
|
.getpgrp ⇒ Integer
5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 |
# File 'process.c', line 5091
static VALUE
proc_getpgrp(VALUE _)
{
rb_pid_t pgrp;
#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
pgrp = getpgrp();
if (pgrp < 0) rb_sys_fail(0);
return PIDT2NUM(pgrp);
#else /* defined(HAVE_GETPGID) */
pgrp = getpgid(0);
if (pgrp < 0) rb_sys_fail(0);
return PIDT2NUM(pgrp);
#endif
}
|
.getpriority(kind, id) ⇒ Integer
Returns the scheduling priority for specified process, process group, or user.
Argument kind
is one of:
-
Process::PRIO_PROCESS: return priority for process.
-
Process::PRIO_PGRP: return priority for process group.
-
Process::PRIO_USER: return priority for user.
Argument id
is the ID for the process, process group, or user; zero specified the current ID for kind
.
Examples:
Process.getpriority(Process::PRIO_USER, 0) # => 19
Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
Not available on all platforms.
5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 |
# File 'process.c', line 5310
static VALUE
proc_getpriority(VALUE obj, VALUE which, VALUE who)
{
int prio, iwhich, iwho;
iwhich = NUM2INT(which);
iwho = NUM2INT(who);
errno = 0;
prio = getpriority(iwhich, iwho);
if (errno) rb_sys_fail(0);
return INT2FIX(prio);
}
|
.getrlimit(resource) ⇒ Array
Returns a 2-element array of the current (soft) limit and maximum (hard) limit for the given resource
.
Argument resource
specifies the resource whose limits are to be returned; see Process.setrlimit.
Each of the returned values cur_limit
and max_limit
is an integer; see Process.setrlimit.
Example:
Process.getrlimit(:CORE) # => [0, 18446744073709551615]
See Process.setrlimit.
Not available on all platforms.
5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 |
# File 'process.c', line 5610
static VALUE
proc_getrlimit(VALUE obj, VALUE resource)
{
struct rlimit rlim;
if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
rb_sys_fail("getrlimit");
}
return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
}
|
.getsid(pid = nil) ⇒ Integer
5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 |
# File 'process.c', line 5207
static VALUE
proc_getsid(int argc, VALUE *argv, VALUE _)
{
rb_pid_t sid;
rb_pid_t pid = 0;
if (rb_check_arity(argc, 0, 1) == 1 && !NIL_P(argv[0]))
pid = NUM2PIDT(argv[0]);
sid = getsid(pid);
if (sid < 0) rb_sys_fail(0);
return PIDT2NUM(sid);
}
|
.gid ⇒ Integer .Process::GID.rid ⇒ Integer .Process::Sys.getgid ⇒ Integer
Returns the (real) group ID for the current process:
Process.gid # => 1000
6665 6666 6667 6668 6669 6670 |
# File 'process.c', line 6665
static VALUE
proc_getgid(VALUE obj)
{
rb_gid_t gid = getgid();
return GIDT2NUM(gid);
}
|
.gid=(new_gid) ⇒ Object
6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 |
# File 'process.c', line 6684
static VALUE
proc_setgid(VALUE obj, VALUE id)
{
rb_gid_t gid;
check_gid_switch();
gid = OBJ2GID(id);
#if defined(HAVE_SETRESGID)
if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETREGID
if (setregid(gid, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETRGID
if (setrgid(gid) < 0) rb_sys_fail(0);
#elif defined HAVE_SETGID
{
if (getegid() == gid) {
if (setgid(gid) < 0) rb_sys_fail(0);
}
else {
rb_notimplement();
}
}
#endif
return GIDT2NUM(gid);
}
|
.groups ⇒ Array
Returns an array of the group IDs in the supplemental group access list for the current process:
Process.groups # => [4, 24, 27, 30, 46, 122, 135, 136, 1000]
These properties of the returned array are system-dependent:
-
Whether (and how) the array is sorted.
-
Whether the array includes effective group IDs.
-
Whether the array includes duplicate group IDs.
-
Whether the array size exceeds the value of Process.maxgroups.
Use this call to get a sorted and unique array:
Process.groups.uniq.sort
6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 |
# File 'process.c', line 6785
static VALUE
proc_getgroups(VALUE obj)
{
VALUE ary, tmp;
int i, ngroups;
rb_gid_t *groups;
ngroups = getgroups(0, NULL);
if (ngroups == -1)
rb_sys_fail(0);
groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
ngroups = getgroups(ngroups, groups);
if (ngroups == -1)
rb_sys_fail(0);
ary = rb_ary_new();
for (i = 0; i < ngroups; i++)
rb_ary_push(ary, GIDT2NUM(groups[i]));
ALLOCV_END(tmp);
return ary;
}
|
.groups=(new_groups) ⇒ Object
6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 |
# File 'process.c', line 6829
static VALUE
proc_setgroups(VALUE obj, VALUE ary)
{
int ngroups, i;
rb_gid_t *groups;
VALUE tmp;
PREPARE_GETGRNAM;
Check_Type(ary, T_ARRAY);
ngroups = RARRAY_LENINT(ary);
if (ngroups > maxgroups())
rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
for (i = 0; i < ngroups; i++) {
VALUE g = RARRAY_AREF(ary, i);
groups[i] = OBJ2GID1(g);
}
FINISH_GETGRNAM;
if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
rb_sys_fail(0);
ALLOCV_END(tmp);
return proc_getgroups(obj);
}
|
.initgroups(username, gid) ⇒ Array
Sets the supplemental group access list; the new list includes:
-
The group IDs of those groups to which the user given by
username
belongs. -
The group ID
gid
.
Example:
Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
Process.initgroups('me', 30) # => [30, 6, 10, 11]
Process.groups # => [30, 6, 10, 11]
Not available on all platforms.
6884 6885 6886 6887 6888 6889 6890 6891 |
# File 'process.c', line 6884
static VALUE
proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
{
if (initgroups(StringValueCStr(uname), OBJ2GID(base_grp)) != 0) {
rb_sys_fail(0);
}
return proc_getgroups(obj);
}
|
.kill(signal, *ids) ⇒ Object
Sends a signal to each process specified by ids
(which must specify at least one ID); returns the count of signals sent.
For each given id
, if id
is:
-
Positive, sends the signal to the process whose process ID is
id
. -
Zero, send the signal to all processes in the current process group.
-
Negative, sends the signal to a system-dependent collection of processes.
Argument signal
specifies the signal to be sent; the argument may be:
-
An integer signal number: e.g.,
-29
,0
,29
. -
A signal name (string), with or without leading
'SIG'
, and with or without a further prefixed minus sign ('-'
): e.g.:-
'SIGPOLL'
. -
'POLL'
, -
'-SIGPOLL'
. -
'-POLL'
.
-
-
A signal symbol, with or without leading
'SIG'
, and with or without a further prefixed minus sign ('-'
): e.g.:-
:SIGPOLL
. -
:POLL
. -
:'-SIGPOLL'
. -
:'-POLL'
.
-
If signal
is:
-
A non-negative integer, or a signal name or symbol without prefixed
'-'
, each process with process IDid
is signalled. -
A negative integer, or a signal name or symbol with prefixed
'-'
, each process group with group IDid
is signalled.
Use method Signal.list to see which signals are supported by Ruby on the underlying platform; the method returns a hash of the string names and non-negative integer values of the supported signals. The size and content of the returned hash varies widely among platforms.
Additionally, signal 0
is useful to determine if the process exists.
Example:
pid = fork do
Signal.trap('HUP') { puts 'Ouch!'; exit }
# ... do some work ...
end
# ...
Process.kill('HUP', pid)
Process.wait
Output:
Ouch!
Exceptions:
-
Raises Errno::EINVAL or RangeError if
signal
is an integer but invalid. -
Raises ArgumentError if
signal
is a string or symbol but invalid. -
Raises Errno::ESRCH or RangeError if one of
ids
is invalid. -
Raises Errno::EPERM if needed permissions are not in force.
In the last two cases, signals may have been sent to some processes.
8741 8742 8743 8744 8745 |
# File 'process.c', line 8741
static VALUE
proc_rb_f_kill(int c, const VALUE *v, VALUE _)
{
return rb_f_kill(c, v);
}
|
.last_status ⇒ Process::Status?
Returns a Process::Status object representing the most recently exited child process in the current thread, or nil
if none:
Process.spawn('ruby', '-e', 'exit 13')
Process.wait
Process.last_status # => #<Process::Status: pid 14396 exit 13>
Process.spawn('ruby', '-e', 'exit 14')
Process.wait
Process.last_status # => #<Process::Status: pid 4692 exit 14>
Process.spawn('ruby', '-e', 'exit 15')
# 'exit 15' has not been reaped by #wait.
Process.last_status # => #<Process::Status: pid 4692 exit 14>
Process.wait
Process.last_status # => #<Process::Status: pid 1380 exit 15>
638 639 640 641 642 |
# File 'process.c', line 638
static VALUE
proc_s_last_status(VALUE mod)
{
return rb_last_status_get();
}
|
.maxgroups ⇒ Integer
Returns the maximum number of group IDs allowed in the supplemental group access list:
Process.maxgroups # => 32
6908 6909 6910 6911 6912 |
# File 'process.c', line 6908
static VALUE
proc_getmaxgroups(VALUE obj)
{
return INT2FIX(maxgroups());
}
|
.maxgroups=(new_max) ⇒ Object
Sets the maximum number of group IDs allowed in the supplemental group access list.
6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 |
# File 'process.c', line 6926
static VALUE
proc_setmaxgroups(VALUE obj, VALUE val)
{
int ngroups = FIX2INT(val);
int ngroups_max = get_sc_ngroups_max();
if (ngroups <= 0)
rb_raise(rb_eArgError, "maxgroups %d should be positive", ngroups);
if (ngroups > RB_MAX_GROUPS)
ngroups = RB_MAX_GROUPS;
if (ngroups_max > 0 && ngroups > ngroups_max)
ngroups = ngroups_max;
_maxgroups = ngroups;
return INT2FIX(_maxgroups);
}
|
.pid ⇒ Integer
Returns the process ID of the current process:
Process.pid # => 15668
529 530 531 532 533 |
# File 'process.c', line 529
static VALUE
proc_get_pid(VALUE _)
{
return get_pid();
}
|
.ppid ⇒ Integer
558 559 560 561 562 |
# File 'process.c', line 558
static VALUE
proc_get_ppid(VALUE _)
{
return get_ppid();
}
|
.setpgid(pid, pgid) ⇒ 0
Sets the process group ID for the process given by process ID pid
to pgid
.
Not available on all platforms.
5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 |
# File 'process.c', line 5177
static VALUE
proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
{
rb_pid_t ipid, ipgrp;
ipid = NUM2PIDT(pid);
ipgrp = NUM2PIDT(pgrp);
if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
return INT2FIX(0);
}
|
.setpgrp ⇒ 0
Equivalent to setpgid(0, 0)
.
Not available on all platforms.
5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 |
# File 'process.c', line 5121
static VALUE
proc_setpgrp(VALUE _)
{
/* check for posix setpgid() first; this matches the posix */
/* getpgrp() above. It appears that configure will set SETPGRP_VOID */
/* even though setpgrp(0,0) would be preferred. The posix call avoids */
/* this confusion. */
#ifdef HAVE_SETPGID
if (setpgid(0,0) < 0) rb_sys_fail(0);
#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
if (setpgrp() < 0) rb_sys_fail(0);
#endif
return INT2FIX(0);
}
|
.setpriority(kind, integer, priority) ⇒ 0
See Process.getpriority.
Examples:
Process.setpriority(Process::PRIO_USER, 0, 19) # => 0
Process.setpriority(Process::PRIO_PROCESS, 0, 19) # => 0
Process.getpriority(Process::PRIO_USER, 0) # => 19
Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
Not available on all platforms.
5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 |
# File 'process.c', line 5345
static VALUE
proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
{
int iwhich, iwho, iprio;
iwhich = NUM2INT(which);
iwho = NUM2INT(who);
iprio = NUM2INT(prio);
if (setpriority(iwhich, iwho, iprio) < 0)
rb_sys_fail(0);
return INT2FIX(0);
}
|
.setproctitle(string) ⇒ String
Sets the process title that appears on the ps(1) command. Not necessarily effective on all platforms. No exception will be raised regardless of the result, nor will NotImplementedError be raised even if the platform does not support the feature.
Calling this method does not affect the value of $0.
Process.setproctitle('myapp: worker #%d' % worker_id)
This method first appeared in Ruby 2.1 to serve as a global variable free means to change the process title.
2828 2829 2830 2831 2832 |
# File 'ruby.c', line 2828
static VALUE
proc_setproctitle(VALUE process, VALUE title)
{
return ruby_setproctitle(title);
}
|
.setrlimit(resource, cur_limit, max_limit = cur_limit) ⇒ nil
Sets limits for the current process for the given resource
to cur_limit
(soft limit) and max_limit
(hard limit); returns nil
.
Argument resource
specifies the resource whose limits are to be set; the argument may be given as a symbol, as a string, or as a constant beginning with Process::RLIMIT_
(e.g., :CORE
, 'CORE'
, or Process::RLIMIT_CORE
.
The resources available and supported are system-dependent, and may include (here expressed as symbols):
-
:AS
: Total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD except 4.4BSD-Lite). -
:CORE
: Core size (bytes) (SUSv3). -
:CPU
: CPU time (seconds) (SUSv3). -
:DATA
: Data segment (bytes) (SUSv3). -
:FSIZE
: File size (bytes) (SUSv3). -
:MEMLOCK
: Total size for mlock(2) (bytes) (4.4BSD, GNU/Linux). -
:MSGQUEUE
: Allocation for POSIX message queues (bytes) (GNU/Linux). -
:NICE
: Ceiling on process’s nice(2) value (number) (GNU/Linux). -
:NOFILE
: File descriptors (number) (SUSv3). -
:NPROC
: Number of processes for the user (number) (4.4BSD, GNU/Linux). -
:NPTS
: Number of pseudo terminals (number) (FreeBSD). -
:RSS
: Resident memory size (bytes) (4.2BSD, GNU/Linux). -
:RTPRIO
: Ceiling on the process’s real-time priority (number) (GNU/Linux). -
:RTTIME
: CPU time for real-time process (us) (GNU/Linux). -
:SBSIZE
: All socket buffers (bytes) (NetBSD, FreeBSD). -
:SIGPENDING
: Number of queued signals allowed (signals) (GNU/Linux). -
:STACK
: Stack size (bytes) (SUSv3).
Arguments cur_limit
and max_limit
may be:
-
Integers (
max_limit
should not be smaller thancur_limit
). -
Symbol
:SAVED_MAX
, string'SAVED_MAX'
, or constantProcess::RLIM_SAVED_MAX
: saved maximum limit. -
Symbol
:SAVED_CUR
, string'SAVED_CUR'
, or constantProcess::RLIM_SAVED_CUR
: saved current limit. -
Symbol
:INFINITY
, string'INFINITY'
, or constantProcess::RLIM_INFINITY
: no limit on resource.
This example raises the soft limit of core size to the hard limit to try to make core dump possible:
Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
Not available on all platforms.
5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 |
# File 'process.c', line 5677
static VALUE
proc_setrlimit(int argc, VALUE *argv, VALUE obj)
{
VALUE resource, rlim_cur, rlim_max;
struct rlimit rlim;
rb_check_arity(argc, 2, 3);
resource = argv[0];
rlim_cur = argv[1];
if (argc < 3 || NIL_P(rlim_max = argv[2]))
rlim_max = rlim_cur;
rlim.rlim_cur = rlimit_resource_value(rlim_cur);
rlim.rlim_max = rlimit_resource_value(rlim_max);
if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
rb_sys_fail("setrlimit");
}
return Qnil;
}
|
.setsid ⇒ Integer
Establishes the current process as a new session and process group leader, with no controlling tty; returns the session ID:
Process.setsid # => 27422
Not available on all platforms.
5243 5244 5245 5246 5247 5248 5249 5250 5251 |
# File 'process.c', line 5243
static VALUE
proc_setsid(VALUE _)
{
rb_pid_t pid;
pid = setsid();
if (pid < 0) rb_sys_fail(0);
return PIDT2NUM(pid);
}
|
.spawn([env, ], options = {}) ⇒ Object .spawn([env, ], *args, options = {}) ⇒ Object
Creates a new child process by doing one of the following in that process:
-
Passing string
command_line
to the shell. -
Invoking the executable at
exe_path
.
This method has potential security vulnerabilities if called with untrusted input; see Command Injection.
Returns the process ID (pid) of the new process, without waiting for it to complete.
To avoid zombie processes, the parent process should call either:
-
Process.wait, to collect the termination statuses of its children.
-
Process.detach, to register disinterest in their status.
The new process is created using the exec system call; it may inherit some of its environment from the calling program (possibly including open file descriptors).
Argument env
, if given, is a hash that affects ENV
for the new process; see Execution Environment.
Argument options
is a hash of options for the new process; see Execution Options.
The first required argument is one of the following:
-
command_line
if it is a string, and if it begins with a shell reserved word or special built-in, or if it contains one or more meta characters. -
exe_path
otherwise.
Argument command_line
String argument command_line
is a command line to be passed to a shell; it must begin with a shell reserved word, begin with a special built-in, or contain meta characters:
spawn('if true; then echo "Foo"; fi') # => 798847 # Shell reserved word.
Process.wait # => 798847
spawn('echo') # => 798848 # Built-in.
Process.wait # => 798848
spawn('date > /tmp/date.tmp') # => 798879 # Contains meta character.
Process.wait # => 798849
spawn('date > /nop/date.tmp') # => 798882 # Issues error message.
Process.wait # => 798882
The command line may also contain arguments and options for the command:
spawn('echo "Foo"') # => 799031
Process.wait # => 799031
Output:
Foo
See Execution Shell for details about the shell.
Raises an exception if the new process could not execute.
Argument exe_path
Argument exe_path
is one of the following:
-
The string path to an executable to be called:
spawn('/usr/bin/date') # Path to date on Unix-style system. Process.wait
Output:
Thu Aug 31 10:06:48 AM CDT 2023
-
A 2-element array containing the path to an executable and the string to be used as the name of the executing process:
pid = spawn(['sleep', 'Hello!'], '1') # 2-element array. p `ps -p #{pid} -o command=`
Output:
"Hello! 1\n"
Ruby invokes the executable directly, with no shell and no shell expansion.
If one or more args
is given, each is an argument or option to be passed to the executable:
spawn('echo', 'C*') # => 799392
Process.wait # => 799392
spawn('echo', 'hello', 'world') # => 799393
Process.wait # => 799393
Output:
C*
hello world
Raises an exception if the new process could not execute.
5011 5012 5013 5014 5015 5016 5017 5018 5019 5020 5021 5022 5023 5024 5025 5026 5027 5028 5029 5030 5031 5032 5033 5034 5035 5036 |
# File 'process.c', line 5011
static VALUE
rb_f_spawn(int argc, VALUE *argv, VALUE _)
{
rb_pid_t pid;
char errmsg[CHILD_ERRMSG_BUFLEN] = { '\0' };
VALUE execarg_obj, fail_str;
struct rb_execarg *eargp;
execarg_obj = rb_execarg_new(argc, argv, TRUE, FALSE);
eargp = rb_execarg_get(execarg_obj);
fail_str = eargp->use_shell ? eargp->invoke.sh.shell_script : eargp->invoke.cmd.command_name;
pid = rb_execarg_spawn(execarg_obj, errmsg, sizeof(errmsg));
if (pid == -1) {
int err = errno;
rb_exec_fail(eargp, err, errmsg);
RB_GC_GUARD(execarg_obj);
rb_syserr_fail_str(err, fail_str);
}
#if defined(HAVE_WORKING_FORK) || defined(HAVE_SPAWNV)
return PIDT2NUM(pid);
#else
return Qnil;
#endif
}
|
.times ⇒ Object
Returns a Process::Tms structure that contains user and system CPU times for the current process, and for its children processes:
Process.times
# => #<struct Process::Tms utime=55.122118, stime=35.533068, cutime=0.0, cstime=0.002846>
The precision is platform-defined.
7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 |
# File 'process.c', line 7861
VALUE
rb_proc_times(VALUE obj)
{
VALUE utime, stime, cutime, cstime, ret;
#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
struct rusage usage_s, usage_c;
if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
rb_sys_fail("getrusage");
utime = DBL2NUM((double)usage_s.ru_utime.tv_sec + (double)usage_s.ru_utime.tv_usec/1e6);
stime = DBL2NUM((double)usage_s.ru_stime.tv_sec + (double)usage_s.ru_stime.tv_usec/1e6);
cutime = DBL2NUM((double)usage_c.ru_utime.tv_sec + (double)usage_c.ru_utime.tv_usec/1e6);
cstime = DBL2NUM((double)usage_c.ru_stime.tv_sec + (double)usage_c.ru_stime.tv_usec/1e6);
#else
const double hertz = (double)get_clk_tck();
struct tms buf;
times(&buf);
utime = DBL2NUM(buf.tms_utime / hertz);
stime = DBL2NUM(buf.tms_stime / hertz);
cutime = DBL2NUM(buf.tms_cutime / hertz);
cstime = DBL2NUM(buf.tms_cstime / hertz);
#endif
ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
RB_GC_GUARD(utime);
RB_GC_GUARD(stime);
RB_GC_GUARD(cutime);
RB_GC_GUARD(cstime);
return ret;
}
|
.uid ⇒ Integer .Process::UID.rid ⇒ Integer .Process::Sys.getuid ⇒ Integer
Returns the (real) user ID of the current process.
Process.uid # => 1000
6263 6264 6265 6266 6267 6268 |
# File 'process.c', line 6263
static VALUE
proc_getuid(VALUE obj)
{
rb_uid_t uid = getuid();
return UIDT2NUM(uid);
}
|
.uid=(new_uid) ⇒ Object
6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 |
# File 'process.c', line 6283
static VALUE
proc_setuid(VALUE obj, VALUE id)
{
rb_uid_t uid;
check_uid_switch();
uid = OBJ2UID(id);
#if defined(HAVE_SETRESUID)
if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETREUID
if (setreuid(uid, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETRUID
if (setruid(uid) < 0) rb_sys_fail(0);
#elif defined HAVE_SETUID
{
if (geteuid() == uid) {
if (setuid(uid) < 0) rb_sys_fail(0);
}
else {
rb_notimplement();
}
}
#endif
return id;
}
|
.wait(pid = -1, flags = 0) ⇒ Integer
Waits for a suitable child process to exit, returns its process ID, and sets $?
to a Process::Status object containing information on that process. Which child it waits for depends on the value of the given pid
:
-
Positive integer: Waits for the child process whose process ID is
pid
:pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 230866 pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 230891 Process.wait(pid0) # => 230866 $? # => #<Process::Status: pid 230866 exit 13> Process.wait(pid1) # => 230891 $? # => #<Process::Status: pid 230891 exit 14> Process.wait(pid0) # Raises Errno::ECHILD
-
0
: Waits for any child process whose group ID is the same as that of the current process:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end retrieved_pid = Process.wait(0) puts "Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid." begin Process.wait(0) rescue Errno::ECHILD => x puts "Raised #{x.class}, because child 1 process group ID differs from parent process group ID." end
Output:
Parent process group ID is 225764. Child 0 pid is 225788 Child 0 process group ID is 225764 (same as parent's). Child 1 pid is 225789 Child 1 process group ID is 225789 (different from parent's). Process.wait(0) returned pid 225788, which is child 0 pid. Raised Errno::ECHILD, because child 1 process group ID differs from parent process group ID.
-
-1
(default): Waits for any child process:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." sleep 3 # To force child 1 to exit later than child 0 exit. end child_pids = [child0_pid, child1_pid] retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid) retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid)
Output:
Parent process group ID is 228736. Child 0 pid is 228758 Child 0 process group ID is 228736 (same as parent's). Child 1 pid is 228759 Child 1 process group ID is 228759 (different from parent's). true true
-
Less than
-1
: Waits for any child whose process group ID is-pid
:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end sleep 1 retrieved_pid = Process.wait(-child1_pid) puts "Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid." begin Process.wait(-child1_pid) rescue Errno::ECHILD => x puts "Raised #{x.class}, because there's no longer a child with process group id #{child1_pid}." end
Output:
Parent process group ID is 230083. Child 0 pid is 230108 Child 0 process group ID is 230083 (same as parent's). Child 1 pid is 230109 Child 1 process group ID is 230109 (different from parent's). Process.wait(-child1_pid) returned pid 230109, which is child 1 pid. Raised Errno::ECHILD, because there's no longer a child with process group id 230109.
Argument flags
should be given as one of the following constants, or as the logical OR of both:
-
Process::WNOHANG: Does not block if no child process is available.
-
Process:WUNTRACED: May return a stopped child process, even if not yet reported.
Not all flags are available on all platforms.
Raises Errno::ECHILD if there is no suitable child process.
Not available on all platforms.
Process.waitpid is an alias for Process.wait.
1465 1466 1467 1468 1469 |
# File 'process.c', line 1465
static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
return proc_wait(c, v);
}
|
.wait2(pid = -1, flags = 0) ⇒ Array
1485 1486 1487 1488 1489 1490 1491 |
# File 'process.c', line 1485
static VALUE
proc_wait2(int argc, VALUE *argv, VALUE _)
{
VALUE pid = proc_wait(argc, argv);
if (NIL_P(pid)) return Qnil;
return rb_assoc_new(pid, rb_last_status_get());
}
|
.waitall ⇒ Array
Waits for all children, returns an array of 2-element arrays; each subarray contains the integer pid and Process::Status status for one of the reaped child processes:
pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 325470
pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 325495
Process.waitall
# => [[325470, #<Process::Status: pid 325470 exit 13>], [325495, #<Process::Status: pid 325495 exit 14>]]
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 |
# File 'process.c', line 1509
static VALUE
proc_waitall(VALUE _)
{
VALUE result;
rb_pid_t pid;
int status;
result = rb_ary_new();
rb_last_status_clear();
for (pid = -1;;) {
pid = rb_waitpid(-1, &status, 0);
if (pid == -1) {
int e = errno;
if (e == ECHILD)
break;
rb_syserr_fail(e, 0);
}
rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
}
return result;
}
|
.wait(pid = -1, flags = 0) ⇒ Integer
Waits for a suitable child process to exit, returns its process ID, and sets $?
to a Process::Status object containing information on that process. Which child it waits for depends on the value of the given pid
:
-
Positive integer: Waits for the child process whose process ID is
pid
:pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 230866 pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 230891 Process.wait(pid0) # => 230866 $? # => #<Process::Status: pid 230866 exit 13> Process.wait(pid1) # => 230891 $? # => #<Process::Status: pid 230891 exit 14> Process.wait(pid0) # Raises Errno::ECHILD
-
0
: Waits for any child process whose group ID is the same as that of the current process:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end retrieved_pid = Process.wait(0) puts "Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid." begin Process.wait(0) rescue Errno::ECHILD => x puts "Raised #{x.class}, because child 1 process group ID differs from parent process group ID." end
Output:
Parent process group ID is 225764. Child 0 pid is 225788 Child 0 process group ID is 225764 (same as parent's). Child 1 pid is 225789 Child 1 process group ID is 225789 (different from parent's). Process.wait(0) returned pid 225788, which is child 0 pid. Raised Errno::ECHILD, because child 1 process group ID differs from parent process group ID.
-
-1
(default): Waits for any child process:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." sleep 3 # To force child 1 to exit later than child 0 exit. end child_pids = [child0_pid, child1_pid] retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid) retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid)
Output:
Parent process group ID is 228736. Child 0 pid is 228758 Child 0 process group ID is 228736 (same as parent's). Child 1 pid is 228759 Child 1 process group ID is 228759 (different from parent's). true true
-
Less than
-1
: Waits for any child whose process group ID is-pid
:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end sleep 1 retrieved_pid = Process.wait(-child1_pid) puts "Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid." begin Process.wait(-child1_pid) rescue Errno::ECHILD => x puts "Raised #{x.class}, because there's no longer a child with process group id #{child1_pid}." end
Output:
Parent process group ID is 230083. Child 0 pid is 230108 Child 0 process group ID is 230083 (same as parent's). Child 1 pid is 230109 Child 1 process group ID is 230109 (different from parent's). Process.wait(-child1_pid) returned pid 230109, which is child 1 pid. Raised Errno::ECHILD, because there's no longer a child with process group id 230109.
Argument flags
should be given as one of the following constants, or as the logical OR of both:
-
Process::WNOHANG: Does not block if no child process is available.
-
Process:WUNTRACED: May return a stopped child process, even if not yet reported.
Not all flags are available on all platforms.
Raises Errno::ECHILD if there is no suitable child process.
Not available on all platforms.
Process.waitpid is an alias for Process.wait.
1465 1466 1467 1468 1469 |
# File 'process.c', line 1465
static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
return proc_wait(c, v);
}
|
.wait2(pid = -1, flags = 0) ⇒ Array
1485 1486 1487 1488 1489 1490 1491 |
# File 'process.c', line 1485
static VALUE
proc_wait2(int argc, VALUE *argv, VALUE _)
{
VALUE pid = proc_wait(argc, argv);
if (NIL_P(pid)) return Qnil;
return rb_assoc_new(pid, rb_last_status_get());
}
|
.warmup ⇒ true
Notify the Ruby virtual machine that the boot sequence is finished, and that now is a good time to optimize the application. This is useful for long running applications.
This method is expected to be called at the end of the application boot. If the application is deployed using a pre-forking model, Process.warmup
should be called in the original process before the first fork.
The actual optimizations performed are entirely implementation specific and may change in the future without notice.
On CRuby, Process.warmup
:
-
Performs a major GC.
-
Compacts the heap.
-
Promotes all surviving objects to the old generation.
-
Precomputes the coderange of all strings.
-
Frees all empty heap pages and increments the allocatable pages counter by the number of pages freed.
-
Invoke
malloc_trim
if available to free empty malloc pages.
8778 8779 8780 8781 8782 8783 8784 8785 |
# File 'process.c', line 8778
static VALUE
proc_warmup(VALUE _)
{
RB_VM_LOCK_ENTER();
rb_gc_prepare_heap();
RB_VM_LOCK_LEAVE();
return Qtrue;
}
|
Instance Method Details
#argv0 ⇒ Object (private)
Returns the name of the script being executed. The value is not affected by assigning a new value to $0.
This method first appeared in Ruby 2.1 to serve as a global variable free means to get the script name.
2803 2804 2805 2806 2807 |
# File 'ruby.c', line 2803
static VALUE
proc_argv0(VALUE process)
{
return rb_orig_progname;
}
|
#clock_getres(clock_id, unit = :float_second) ⇒ Numeric (private)
Returns a clock resolution as determined by POSIX function clock_getres():
Process.clock_getres(:CLOCK_REALTIME) # => 1.0e-09
See Process.clock_gettime for the values of clock_id
and unit
.
Examples:
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond) # => 0.001
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond) # => 1.0e-06
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 1.0e-09
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :microsecond) # => 0
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :millisecond) # => 0
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond) # => 1
Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID, :second) # => 0
In addition to the values for unit
supported in Process.clock_gettime, this method supports :hertz
, the integer number of clock ticks per second (which is the reciprocal of :float_second
):
Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz) # => 100.0
Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :float_second) # => 0.01
Accuracy: Note that the returned resolution may be inaccurate on some platforms due to underlying bugs. Inaccurate resolutions have been reported for various clocks including :CLOCK_MONOTONIC
and :CLOCK_MONOTONIC_RAW
on Linux, macOS, BSD or AIX platforms, when using ARM processors, or when using virtualization.
8509 8510 8511 8512 8513 8514 8515 8516 8517 8518 8519 8520 8521 8522 8523 8524 8525 8526 8527 8528 8529 8530 8531 8532 8533 8534 8535 8536 8537 8538 8539 8540 8541 8542 8543 8544 8545 8546 8547 8548 8549 8550 8551 8552 8553 8554 8555 8556 8557 8558 8559 8560 8561 8562 8563 8564 8565 8566 8567 8568 8569 8570 8571 8572 8573 8574 8575 8576 8577 8578 8579 8580 8581 8582 8583 8584 8585 8586 8587 8588 8589 8590 8591 8592 8593 8594 8595 8596 8597 8598 8599 8600 8601 8602 8603 8604 8605 8606 8607 8608 8609 8610 8611 8612 8613 8614 8615 8616 8617 8618 8619 8620 8621 8622 8623 8624 8625 8626 8627 8628 8629 8630 8631 8632 8633 8634 8635 8636 8637 8638 8639 8640 8641 8642 8643 8644 8645 8646 8647 |
# File 'process.c', line 8509
static VALUE
rb_clock_getres(int argc, VALUE *argv, VALUE _)
{
int ret;
struct timetick tt;
timetick_int_t numerators[2];
timetick_int_t denominators[2];
int num_numerators = 0;
int num_denominators = 0;
#ifdef HAVE_CLOCK_GETRES
clockid_t c;
#endif
VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
VALUE clk_id = argv[0];
if (SYMBOL_P(clk_id)) {
#ifdef CLOCK_REALTIME
if (clk_id == RUBY_CLOCK_REALTIME) {
c = CLOCK_REALTIME;
goto getres;
}
#endif
#ifdef CLOCK_MONOTONIC
if (clk_id == RUBY_CLOCK_MONOTONIC) {
c = CLOCK_MONOTONIC;
goto getres;
}
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
c = CLOCK_PROCESS_CPUTIME_ID;
goto getres;
}
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
c = CLOCK_THREAD_CPUTIME_ID;
goto getres;
}
#endif
#ifdef RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME
if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
tt.giga_count = 0;
tt.count = 1000;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#ifdef RUBY_TIME_BASED_CLOCK_REALTIME
if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
tt.giga_count = 1;
tt.count = 0;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#ifdef RUBY_TIMES_BASED_CLOCK_MONOTONIC
if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
tt.count = 1;
tt.giga_count = 0;
denominators[num_denominators++] = get_clk_tck();
goto success;
}
#endif
#ifdef RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
tt.giga_count = 0;
tt.count = 1000;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#ifdef RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
tt.count = 1;
tt.giga_count = 0;
denominators[num_denominators++] = get_clk_tck();
goto success;
}
#endif
#ifdef RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
tt.count = 1;
tt.giga_count = 0;
denominators[num_denominators++] = CLOCKS_PER_SEC;
goto success;
}
#endif
#ifdef RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
const mach_timebase_info_data_t *info = get_mach_timebase_info();
tt.count = 1;
tt.giga_count = 0;
numerators[num_numerators++] = info->numer;
denominators[num_denominators++] = info->denom;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
}
else if (NUMERIC_CLOCKID) {
#if defined(HAVE_CLOCK_GETRES)
struct timespec ts;
c = NUM2CLOCKID(clk_id);
getres:
ret = clock_getres(c, &ts);
if (ret == -1)
clock_failed("getres", errno, clk_id);
tt.count = (int32_t)ts.tv_nsec;
tt.giga_count = ts.tv_sec;
denominators[num_denominators++] = 1000000000;
goto success;
#endif
}
else {
rb_unexpected_type(clk_id, T_SYMBOL);
}
clock_failed("getres", EINVAL, clk_id);
success:
if (unit == ID2SYM(id_hertz)) {
return timetick2dblnum_reciprocal(&tt, numerators, num_numerators, denominators, num_denominators);
}
else {
return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
}
}
|
#clock_gettime(clock_id, unit = :float_second) ⇒ Numeric (private)
Returns a clock time as determined by POSIX function clock_gettime():
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID) # => 198.650379677
Argument clock_id
should be a symbol or a constant that specifies the clock whose time is to be returned; see below.
Optional argument unit
should be a symbol that specifies the unit to be used in the returned clock time; see below.
Argument clock_id
Argument clock_id
specifies the clock whose time is to be returned; it may be a constant such as Process::CLOCK_REALTIME
, or a symbol shorthand such as :CLOCK_REALTIME
.
The supported clocks depend on the underlying operating system; this method supports the following clocks on the indicated platforms (raises Errno::EINVAL if called with an unsupported clock):
-
:CLOCK_BOOTTIME
: Linux 2.6.39. -
:CLOCK_BOOTTIME_ALARM
: Linux 3.0. -
:CLOCK_MONOTONIC
: SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12, Windows-2000. -
:CLOCK_MONOTONIC_COARSE
: Linux 2.6.32. -
:CLOCK_MONOTONIC_FAST
: FreeBSD 8.1. -
:CLOCK_MONOTONIC_PRECISE
: FreeBSD 8.1. -
:CLOCK_MONOTONIC_RAW
: Linux 2.6.28, macOS 10.12. -
:CLOCK_MONOTONIC_RAW_APPROX
: macOS 10.12. -
:CLOCK_PROCESS_CPUTIME_ID
: SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12. -
:CLOCK_PROF
: FreeBSD 3.0, OpenBSD 2.1. -
:CLOCK_REALTIME
: SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12, Windows-8/Server-2012. Time.now is recommended over +:CLOCK_REALTIME:. -
:CLOCK_REALTIME_ALARM
: Linux 3.0. -
:CLOCK_REALTIME_COARSE
: Linux 2.6.32. -
:CLOCK_REALTIME_FAST
: FreeBSD 8.1. -
:CLOCK_REALTIME_PRECISE
: FreeBSD 8.1. -
:CLOCK_SECOND
: FreeBSD 8.1. -
:CLOCK_TAI
: Linux 3.10. -
:CLOCK_THREAD_CPUTIME_ID
: SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12. -
:CLOCK_UPTIME
: FreeBSD 7.0, OpenBSD 5.5. -
:CLOCK_UPTIME_FAST
: FreeBSD 8.1. -
:CLOCK_UPTIME_PRECISE
: FreeBSD 8.1. -
:CLOCK_UPTIME_RAW
: macOS 10.12. -
:CLOCK_UPTIME_RAW_APPROX
: macOS 10.12. -
:CLOCK_VIRTUAL
: FreeBSD 3.0, OpenBSD 2.1.
Note that SUS stands for Single Unix Specification. SUS contains POSIX and clock_gettime is defined in the POSIX part. SUS defines :CLOCK_REALTIME
as mandatory but :CLOCK_MONOTONIC
, :CLOCK_PROCESS_CPUTIME_ID
, and :CLOCK_THREAD_CPUTIME_ID
are optional.
Certain emulations are used when the given clock_id
is not supported directly:
-
Emulations for
:CLOCK_REALTIME
:-
:GETTIMEOFDAY_BASED_CLOCK_REALTIME
: Use gettimeofday() defined by SUS (deprecated in SUSv4). The resolution is 1 microsecond. -
:TIME_BASED_CLOCK_REALTIME
: Use time() defined by ISO C. The resolution is 1 second.
-
-
Emulations for
:CLOCK_MONOTONIC
:-
:MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC
: Use mach_absolute_time(), available on Darwin. The resolution is CPU dependent. -
:TIMES_BASED_CLOCK_MONOTONIC
: Use the result value of times() defined by POSIX, thus:Upon successful completion, times() shall return the elapsed real time, in clock ticks, since an arbitrary point in the past (for example, system start-up time).
For example, GNU/Linux returns a value based on jiffies and it is monotonic. However, 4.4BSD uses gettimeofday() and it is not monotonic. (FreeBSD uses
:CLOCK_MONOTONIC
instead, though.)The resolution is the clock tick. “getconf CLK_TCK” command shows the clock ticks per second. (The clock ticks-per-second is defined by HZ macro in older systems.) If it is 100 and clock_t is 32 bits integer type, the resolution is 10 millisecond and cannot represent over 497 days.
-
-
Emulations for
:CLOCK_PROCESS_CPUTIME_ID
:-
:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID
: Use getrusage() defined by SUS. getrusage() is used with RUSAGE_SELF to obtain the time only for the calling process (excluding the time for child processes). The result is addition of user time (ru_utime) and system time (ru_stime). The resolution is 1 microsecond. -
:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID
: Use times() defined by POSIX. The result is addition of user time (tms_utime) and system time (tms_stime). tms_cutime and tms_cstime are ignored to exclude the time for child processes. The resolution is the clock tick. “getconf CLK_TCK” command shows the clock ticks per second. (The clock ticks per second is defined by HZ macro in older systems.) If it is 100, the resolution is 10 millisecond. -
:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID
: Use clock() defined by ISO C. The resolution is1/CLOCKS_PER_SEC
.CLOCKS_PER_SEC
is the C-level macro defined by time.h. SUS definesCLOCKS_PER_SEC
as 1000000; other systems may define it differently. IfCLOCKS_PER_SEC
is 1000000 (as in SUS), the resolution is 1 microsecond. IfCLOCKS_PER_SEC
is 1000000 and clock_t is a 32-bit integer type, it cannot represent over 72 minutes.
-
Argument unit
Optional argument unit
(default :float_second
) specifies the unit for the returned value.
-
:float_microsecond
: Number of microseconds as a float. -
:float_millisecond
: Number of milliseconds as a float. -
:float_second
: Number of seconds as a float. -
:microsecond
: Number of microseconds as an integer. -
:millisecond
: Number of milliseconds as an integer. -
:nanosecond
: Number of nanoseconds as an integer. -
::second
: Number of seconds as an integer.
Examples:
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_microsecond)
# => 203605054.825
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_millisecond)
# => 203643.696848
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :float_second)
# => 203.762181929
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :microsecond)
# => 204123212
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :millisecond)
# => 204298
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :nanosecond)
# => 204602286036
Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID, :second)
# => 204
The underlying function, clock_gettime(), returns a number of nanoseconds. Float object (IEEE 754 double) is not enough to represent the return value for :CLOCK_REALTIME
. If the exact nanoseconds value is required, use :nanosecond
as the unit
.
The origin (time zero) of the returned value is system-dependent, and may be, for example, system start up time, process start up time, the Epoch, etc.
The origin in :CLOCK_REALTIME
is defined as the Epoch: 1970-01-01 00:00:00 UTC
; some systems count leap seconds and others don’t, so the result may vary across systems.
8282 8283 8284 8285 8286 8287 8288 8289 8290 8291 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 8332 8333 8334 8335 8336 8337 8338 8339 8340 8341 8342 8343 8344 8345 8346 8347 8348 8349 8350 8351 8352 8353 8354 8355 8356 8357 8358 8359 8360 8361 8362 8363 8364 8365 8366 8367 8368 8369 8370 8371 8372 8373 8374 8375 8376 8377 8378 8379 8380 8381 8382 8383 8384 8385 8386 8387 8388 8389 8390 8391 8392 8393 8394 8395 8396 8397 8398 8399 8400 8401 8402 8403 8404 8405 8406 8407 8408 8409 8410 8411 8412 8413 8414 8415 8416 8417 8418 8419 8420 8421 8422 8423 8424 8425 8426 8427 8428 8429 8430 8431 8432 8433 8434 8435 8436 8437 8438 8439 8440 8441 8442 8443 8444 8445 8446 8447 8448 8449 8450 8451 8452 8453 8454 8455 8456 8457 8458 8459 8460 8461 8462 8463 8464 8465 8466 8467 8468 8469 8470 8471 |
# File 'process.c', line 8282
static VALUE
rb_clock_gettime(int argc, VALUE *argv, VALUE _)
{
int ret;
struct timetick tt;
timetick_int_t numerators[2];
timetick_int_t denominators[2];
int num_numerators = 0;
int num_denominators = 0;
VALUE unit = (rb_check_arity(argc, 1, 2) == 2) ? argv[1] : Qnil;
VALUE clk_id = argv[0];
#ifdef HAVE_CLOCK_GETTIME
clockid_t c;
#endif
if (SYMBOL_P(clk_id)) {
#ifdef CLOCK_REALTIME
if (clk_id == RUBY_CLOCK_REALTIME) {
c = CLOCK_REALTIME;
goto gettime;
}
#endif
#ifdef CLOCK_MONOTONIC
if (clk_id == RUBY_CLOCK_MONOTONIC) {
c = CLOCK_MONOTONIC;
goto gettime;
}
#endif
#ifdef CLOCK_PROCESS_CPUTIME_ID
if (clk_id == RUBY_CLOCK_PROCESS_CPUTIME_ID) {
c = CLOCK_PROCESS_CPUTIME_ID;
goto gettime;
}
#endif
#ifdef CLOCK_THREAD_CPUTIME_ID
if (clk_id == RUBY_CLOCK_THREAD_CPUTIME_ID) {
c = CLOCK_THREAD_CPUTIME_ID;
goto gettime;
}
#endif
/*
* Non-clock_gettime clocks are provided by symbol clk_id.
*/
#ifdef HAVE_GETTIMEOFDAY
/*
* GETTIMEOFDAY_BASED_CLOCK_REALTIME is used for
* CLOCK_REALTIME if clock_gettime is not available.
*/
#define RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME ID2SYM(id_GETTIMEOFDAY_BASED_CLOCK_REALTIME)
if (clk_id == RUBY_GETTIMEOFDAY_BASED_CLOCK_REALTIME) {
struct timeval tv;
ret = gettimeofday(&tv, 0);
if (ret != 0)
rb_sys_fail("gettimeofday");
tt.giga_count = tv.tv_sec;
tt.count = (int32_t)tv.tv_usec * 1000;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#define RUBY_TIME_BASED_CLOCK_REALTIME ID2SYM(id_TIME_BASED_CLOCK_REALTIME)
if (clk_id == RUBY_TIME_BASED_CLOCK_REALTIME) {
time_t t;
t = time(NULL);
if (t == (time_t)-1)
rb_sys_fail("time");
tt.giga_count = t;
tt.count = 0;
denominators[num_denominators++] = 1000000000;
goto success;
}
#ifdef HAVE_TIMES
#define RUBY_TIMES_BASED_CLOCK_MONOTONIC \
ID2SYM(id_TIMES_BASED_CLOCK_MONOTONIC)
if (clk_id == RUBY_TIMES_BASED_CLOCK_MONOTONIC) {
struct tms buf;
clock_t c;
unsigned_clock_t uc;
c = times(&buf);
if (c == (clock_t)-1)
rb_sys_fail("times");
uc = (unsigned_clock_t)c;
tt.count = (int32_t)(uc % 1000000000);
tt.giga_count = (uc / 1000000000);
denominators[num_denominators++] = get_clk_tck();
goto success;
}
#endif
#ifdef RUSAGE_SELF
#define RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID \
ID2SYM(id_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
if (clk_id == RUBY_GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID) {
struct rusage usage;
int32_t usec;
ret = getrusage(RUSAGE_SELF, &usage);
if (ret != 0)
rb_sys_fail("getrusage");
tt.giga_count = usage.ru_utime.tv_sec + usage.ru_stime.tv_sec;
usec = (int32_t)(usage.ru_utime.tv_usec + usage.ru_stime.tv_usec);
if (1000000 <= usec) {
tt.giga_count++;
usec -= 1000000;
}
tt.count = usec * 1000;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
#ifdef HAVE_TIMES
#define RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID \
ID2SYM(id_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID)
if (clk_id == RUBY_TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID) {
struct tms buf;
unsigned_clock_t utime, stime;
if (times(&buf) == (clock_t)-1)
rb_sys_fail("times");
utime = (unsigned_clock_t)buf.tms_utime;
stime = (unsigned_clock_t)buf.tms_stime;
tt.count = (int32_t)((utime % 1000000000) + (stime % 1000000000));
tt.giga_count = (utime / 1000000000) + (stime / 1000000000);
if (1000000000 <= tt.count) {
tt.count -= 1000000000;
tt.giga_count++;
}
denominators[num_denominators++] = get_clk_tck();
goto success;
}
#endif
#define RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID \
ID2SYM(id_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID)
if (clk_id == RUBY_CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID) {
clock_t c;
unsigned_clock_t uc;
errno = 0;
c = clock();
if (c == (clock_t)-1)
rb_sys_fail("clock");
uc = (unsigned_clock_t)c;
tt.count = (int32_t)(uc % 1000000000);
tt.giga_count = uc / 1000000000;
denominators[num_denominators++] = CLOCKS_PER_SEC;
goto success;
}
#ifdef __APPLE__
if (clk_id == RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC) {
const mach_timebase_info_data_t *info = get_mach_timebase_info();
uint64_t t = mach_absolute_time();
tt.count = (int32_t)(t % 1000000000);
tt.giga_count = t / 1000000000;
numerators[num_numerators++] = info->numer;
denominators[num_denominators++] = info->denom;
denominators[num_denominators++] = 1000000000;
goto success;
}
#endif
}
else if (NUMERIC_CLOCKID) {
#if defined(HAVE_CLOCK_GETTIME)
struct timespec ts;
c = NUM2CLOCKID(clk_id);
gettime:
ret = clock_gettime(c, &ts);
if (ret == -1)
clock_failed("gettime", errno, clk_id);
tt.count = (int32_t)ts.tv_nsec;
tt.giga_count = ts.tv_sec;
denominators[num_denominators++] = 1000000000;
goto success;
#endif
}
else {
rb_unexpected_type(clk_id, T_SYMBOL);
}
clock_failed("gettime", EINVAL, clk_id);
success:
return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);
}
|
#daemon(nochdir = nil, noclose = nil) ⇒ 0 (private)
Detaches the current process from its controlling terminal and runs it in the background as system daemon; returns zero.
By default:
-
Changes the current working directory to the root directory.
-
Redirects $stdin, $stdout, and $stderr to the null device.
If optional argument nochdir
is true
, does not change the current working directory.
If optional argument noclose
is true
, does not redirect $stdin, $stdout, or $stderr.
6972 6973 6974 6975 6976 6977 6978 6979 6980 6981 6982 6983 6984 6985 6986 |
# File 'process.c', line 6972
static VALUE
proc_daemon(int argc, VALUE *argv, VALUE _)
{
int n, nochdir = FALSE, noclose = FALSE;
switch (rb_check_arity(argc, 0, 2)) {
case 2: noclose = TO_BOOL(argv[1], "noclose");
case 1: nochdir = TO_BOOL(argv[0], "nochdir");
}
prefork();
n = rb_daemon(nochdir, noclose);
if (n < 0) rb_sys_fail("daemon");
return INT2FIX(n);
}
|
#detach(pid) ⇒ Object (private)
Avoids the potential for a child process to become a zombie process. Process.detach prevents this by setting up a separate Ruby thread whose sole job is to reap the status of the process pid when it terminates.
This method is needed only when the parent process will never wait for the child process.
This example does not reap the second child process; that process appears as a zombie in the process status (ps
) output:
pid = Process.spawn('ruby', '-e', 'exit 13') # => 312691
sleep(1)
# Find zombies.
system("ps -ho pid,state -p #{pid}")
Output:
312716 Z
This example also does not reap the second child process, but it does detach the process so that it does not become a zombie:
pid = Process.spawn('ruby', '-e', 'exit 13') # => 313213
thread = Process.detach(pid)
sleep(1)
# => #<Process::Waiter:0x00007f038f48b838 run>
system("ps -ho pid,state -p #{pid}") # Finds no zombies.
The waiting thread can return the pid of the detached child process:
thread.join.pid # => 313262
1601 1602 1603 1604 1605 |
# File 'process.c', line 1601
static VALUE
proc_detach(VALUE obj, VALUE pid)
{
return rb_detach_process(NUM2PIDT(pid));
}
|
#egid ⇒ Integer (private) #Process::GID.eid ⇒ Integer (private) #Process::Sys.geteid ⇒ Integer (private)
7362 7363 7364 7365 7366 7367 7368 |
# File 'process.c', line 7362
static VALUE
proc_getegid(VALUE obj)
{
rb_gid_t egid = getegid();
return GIDT2NUM(egid);
}
|
#egid= ⇒ Object (private)
#euid ⇒ Integer (private) #Process::UID.eid ⇒ Integer (private) #Process::Sys.geteuid ⇒ Integer (private)
7236 7237 7238 7239 7240 7241 |
# File 'process.c', line 7236
static VALUE
proc_geteuid(VALUE obj)
{
rb_uid_t euid = geteuid();
return UIDT2NUM(euid);
}
|
#euid=(new_euid) ⇒ Object (private)
Sets the effective user ID for the current process.
Not available on all platforms.
7276 7277 7278 7279 7280 7281 7282 |
# File 'process.c', line 7276
static VALUE
proc_seteuid_m(VALUE mod, VALUE euid)
{
check_uid_switch();
proc_seteuid(OBJ2UID(euid));
return euid;
}
|
#getpgid(pid) ⇒ Integer (private)
5152 5153 5154 5155 5156 5157 5158 5159 5160 |
# File 'process.c', line 5152
static VALUE
proc_getpgid(VALUE obj, VALUE pid)
{
rb_pid_t i;
i = getpgid(NUM2PIDT(pid));
if (i < 0) rb_sys_fail(0);
return PIDT2NUM(i);
}
|
#getpgrp ⇒ Integer (private)
5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 5104 5105 |
# File 'process.c', line 5091
static VALUE
proc_getpgrp(VALUE _)
{
rb_pid_t pgrp;
#if defined(HAVE_GETPGRP) && defined(GETPGRP_VOID)
pgrp = getpgrp();
if (pgrp < 0) rb_sys_fail(0);
return PIDT2NUM(pgrp);
#else /* defined(HAVE_GETPGID) */
pgrp = getpgid(0);
if (pgrp < 0) rb_sys_fail(0);
return PIDT2NUM(pgrp);
#endif
}
|
#getpriority(kind, id) ⇒ Integer (private)
Returns the scheduling priority for specified process, process group, or user.
Argument kind
is one of:
-
Process::PRIO_PROCESS: return priority for process.
-
Process::PRIO_PGRP: return priority for process group.
-
Process::PRIO_USER: return priority for user.
Argument id
is the ID for the process, process group, or user; zero specified the current ID for kind
.
Examples:
Process.getpriority(Process::PRIO_USER, 0) # => 19
Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
Not available on all platforms.
5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 |
# File 'process.c', line 5310
static VALUE
proc_getpriority(VALUE obj, VALUE which, VALUE who)
{
int prio, iwhich, iwho;
iwhich = NUM2INT(which);
iwho = NUM2INT(who);
errno = 0;
prio = getpriority(iwhich, iwho);
if (errno) rb_sys_fail(0);
return INT2FIX(prio);
}
|
#getrlimit(resource) ⇒ Array (private)
Returns a 2-element array of the current (soft) limit and maximum (hard) limit for the given resource
.
Argument resource
specifies the resource whose limits are to be returned; see Process.setrlimit.
Each of the returned values cur_limit
and max_limit
is an integer; see Process.setrlimit.
Example:
Process.getrlimit(:CORE) # => [0, 18446744073709551615]
See Process.setrlimit.
Not available on all platforms.
5610 5611 5612 5613 5614 5615 5616 5617 5618 5619 |
# File 'process.c', line 5610
static VALUE
proc_getrlimit(VALUE obj, VALUE resource)
{
struct rlimit rlim;
if (getrlimit(rlimit_resource_type(resource), &rlim) < 0) {
rb_sys_fail("getrlimit");
}
return rb_assoc_new(RLIM2NUM(rlim.rlim_cur), RLIM2NUM(rlim.rlim_max));
}
|
#getsid(pid = nil) ⇒ Integer (private)
5207 5208 5209 5210 5211 5212 5213 5214 5215 5216 5217 5218 5219 |
# File 'process.c', line 5207
static VALUE
proc_getsid(int argc, VALUE *argv, VALUE _)
{
rb_pid_t sid;
rb_pid_t pid = 0;
if (rb_check_arity(argc, 0, 1) == 1 && !NIL_P(argv[0]))
pid = NUM2PIDT(argv[0]);
sid = getsid(pid);
if (sid < 0) rb_sys_fail(0);
return PIDT2NUM(sid);
}
|
#gid ⇒ Integer (private) #Process::GID.rid ⇒ Integer (private) #Process::Sys.getgid ⇒ Integer (private)
6665 6666 6667 6668 6669 6670 |
# File 'process.c', line 6665
static VALUE
proc_getgid(VALUE obj)
{
rb_gid_t gid = getgid();
return GIDT2NUM(gid);
}
|
#gid=(new_gid) ⇒ Object (private)
6684 6685 6686 6687 6688 6689 6690 6691 6692 6693 6694 6695 6696 6697 6698 6699 6700 6701 6702 6703 6704 6705 6706 6707 6708 6709 |
# File 'process.c', line 6684
static VALUE
proc_setgid(VALUE obj, VALUE id)
{
rb_gid_t gid;
check_gid_switch();
gid = OBJ2GID(id);
#if defined(HAVE_SETRESGID)
if (setresgid(gid, -1, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETREGID
if (setregid(gid, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETRGID
if (setrgid(gid) < 0) rb_sys_fail(0);
#elif defined HAVE_SETGID
{
if (getegid() == gid) {
if (setgid(gid) < 0) rb_sys_fail(0);
}
else {
rb_notimplement();
}
}
#endif
return GIDT2NUM(gid);
}
|
#groups ⇒ Array (private)
Returns an array of the group IDs in the supplemental group access list for the current process:
Process.groups # => [4, 24, 27, 30, 46, 122, 135, 136, 1000]
These properties of the returned array are system-dependent:
-
Whether (and how) the array is sorted.
-
Whether the array includes effective group IDs.
-
Whether the array includes duplicate group IDs.
-
Whether the array size exceeds the value of Process.maxgroups.
Use this call to get a sorted and unique array:
Process.groups.uniq.sort
6785 6786 6787 6788 6789 6790 6791 6792 6793 6794 6795 6796 6797 6798 6799 6800 6801 6802 6803 6804 6805 6806 6807 6808 6809 |
# File 'process.c', line 6785
static VALUE
proc_getgroups(VALUE obj)
{
VALUE ary, tmp;
int i, ngroups;
rb_gid_t *groups;
ngroups = getgroups(0, NULL);
if (ngroups == -1)
rb_sys_fail(0);
groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
ngroups = getgroups(ngroups, groups);
if (ngroups == -1)
rb_sys_fail(0);
ary = rb_ary_new();
for (i = 0; i < ngroups; i++)
rb_ary_push(ary, GIDT2NUM(groups[i]));
ALLOCV_END(tmp);
return ary;
}
|
#groups=(new_groups) ⇒ Object (private)
6829 6830 6831 6832 6833 6834 6835 6836 6837 6838 6839 6840 6841 6842 6843 6844 6845 6846 6847 6848 6849 6850 6851 6852 6853 6854 6855 6856 6857 6858 |
# File 'process.c', line 6829
static VALUE
proc_setgroups(VALUE obj, VALUE ary)
{
int ngroups, i;
rb_gid_t *groups;
VALUE tmp;
PREPARE_GETGRNAM;
Check_Type(ary, T_ARRAY);
ngroups = RARRAY_LENINT(ary);
if (ngroups > maxgroups())
rb_raise(rb_eArgError, "too many groups, %d max", maxgroups());
groups = ALLOCV_N(rb_gid_t, tmp, ngroups);
for (i = 0; i < ngroups; i++) {
VALUE g = RARRAY_AREF(ary, i);
groups[i] = OBJ2GID1(g);
}
FINISH_GETGRNAM;
if (setgroups(ngroups, groups) == -1) /* ngroups <= maxgroups */
rb_sys_fail(0);
ALLOCV_END(tmp);
return proc_getgroups(obj);
}
|
#initgroups(username, gid) ⇒ Array (private)
Sets the supplemental group access list; the new list includes:
-
The group IDs of those groups to which the user given by
username
belongs. -
The group ID
gid
.
Example:
Process.groups # => [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27]
Process.initgroups('me', 30) # => [30, 6, 10, 11]
Process.groups # => [30, 6, 10, 11]
Not available on all platforms.
6884 6885 6886 6887 6888 6889 6890 6891 |
# File 'process.c', line 6884
static VALUE
proc_initgroups(VALUE obj, VALUE uname, VALUE base_grp)
{
if (initgroups(StringValueCStr(uname), OBJ2GID(base_grp)) != 0) {
rb_sys_fail(0);
}
return proc_getgroups(obj);
}
|
#kill(signal, *ids) ⇒ Object (private)
Sends a signal to each process specified by ids
(which must specify at least one ID); returns the count of signals sent.
For each given id
, if id
is:
-
Positive, sends the signal to the process whose process ID is
id
. -
Zero, send the signal to all processes in the current process group.
-
Negative, sends the signal to a system-dependent collection of processes.
Argument signal
specifies the signal to be sent; the argument may be:
-
An integer signal number: e.g.,
-29
,0
,29
. -
A signal name (string), with or without leading
'SIG'
, and with or without a further prefixed minus sign ('-'
): e.g.:-
'SIGPOLL'
. -
'POLL'
, -
'-SIGPOLL'
. -
'-POLL'
.
-
-
A signal symbol, with or without leading
'SIG'
, and with or without a further prefixed minus sign ('-'
): e.g.:-
:SIGPOLL
. -
:POLL
. -
:'-SIGPOLL'
. -
:'-POLL'
.
-
If signal
is:
-
A non-negative integer, or a signal name or symbol without prefixed
'-'
, each process with process IDid
is signalled. -
A negative integer, or a signal name or symbol with prefixed
'-'
, each process group with group IDid
is signalled.
Use method Signal.list to see which signals are supported by Ruby on the underlying platform; the method returns a hash of the string names and non-negative integer values of the supported signals. The size and content of the returned hash varies widely among platforms.
Additionally, signal 0
is useful to determine if the process exists.
Example:
pid = fork do
Signal.trap('HUP') { puts 'Ouch!'; exit }
# ... do some work ...
end
# ...
Process.kill('HUP', pid)
Process.wait
Output:
Ouch!
Exceptions:
-
Raises Errno::EINVAL or RangeError if
signal
is an integer but invalid. -
Raises ArgumentError if
signal
is a string or symbol but invalid. -
Raises Errno::ESRCH or RangeError if one of
ids
is invalid. -
Raises Errno::EPERM if needed permissions are not in force.
In the last two cases, signals may have been sent to some processes.
8741 8742 8743 8744 8745 |
# File 'process.c', line 8741
static VALUE
proc_rb_f_kill(int c, const VALUE *v, VALUE _)
{
return rb_f_kill(c, v);
}
|
#maxgroups ⇒ Integer (private)
6908 6909 6910 6911 6912 |
# File 'process.c', line 6908
static VALUE
proc_getmaxgroups(VALUE obj)
{
return INT2FIX(maxgroups());
}
|
#maxgroups=(new_max) ⇒ Object (private)
Sets the maximum number of group IDs allowed in the supplemental group access list.
6926 6927 6928 6929 6930 6931 6932 6933 6934 6935 6936 6937 6938 6939 6940 6941 6942 6943 6944 |
# File 'process.c', line 6926
static VALUE
proc_setmaxgroups(VALUE obj, VALUE val)
{
int ngroups = FIX2INT(val);
int ngroups_max = get_sc_ngroups_max();
if (ngroups <= 0)
rb_raise(rb_eArgError, "maxgroups %d should be positive", ngroups);
if (ngroups > RB_MAX_GROUPS)
ngroups = RB_MAX_GROUPS;
if (ngroups_max > 0 && ngroups > ngroups_max)
ngroups = ngroups_max;
_maxgroups = ngroups;
return INT2FIX(_maxgroups);
}
|
#pid ⇒ Integer (private)
529 530 531 532 533 |
# File 'process.c', line 529
static VALUE
proc_get_pid(VALUE _)
{
return get_pid();
}
|
#ppid ⇒ Integer (private)
558 559 560 561 562 |
# File 'process.c', line 558
static VALUE
proc_get_ppid(VALUE _)
{
return get_ppid();
}
|
#setpgid(pid, pgid) ⇒ 0 (private)
Sets the process group ID for the process given by process ID pid
to pgid
.
Not available on all platforms.
5177 5178 5179 5180 5181 5182 5183 5184 5185 5186 5187 |
# File 'process.c', line 5177
static VALUE
proc_setpgid(VALUE obj, VALUE pid, VALUE pgrp)
{
rb_pid_t ipid, ipgrp;
ipid = NUM2PIDT(pid);
ipgrp = NUM2PIDT(pgrp);
if (setpgid(ipid, ipgrp) < 0) rb_sys_fail(0);
return INT2FIX(0);
}
|
#setpgrp ⇒ 0 (private)
Equivalent to setpgid(0, 0)
.
Not available on all platforms.
5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 |
# File 'process.c', line 5121
static VALUE
proc_setpgrp(VALUE _)
{
/* check for posix setpgid() first; this matches the posix */
/* getpgrp() above. It appears that configure will set SETPGRP_VOID */
/* even though setpgrp(0,0) would be preferred. The posix call avoids */
/* this confusion. */
#ifdef HAVE_SETPGID
if (setpgid(0,0) < 0) rb_sys_fail(0);
#elif defined(HAVE_SETPGRP) && defined(SETPGRP_VOID)
if (setpgrp() < 0) rb_sys_fail(0);
#endif
return INT2FIX(0);
}
|
#setpriority(kind, integer, priority) ⇒ 0 (private)
See Process.getpriority.
Examples:
Process.setpriority(Process::PRIO_USER, 0, 19) # => 0
Process.setpriority(Process::PRIO_PROCESS, 0, 19) # => 0
Process.getpriority(Process::PRIO_USER, 0) # => 19
Process.getpriority(Process::PRIO_PROCESS, 0) # => 19
Not available on all platforms.
5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 |
# File 'process.c', line 5345
static VALUE
proc_setpriority(VALUE obj, VALUE which, VALUE who, VALUE prio)
{
int iwhich, iwho, iprio;
iwhich = NUM2INT(which);
iwho = NUM2INT(who);
iprio = NUM2INT(prio);
if (setpriority(iwhich, iwho, iprio) < 0)
rb_sys_fail(0);
return INT2FIX(0);
}
|
#setproctitle(string) ⇒ String (private)
Sets the process title that appears on the ps(1) command. Not necessarily effective on all platforms. No exception will be raised regardless of the result, nor will NotImplementedError be raised even if the platform does not support the feature.
Calling this method does not affect the value of $0.
Process.setproctitle('myapp: worker #%d' % worker_id)
This method first appeared in Ruby 2.1 to serve as a global variable free means to change the process title.
2828 2829 2830 2831 2832 |
# File 'ruby.c', line 2828
static VALUE
proc_setproctitle(VALUE process, VALUE title)
{
return ruby_setproctitle(title);
}
|
#setrlimit(resource, cur_limit, max_limit = cur_limit) ⇒ nil (private)
Sets limits for the current process for the given resource
to cur_limit
(soft limit) and max_limit
(hard limit); returns nil
.
Argument resource
specifies the resource whose limits are to be set; the argument may be given as a symbol, as a string, or as a constant beginning with Process::RLIMIT_
(e.g., :CORE
, 'CORE'
, or Process::RLIMIT_CORE
.
The resources available and supported are system-dependent, and may include (here expressed as symbols):
-
:AS
: Total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD except 4.4BSD-Lite). -
:CORE
: Core size (bytes) (SUSv3). -
:CPU
: CPU time (seconds) (SUSv3). -
:DATA
: Data segment (bytes) (SUSv3). -
:FSIZE
: File size (bytes) (SUSv3). -
:MEMLOCK
: Total size for mlock(2) (bytes) (4.4BSD, GNU/Linux). -
:MSGQUEUE
: Allocation for POSIX message queues (bytes) (GNU/Linux). -
:NICE
: Ceiling on process’s nice(2) value (number) (GNU/Linux). -
:NOFILE
: File descriptors (number) (SUSv3). -
:NPROC
: Number of processes for the user (number) (4.4BSD, GNU/Linux). -
:NPTS
: Number of pseudo terminals (number) (FreeBSD). -
:RSS
: Resident memory size (bytes) (4.2BSD, GNU/Linux). -
:RTPRIO
: Ceiling on the process’s real-time priority (number) (GNU/Linux). -
:RTTIME
: CPU time for real-time process (us) (GNU/Linux). -
:SBSIZE
: All socket buffers (bytes) (NetBSD, FreeBSD). -
:SIGPENDING
: Number of queued signals allowed (signals) (GNU/Linux). -
:STACK
: Stack size (bytes) (SUSv3).
Arguments cur_limit
and max_limit
may be:
-
Integers (
max_limit
should not be smaller thancur_limit
). -
Symbol
:SAVED_MAX
, string'SAVED_MAX'
, or constantProcess::RLIM_SAVED_MAX
: saved maximum limit. -
Symbol
:SAVED_CUR
, string'SAVED_CUR'
, or constantProcess::RLIM_SAVED_CUR
: saved current limit. -
Symbol
:INFINITY
, string'INFINITY'
, or constantProcess::RLIM_INFINITY
: no limit on resource.
This example raises the soft limit of core size to the hard limit to try to make core dump possible:
Process.setrlimit(:CORE, Process.getrlimit(:CORE)[1])
Not available on all platforms.
5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 |
# File 'process.c', line 5677
static VALUE
proc_setrlimit(int argc, VALUE *argv, VALUE obj)
{
VALUE resource, rlim_cur, rlim_max;
struct rlimit rlim;
rb_check_arity(argc, 2, 3);
resource = argv[0];
rlim_cur = argv[1];
if (argc < 3 || NIL_P(rlim_max = argv[2]))
rlim_max = rlim_cur;
rlim.rlim_cur = rlimit_resource_value(rlim_cur);
rlim.rlim_max = rlimit_resource_value(rlim_max);
if (setrlimit(rlimit_resource_type(resource), &rlim) < 0) {
rb_sys_fail("setrlimit");
}
return Qnil;
}
|
#setsid ⇒ Integer (private)
5243 5244 5245 5246 5247 5248 5249 5250 5251 |
# File 'process.c', line 5243
static VALUE
proc_setsid(VALUE _)
{
rb_pid_t pid;
pid = setsid();
if (pid < 0) rb_sys_fail(0);
return PIDT2NUM(pid);
}
|
#times ⇒ Object (private)
7861 7862 7863 7864 7865 7866 7867 7868 7869 7870 7871 7872 7873 7874 7875 7876 7877 7878 7879 7880 7881 7882 7883 7884 7885 7886 7887 7888 7889 7890 |
# File 'process.c', line 7861
VALUE
rb_proc_times(VALUE obj)
{
VALUE utime, stime, cutime, cstime, ret;
#if defined(RUSAGE_SELF) && defined(RUSAGE_CHILDREN)
struct rusage usage_s, usage_c;
if (getrusage(RUSAGE_SELF, &usage_s) != 0 || getrusage(RUSAGE_CHILDREN, &usage_c) != 0)
rb_sys_fail("getrusage");
utime = DBL2NUM((double)usage_s.ru_utime.tv_sec + (double)usage_s.ru_utime.tv_usec/1e6);
stime = DBL2NUM((double)usage_s.ru_stime.tv_sec + (double)usage_s.ru_stime.tv_usec/1e6);
cutime = DBL2NUM((double)usage_c.ru_utime.tv_sec + (double)usage_c.ru_utime.tv_usec/1e6);
cstime = DBL2NUM((double)usage_c.ru_stime.tv_sec + (double)usage_c.ru_stime.tv_usec/1e6);
#else
const double hertz = (double)get_clk_tck();
struct tms buf;
times(&buf);
utime = DBL2NUM(buf.tms_utime / hertz);
stime = DBL2NUM(buf.tms_stime / hertz);
cutime = DBL2NUM(buf.tms_cutime / hertz);
cstime = DBL2NUM(buf.tms_cstime / hertz);
#endif
ret = rb_struct_new(rb_cProcessTms, utime, stime, cutime, cstime);
RB_GC_GUARD(utime);
RB_GC_GUARD(stime);
RB_GC_GUARD(cutime);
RB_GC_GUARD(cstime);
return ret;
}
|
#uid ⇒ Integer (private) #Process::UID.rid ⇒ Integer (private) #Process::Sys.getuid ⇒ Integer (private)
6263 6264 6265 6266 6267 6268 |
# File 'process.c', line 6263
static VALUE
proc_getuid(VALUE obj)
{
rb_uid_t uid = getuid();
return UIDT2NUM(uid);
}
|
#uid=(new_uid) ⇒ Object (private)
6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 6295 6296 6297 6298 6299 6300 6301 6302 6303 6304 6305 6306 6307 6308 |
# File 'process.c', line 6283
static VALUE
proc_setuid(VALUE obj, VALUE id)
{
rb_uid_t uid;
check_uid_switch();
uid = OBJ2UID(id);
#if defined(HAVE_SETRESUID)
if (setresuid(uid, -1, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETREUID
if (setreuid(uid, -1) < 0) rb_sys_fail(0);
#elif defined HAVE_SETRUID
if (setruid(uid) < 0) rb_sys_fail(0);
#elif defined HAVE_SETUID
{
if (geteuid() == uid) {
if (setuid(uid) < 0) rb_sys_fail(0);
}
else {
rb_notimplement();
}
}
#endif
return id;
}
|
#wait(pid = -1, flags = 0) ⇒ Integer (private)
Waits for a suitable child process to exit, returns its process ID, and sets $?
to a Process::Status object containing information on that process. Which child it waits for depends on the value of the given pid
:
-
Positive integer: Waits for the child process whose process ID is
pid
:pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 230866 pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 230891 Process.wait(pid0) # => 230866 $? # => #<Process::Status: pid 230866 exit 13> Process.wait(pid1) # => 230891 $? # => #<Process::Status: pid 230891 exit 14> Process.wait(pid0) # Raises Errno::ECHILD
-
0
: Waits for any child process whose group ID is the same as that of the current process:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end retrieved_pid = Process.wait(0) puts "Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid." begin Process.wait(0) rescue Errno::ECHILD => x puts "Raised #{x.class}, because child 1 process group ID differs from parent process group ID." end
Output:
Parent process group ID is 225764. Child 0 pid is 225788 Child 0 process group ID is 225764 (same as parent's). Child 1 pid is 225789 Child 1 process group ID is 225789 (different from parent's). Process.wait(0) returned pid 225788, which is child 0 pid. Raised Errno::ECHILD, because child 1 process group ID differs from parent process group ID.
-
-1
(default): Waits for any child process:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." sleep 3 # To force child 1 to exit later than child 0 exit. end child_pids = [child0_pid, child1_pid] retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid) retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid)
Output:
Parent process group ID is 228736. Child 0 pid is 228758 Child 0 process group ID is 228736 (same as parent's). Child 1 pid is 228759 Child 1 process group ID is 228759 (different from parent's). true true
-
Less than
-1
: Waits for any child whose process group ID is-pid
:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end sleep 1 retrieved_pid = Process.wait(-child1_pid) puts "Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid." begin Process.wait(-child1_pid) rescue Errno::ECHILD => x puts "Raised #{x.class}, because there's no longer a child with process group id #{child1_pid}." end
Output:
Parent process group ID is 230083. Child 0 pid is 230108 Child 0 process group ID is 230083 (same as parent's). Child 1 pid is 230109 Child 1 process group ID is 230109 (different from parent's). Process.wait(-child1_pid) returned pid 230109, which is child 1 pid. Raised Errno::ECHILD, because there's no longer a child with process group id 230109.
Argument flags
should be given as one of the following constants, or as the logical OR of both:
-
Process::WNOHANG: Does not block if no child process is available.
-
Process:WUNTRACED: May return a stopped child process, even if not yet reported.
Not all flags are available on all platforms.
Raises Errno::ECHILD if there is no suitable child process.
Not available on all platforms.
Process.waitpid is an alias for Process.wait.
1465 1466 1467 1468 1469 |
# File 'process.c', line 1465
static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
return proc_wait(c, v);
}
|
#wait2(pid = -1, flags = 0) ⇒ Array (private)
1485 1486 1487 1488 1489 1490 1491 |
# File 'process.c', line 1485
static VALUE
proc_wait2(int argc, VALUE *argv, VALUE _)
{
VALUE pid = proc_wait(argc, argv);
if (NIL_P(pid)) return Qnil;
return rb_assoc_new(pid, rb_last_status_get());
}
|
#waitall ⇒ Array (private)
Waits for all children, returns an array of 2-element arrays; each subarray contains the integer pid and Process::Status status for one of the reaped child processes:
pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 325470
pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 325495
Process.waitall
# => [[325470, #<Process::Status: pid 325470 exit 13>], [325495, #<Process::Status: pid 325495 exit 14>]]
1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 |
# File 'process.c', line 1509
static VALUE
proc_waitall(VALUE _)
{
VALUE result;
rb_pid_t pid;
int status;
result = rb_ary_new();
rb_last_status_clear();
for (pid = -1;;) {
pid = rb_waitpid(-1, &status, 0);
if (pid == -1) {
int e = errno;
if (e == ECHILD)
break;
rb_syserr_fail(e, 0);
}
rb_ary_push(result, rb_assoc_new(PIDT2NUM(pid), rb_last_status_get()));
}
return result;
}
|
#wait(pid = -1, flags = 0) ⇒ Integer (private)
Waits for a suitable child process to exit, returns its process ID, and sets $?
to a Process::Status object containing information on that process. Which child it waits for depends on the value of the given pid
:
-
Positive integer: Waits for the child process whose process ID is
pid
:pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 230866 pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 230891 Process.wait(pid0) # => 230866 $? # => #<Process::Status: pid 230866 exit 13> Process.wait(pid1) # => 230891 $? # => #<Process::Status: pid 230891 exit 14> Process.wait(pid0) # Raises Errno::ECHILD
-
0
: Waits for any child process whose group ID is the same as that of the current process:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end retrieved_pid = Process.wait(0) puts "Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid." begin Process.wait(0) rescue Errno::ECHILD => x puts "Raised #{x.class}, because child 1 process group ID differs from parent process group ID." end
Output:
Parent process group ID is 225764. Child 0 pid is 225788 Child 0 process group ID is 225764 (same as parent's). Child 1 pid is 225789 Child 1 process group ID is 225789 (different from parent's). Process.wait(0) returned pid 225788, which is child 0 pid. Raised Errno::ECHILD, because child 1 process group ID differs from parent process group ID.
-
-1
(default): Waits for any child process:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." sleep 3 # To force child 1 to exit later than child 0 exit. end child_pids = [child0_pid, child1_pid] retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid) retrieved_pid = Process.wait(-1) puts child_pids.include?(retrieved_pid)
Output:
Parent process group ID is 228736. Child 0 pid is 228758 Child 0 process group ID is 228736 (same as parent's). Child 1 pid is 228759 Child 1 process group ID is 228759 (different from parent's). true true
-
Less than
-1
: Waits for any child whose process group ID is-pid
:parent_pgpid = Process.getpgid(Process.pid) puts "Parent process group ID is #{parent_pgpid}." child0_pid = fork do puts "Child 0 pid is #{Process.pid}" child0_pgid = Process.getpgid(Process.pid) puts "Child 0 process group ID is #{child0_pgid} (same as parent's)." end child1_pid = fork do puts "Child 1 pid is #{Process.pid}" Process.setpgid(0, Process.pid) child1_pgid = Process.getpgid(Process.pid) puts "Child 1 process group ID is #{child1_pgid} (different from parent's)." end sleep 1 retrieved_pid = Process.wait(-child1_pid) puts "Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid." begin Process.wait(-child1_pid) rescue Errno::ECHILD => x puts "Raised #{x.class}, because there's no longer a child with process group id #{child1_pid}." end
Output:
Parent process group ID is 230083. Child 0 pid is 230108 Child 0 process group ID is 230083 (same as parent's). Child 1 pid is 230109 Child 1 process group ID is 230109 (different from parent's). Process.wait(-child1_pid) returned pid 230109, which is child 1 pid. Raised Errno::ECHILD, because there's no longer a child with process group id 230109.
Argument flags
should be given as one of the following constants, or as the logical OR of both:
-
Process::WNOHANG: Does not block if no child process is available.
-
Process:WUNTRACED: May return a stopped child process, even if not yet reported.
Not all flags are available on all platforms.
Raises Errno::ECHILD if there is no suitable child process.
Not available on all platforms.
Process.waitpid is an alias for Process.wait.
1465 1466 1467 1468 1469 |
# File 'process.c', line 1465
static VALUE
proc_m_wait(int c, VALUE *v, VALUE _)
{
return proc_wait(c, v);
}
|
#wait2(pid = -1, flags = 0) ⇒ Array (private)
1485 1486 1487 1488 1489 1490 1491 |
# File 'process.c', line 1485
static VALUE
proc_wait2(int argc, VALUE *argv, VALUE _)
{
VALUE pid = proc_wait(argc, argv);
if (NIL_P(pid)) return Qnil;
return rb_assoc_new(pid, rb_last_status_get());
}
|
#warmup ⇒ true (private)
Notify the Ruby virtual machine that the boot sequence is finished, and that now is a good time to optimize the application. This is useful for long running applications.
This method is expected to be called at the end of the application boot. If the application is deployed using a pre-forking model, Process.warmup
should be called in the original process before the first fork.
The actual optimizations performed are entirely implementation specific and may change in the future without notice.
On CRuby, Process.warmup
:
-
Performs a major GC.
-
Compacts the heap.
-
Promotes all surviving objects to the old generation.
-
Precomputes the coderange of all strings.
-
Frees all empty heap pages and increments the allocatable pages counter by the number of pages freed.
-
Invoke
malloc_trim
if available to free empty malloc pages.
8778 8779 8780 8781 8782 8783 8784 8785 |
# File 'process.c', line 8778
static VALUE
proc_warmup(VALUE _)
{
RB_VM_LOCK_ENTER();
rb_gc_prepare_heap();
RB_VM_LOCK_LEAVE();
return Qtrue;
}
|