# # The module contains several groups of functionality for handling OS processes: # # * Low-level property introspection and management of the current process, # like Process.argv0, Process.pid; # * Low-level introspection of other processes, like Process.getpgid, # Process.getpriority; # * Management of the current process: Process.abort, Process.exit, # Process.daemon, etc. (for convenience, most of those are also available as # global functions and module functions of Kernel); # * Creation and management of child processes: Process.fork, Process.spawn, # and related methods; # * Management of low-level system clock: Process.times and # Process.clock_gettime, which could be important for proper benchmarking # and other elapsed time measurement tasks. # module Process # # 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](https://bugs.ruby-lang.org/issues/18911) for a more detailed discussion # of this. # def self._fork: () -> Integer # # 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. # def self.argv0: () -> String # # Returns an estimate of the resolution of a `clock_id` using the POSIX # `clock_getres()` function. # # Note the reported resolution is often inaccurate on most platforms due to # underlying bugs for this function and therefore the reported resolution often # differs from the actual resolution of the clock in practice. Inaccurate # reported resolutions have been observed for various clocks including # CLOCK_MONOTONIC and CLOCK_MONOTONIC_RAW when using Linux, macOS, BSD or AIX # platforms, when using ARM processors, or when using virtualization. # # `clock_id` specifies a kind of clock. See the document of # `Process.clock_gettime` for details. `clock_id` can be a symbol as for # `Process.clock_gettime`. # # If the given `clock_id` is not supported, Errno::EINVAL is raised. # # `unit` specifies the type of the return value. `Process.clock_getres` accepts # `unit` as `Process.clock_gettime`. The default value, `:float_second`, is also # the same as `Process.clock_gettime`. # # `Process.clock_getres` also accepts `:hertz` as `unit`. `:hertz` means the # reciprocal of `:float_second`. # # `:hertz` can be used to obtain the exact value of the clock ticks per second # for the times() function and CLOCKS_PER_SEC for the clock() function. # # `Process.clock_getres(:TIMES_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)` returns # the clock ticks per second. # # `Process.clock_getres(:CLOCK_BASED_CLOCK_PROCESS_CPUTIME_ID, :hertz)` returns # CLOCKS_PER_SEC. # # p Process.clock_getres(Process::CLOCK_MONOTONIC) # #=> 1.0e-09 # def self.clock_getres: (Symbol | Integer clock_id, ?Symbol unit) -> (Float | Integer) # # Returns a time returned by POSIX clock_gettime() function. # # p Process.clock_gettime(Process::CLOCK_MONOTONIC) # #=> 896053.968060096 # # `clock_id` specifies a kind of clock. It is specified as a constant which # begins with `Process::CLOCK_` such as Process::CLOCK_REALTIME and # Process::CLOCK_MONOTONIC. # # The supported constants depends on OS and version. Ruby provides following # types of `clock_id` if available. # # 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 # CLOCK_MONOTONIC # : SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS # 10.12, Windows-2000 # CLOCK_PROCESS_CPUTIME_ID # : SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12 # CLOCK_THREAD_CPUTIME_ID # : SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12 # CLOCK_VIRTUAL # : FreeBSD 3.0, OpenBSD 2.1 # CLOCK_PROF # : FreeBSD 3.0, OpenBSD 2.1 # CLOCK_REALTIME_FAST # : FreeBSD 8.1 # CLOCK_REALTIME_PRECISE # : FreeBSD 8.1 # CLOCK_REALTIME_COARSE # : Linux 2.6.32 # CLOCK_REALTIME_ALARM # : Linux 3.0 # CLOCK_MONOTONIC_FAST # : FreeBSD 8.1 # CLOCK_MONOTONIC_PRECISE # : FreeBSD 8.1 # CLOCK_MONOTONIC_COARSE # : Linux 2.6.32 # CLOCK_MONOTONIC_RAW # : Linux 2.6.28, macOS 10.12 # CLOCK_MONOTONIC_RAW_APPROX # : macOS 10.12 # CLOCK_BOOTTIME # : Linux 2.6.39 # CLOCK_BOOTTIME_ALARM # : Linux 3.0 # CLOCK_UPTIME # : FreeBSD 7.0, OpenBSD 5.5 # CLOCK_UPTIME_FAST # : FreeBSD 8.1 # CLOCK_UPTIME_RAW # : macOS 10.12 # CLOCK_UPTIME_RAW_APPROX # : macOS 10.12 # CLOCK_UPTIME_PRECISE # : FreeBSD 8.1 # CLOCK_SECOND # : FreeBSD 8.1 # CLOCK_TAI # : Linux 3.10 # # # Note that SUS stands for Single Unix Specification. SUS contains POSIX and # clock_gettime is defined in the POSIX part. SUS defines CLOCK_REALTIME # mandatory but CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID and # CLOCK_THREAD_CPUTIME_ID are optional. # # Also, several symbols are accepted as `clock_id`. There are emulations for # clock_gettime(). # # For example, Process::CLOCK_REALTIME is defined as # `:GETTIMEOFDAY_BASED_CLOCK_REALTIME` when clock_gettime() is not available. # # Emulations for `CLOCK_REALTIME`: # :GETTIMEOFDAY_BASED_CLOCK_REALTIME # : Use gettimeofday() defined by SUS. (SUSv4 obsoleted it, though.) 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. POSIX defines it as # "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_gettime(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 is 1/CLOCKS_PER_SEC. # CLOCKS_PER_SEC is the C-level macro defined by time.h. SUS defines # CLOCKS_PER_SEC is 1000000. Non-Unix systems may define it a different # value, though. If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1 # microsecond. If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integer # type, it cannot represent over 72 minutes. # # # If the given `clock_id` is not supported, Errno::EINVAL is raised. # # `unit` specifies a type of the return value. # # :float_second # : number of seconds as a float (default) # :float_millisecond # : number of milliseconds as a float # :float_microsecond # : number of microseconds as a float # :second # : number of seconds as an integer # :millisecond # : number of milliseconds as an integer # :microsecond # : number of microseconds as an integer # :nanosecond # : number of nanoseconds as an integer # # # 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 (zero) of the returned value varies. 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). But some systems count leap seconds and others doesn't. So the result # can be interpreted differently across systems. Time.now is recommended over # CLOCK_REALTIME. # def self.clock_gettime: (Symbol | Integer clock_id) -> Float | (Symbol | Integer clock_id, :float_second | :float_millisecond | :float_microsecond unit) -> Float | (Symbol | Integer clock_id, :second | :millisecond | :microsecond | :nanosecond unit) -> Integer # # Detach the process from controlling terminal and run in the background as # system daemon. Unless the argument nochdir is true (i.e. non false), it # changes the current working directory to the root ("/"). Unless the argument # noclose is true, daemon() will redirect standard input, standard output and # standard error to /dev/null. Return zero on success, or raise one of Errno::*. # def self.daemon: (?untyped nochdir, ?untyped noclose) -> Integer # # Some operating systems retain the status of terminated child processes until # the parent collects that status (normally using some variant of `wait()`). If # the parent never collects this status, the child stays around as 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. # Use #detach only when you do not intend to explicitly wait for the child to # terminate. # # The waiting thread returns the exit status of the detached process when it # terminates, so you can use Thread#join to know the result. If specified *pid* # is not a valid child process ID, the thread returns `nil` immediately. # # The waiting thread has #pid method which returns the pid. # # In this first example, we don't reap the first child process, so it appears as # a zombie in the process status display. # # p1 = fork { sleep 0.1 } # p2 = fork { sleep 0.2 } # Process.waitpid(p2) # sleep 2 # system("ps -ho pid,state -p #{p1}") # # *produces:* # # 27389 Z # # In the next example, Process::detach is used to reap the child automatically. # # p1 = fork { sleep 0.1 } # p2 = fork { sleep 0.2 } # Process.detach(p1) # Process.waitpid(p2) # sleep 2 # system("ps -ho pid,state -p #{p1}") # # *(produces no output)* # def self.detach: (Integer pid) -> Thread # # Returns the effective group ID for this process. Not available on all # platforms. # # Process.egid #=> 500 # def self.egid: () -> Integer # # Sets the effective group ID for this process. Not available on all platforms. # def self.egid=: (Integer arg0) -> Integer # # Returns the effective user ID for this process. # # Process.euid #=> 501 # def self.euid: () -> Integer # # Sets the effective user ID for this process. Not available on all platforms. # def self.euid=: (Integer arg0) -> Integer # # Returns the process group ID for the given process id. Not available on all # platforms. # # Process.getpgid(Process.ppid()) #=> 25527 # def self.getpgid: (Integer pid) -> Integer # # Returns the process group ID for this process. Not available on all platforms. # # Process.getpgid(0) #=> 25527 # Process.getpgrp #=> 25527 # def self.getpgrp: () -> Integer # # Gets the scheduling priority for specified process, process group, or user. # *kind* indicates the kind of entity to find: one of Process::PRIO_PGRP, # Process::PRIO_USER, or Process::PRIO_PROCESS. *integer* is an id indicating # the particular process, process group, or user (an id of 0 means *current*). # Lower priorities are more favorable for scheduling. Not available on all # platforms. # # Process.getpriority(Process::PRIO_USER, 0) #=> 19 # Process.getpriority(Process::PRIO_PROCESS, 0) #=> 19 # def self.getpriority: (Integer kind, Integer arg0) -> Integer # # Gets the resource limit of the process. *cur_limit* means current (soft) limit # and *max_limit* means maximum (hard) limit. # # *resource* indicates the kind of resource to limit. It is specified as a # symbol such as `:CORE`, a string such as `"CORE"` or a constant such as # Process::RLIMIT_CORE. See Process.setrlimit for details. # # *cur_limit* and *max_limit* may be Process::RLIM_INFINITY, # Process::RLIM_SAVED_MAX or Process::RLIM_SAVED_CUR. See Process.setrlimit and # the system getrlimit(2) manual for details. # def self.getrlimit: (Symbol | String | Integer resource) -> [ Integer, Integer ] # # Returns the session ID for the given process id. If not given, return current # process sid. Not available on all platforms. # # Process.getsid() #=> 27422 # Process.getsid(0) #=> 27422 # Process.getsid(Process.pid()) #=> 27422 # def self.getsid: (?Integer pid) -> Integer # # Returns the (real) group ID for this process. # # Process.gid #=> 500 # def self.gid: () -> Integer # # Sets the group ID for this process. # def self.gid=: (Integer arg0) -> Integer # # Get an Array of the group IDs in the supplemental group access list for this # process. # # Process.groups #=> [27, 6, 10, 11] # # Note that this method is just a wrapper of getgroups(2). This means that the # following characteristics of the result completely depend on your system: # # * the result is sorted # * the result includes effective GIDs # * the result does not include duplicated GIDs # * the result size does not exceed the value of Process.maxgroups # # # You can make sure to get a sorted unique GID list of the current process by # this expression: # # Process.groups.uniq.sort # def self.groups: () -> ::Array[Integer] # # Set the supplemental group access list to the given Array of group IDs. # # Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27] # Process.groups = [27, 6, 10, 11] #=> [27, 6, 10, 11] # Process.groups #=> [27, 6, 10, 11] # def self.groups=: (::Array[Integer] arg0) -> ::Array[Integer] # # Initializes the supplemental group access list by reading the system group # database and using all groups of which the given user is a member. The group # with the specified *gid* is also added to the list. Returns the resulting # Array of the GIDs of all the groups in the supplementary group access list. # Not available on all platforms. # # Process.groups #=> [0, 1, 2, 3, 4, 6, 10, 11, 20, 26, 27] # Process.initgroups( "mgranger", 30 ) #=> [30, 6, 10, 11] # Process.groups #=> [30, 6, 10, 11] # def self.initgroups: (String username, Integer gid) -> ::Array[Integer] # # Sends the given signal to the specified process id(s) if *pid* is positive. If # *pid* is zero, *signal* is sent to all processes whose group ID is equal to # the group ID of the process. If *pid* is negative, results are dependent on # the operating system. *signal* may be an integer signal number or a POSIX # signal name (either with or without a `SIG` prefix). If *signal* is negative # (or starts with a minus sign), kills process groups instead of processes. Not # all signals are available on all platforms. The keys and values of Signal.list # are known signal names and numbers, respectively. # # pid = fork do # Signal.trap("HUP") { puts "Ouch!"; exit } # # ... do some work ... # end # # ... # Process.kill("HUP", pid) # Process.wait # # *produces:* # # Ouch! # # If *signal* is an integer but wrong for signal, Errno::EINVAL or RangeError # will be raised. Otherwise unless *signal* is a String or a Symbol, and a # known signal name, ArgumentError will be raised. # # Also, Errno::ESRCH or RangeError for invalid *pid*, Errno::EPERM when failed # because of no privilege, will be raised. In these cases, signals may have # been sent to preceding processes. # def self.kill: (Integer | Symbol | String signal, *Integer pids) -> Integer # # Returns the maximum number of GIDs allowed in the supplemental group access # list. # # Process.maxgroups #=> 32 # def self.maxgroups: () -> Integer # # Sets the maximum number of GIDs allowed in the supplemental group access list. # def self.maxgroups=: (Integer arg0) -> Integer # # Returns the process id of this process. Not available on all platforms. # # Process.pid #=> 27415 # def self.pid: () -> Integer # # Returns the process id of the parent of this process. Returns untrustworthy # value on Win32/64. Not available on all platforms. # # puts "I am #{Process.pid}" # Process.fork { puts "Dad is #{Process.ppid}" } # # *produces:* # # I am 27417 # Dad is 27417 # def self.ppid: () -> Integer # # Sets the process group ID of *pid* (0 indicates this process) to *integer*. # Not available on all platforms. # def self.setpgid: (Integer pid, Integer arg0) -> Integer # # See Process.getpriority. # # 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 # def self.setpriority: (Integer kind, Integer arg0, Integer priority) -> Integer # # 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. # def self.setproctitle: (String arg0) -> String # # Sets the resource limit of the process. *cur_limit* means current (soft) limit # and *max_limit* means maximum (hard) limit. # # If *max_limit* is not given, *cur_limit* is used. # # *resource* indicates the kind of resource to limit. It should be a symbol such # as `:CORE`, a string such as `"CORE"` or a constant such as # Process::RLIMIT_CORE. The available resources are OS dependent. Ruby may # support following resources. # # AS # : total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but # 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) # # # *cur_limit* and *max_limit* may be `:INFINITY`, `"INFINITY"` or # Process::RLIM_INFINITY, which means that the resource is not limited. They may # be Process::RLIM_SAVED_MAX, Process::RLIM_SAVED_CUR and corresponding symbols # and strings too. See system setrlimit(2) manual for details. # # The following 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]) # def self.setrlimit: (Symbol | String | Integer resource, Integer cur_limit, ?Integer max_limit) -> nil # # Establishes this process as a new session and process group leader, with no # controlling tty. Returns the session id. Not available on all platforms. # # Process.setsid #=> 27422 # def self.setsid: () -> Integer # # Returns a `Tms` structure (see Process::Tms) that contains user and system CPU # times for this process, and also for children processes. # # t = Process.times # [ t.utime, t.stime, t.cutime, t.cstime ] #=> [0.0, 0.02, 0.00, 0.00] # def self.times: () -> Process::Tms # # Returns the (real) user ID of this process. # # Process.uid #=> 501 # def self.uid: () -> Integer # # Sets the (user) user ID for this process. Not available on all platforms. # def self.uid=: (Integer user) -> Integer # # Waits for a child process to exit, returns its process id, and sets `$?` to a # Process::Status object containing information on that process. Which child it # waits on depends on the value of *pid*: # # > 0 # : Waits for the child whose process ID equals *pid*. # # 0 # : Waits for any child whose process group ID equals that of the calling # process. # # -1 # : Waits for any child process (the default if no *pid* is given). # # < -1 # : Waits for any child whose process group ID equals the absolute value of # *pid*. # # # The *flags* argument may be a logical or of the flag values Process::WNOHANG # (do not block if no child available) or Process::WUNTRACED (return stopped # children that haven't been reported). Not all flags are available on all # platforms, but a flag value of zero will work on all platforms. # # Calling this method raises a SystemCallError if there are no child processes. # Not available on all platforms. # # include Process # fork { exit 99 } #=> 27429 # wait #=> 27429 # $?.exitstatus #=> 99 # # pid = fork { sleep 3 } #=> 27440 # Time.now #=> 2008-03-08 19:56:16 +0900 # waitpid(pid, Process::WNOHANG) #=> nil # Time.now #=> 2008-03-08 19:56:16 +0900 # waitpid(pid, 0) #=> 27440 # Time.now #=> 2008-03-08 19:56:19 +0900 # def self.wait: (?Integer pid, ?Integer flags) -> Integer # # Waits for a child process to exit (see Process::waitpid for exact semantics) # and returns an array containing the process id and the exit status (a # Process::Status object) of that child. Raises a SystemCallError if there are # no child processes. # # Process.fork { exit 99 } #=> 27437 # pid, status = Process.wait2 # pid #=> 27437 # status.exitstatus #=> 99 # def self.wait2: (?Integer pid, ?Integer flags) -> [ Integer, Process::Status ] # # Waits for all children, returning an array of *pid*/*status* pairs (where # *status* is a Process::Status object). # # fork { sleep 0.2; exit 2 } #=> 27432 # fork { sleep 0.1; exit 1 } #=> 27433 # fork { exit 0 } #=> 27434 # p Process.waitall # # *produces*: # # [[30982, #], # [30979, #], # [30976, #]] # def self.waitall: () -> ::Array[[ Integer, Process::Status ]] # # Waits for a child process to exit, returns its process id, and sets `$?` to a # Process::Status object containing information on that process. Which child it # waits on depends on the value of *pid*: # # > 0 # : Waits for the child whose process ID equals *pid*. # # 0 # : Waits for any child whose process group ID equals that of the calling # process. # # -1 # : Waits for any child process (the default if no *pid* is given). # # < -1 # : Waits for any child whose process group ID equals the absolute value of # *pid*. # # # The *flags* argument may be a logical or of the flag values Process::WNOHANG # (do not block if no child available) or Process::WUNTRACED (return stopped # children that haven't been reported). Not all flags are available on all # platforms, but a flag value of zero will work on all platforms. # # Calling this method raises a SystemCallError if there are no child processes. # Not available on all platforms. # # include Process # fork { exit 99 } #=> 27429 # wait #=> 27429 # $?.exitstatus #=> 99 # # pid = fork { sleep 3 } #=> 27440 # Time.now #=> 2008-03-08 19:56:16 +0900 # waitpid(pid, Process::WNOHANG) #=> nil # Time.now #=> 2008-03-08 19:56:16 +0900 # waitpid(pid, 0) #=> 27440 # Time.now #=> 2008-03-08 19:56:19 +0900 # def self.waitpid: (?Integer pid, ?Integer flags) -> Integer # # Waits for a child process to exit (see Process::waitpid for exact semantics) # and returns an array containing the process id and the exit status (a # Process::Status object) of that child. Raises a SystemCallError if there are # no child processes. # # Process.fork { exit 99 } #=> 27437 # pid, status = Process.wait2 # pid #=> 27437 # status.exitstatus #=> 99 # def self.waitpid2: (?Integer pid, ?Integer flags) -> [ Integer, Process::Status ] end # # see Process.clock_gettime # Process::CLOCK_BOOTTIME: Integer # # see Process.clock_gettime # Process::CLOCK_BOOTTIME_ALARM: Integer # # see Process.clock_gettime # Process::CLOCK_MONOTONIC: Integer # # see Process.clock_gettime # Process::CLOCK_MONOTONIC_COARSE: Integer # # see Process.clock_gettime # Process::CLOCK_MONOTONIC_RAW: Integer # # see Process.clock_gettime # Process::CLOCK_PROCESS_CPUTIME_ID: Integer # # see Process.clock_gettime # Process::CLOCK_REALTIME: Integer # # see Process.clock_gettime # Process::CLOCK_REALTIME_ALARM: Integer # # see Process.clock_gettime # Process::CLOCK_REALTIME_COARSE: Integer # # see Process.clock_gettime # Process::CLOCK_THREAD_CPUTIME_ID: Integer # # see Process.setpriority # Process::PRIO_PGRP: Integer # # see Process.setpriority # Process::PRIO_PROCESS: Integer # # see Process.setpriority # Process::PRIO_USER: Integer # # Maximum size of the process's virtual memory (address space) in bytes. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_AS: Integer # # Maximum size of the core file. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_CORE: Integer # # CPU time limit in seconds. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_CPU: Integer # # Maximum size of the process's data segment. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_DATA: Integer # # Maximum size of files that the process may create. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_FSIZE: Integer # # Maximum number of bytes of memory that may be locked into RAM. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_MEMLOCK: Integer # # 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. # Process::RLIMIT_MSGQUEUE: Integer # # Specifies a ceiling to which the process's nice value can be raised. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_NICE: Integer # # 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. # Process::RLIMIT_NOFILE: Integer # # 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. # Process::RLIMIT_NPROC: Integer # # 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. # Process::RLIMIT_NPTS: Integer # # Specifies the limit (in pages) of the process's resident set. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_RSS: Integer # # Specifies a ceiling on the real-time priority that may be set for this # process. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_RTPRIO: Integer # # Specifies limit on CPU time this process scheduled under a real-time # scheduling policy can consume. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_RTTIME: Integer # # 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. # Process::RLIMIT_SIGPENDING: Integer # # Maximum size of the stack, in bytes. # # see the system getrlimit(2) manual for details. # Process::RLIMIT_STACK: Integer # # see Process.setrlimit # Process::RLIM_INFINITY: Integer # # see Process.setrlimit # Process::RLIM_SAVED_CUR: Integer # # see Process.setrlimit # Process::RLIM_SAVED_MAX: Integer # # see Process.wait # Process::WNOHANG: Integer # # see Process.wait # Process::WUNTRACED: Integer # # The Process::GID module contains a collection of module functions which can be # used to portably get, set, and switch the current process's real, effective, # and saved group IDs. # module Process::GID # # Change the current process's real and effective group ID to that specified by # *group*. Returns the new group ID. Not available on all platforms. # # [Process.gid, Process.egid] #=> [0, 0] # Process::GID.change_privilege(33) #=> 33 # [Process.gid, Process.egid] #=> [33, 33] # def self.change_privilege: (Integer group) -> Integer # # Returns the effective group ID for this process. Not available on all # platforms. # # Process.egid #=> 500 # def self.eid: () -> Integer # # Get the group ID by the *name*. If the group is not found, `ArgumentError` # will be raised. # # Process::GID.from_name("wheel") #=> 0 # Process::GID.from_name("nosuchgroup") #=> can't find group for nosuchgroup (ArgumentError) # def self.from_name: (String name) -> Integer # # Set the effective group ID, and if possible, the saved group ID of the process # to the given *group*. Returns the new effective group ID. Not available on all # platforms. # # [Process.gid, Process.egid] #=> [0, 0] # Process::GID.grant_privilege(31) #=> 33 # [Process.gid, Process.egid] #=> [0, 33] # def self.grant_privilege: (Integer group) -> Integer # # Exchange real and effective group IDs and return the new effective group ID. # Not available on all platforms. # # [Process.gid, Process.egid] #=> [0, 33] # Process::GID.re_exchange #=> 0 # [Process.gid, Process.egid] #=> [33, 0] # def self.re_exchange: () -> Integer # # Returns `true` if the real and effective group IDs of a process may be # exchanged on the current platform. # def self.re_exchangeable?: () -> bool # # Returns the (real) group ID for this process. # # Process.gid #=> 500 # def self.rid: () -> Integer # # Returns `true` if the current platform has saved group ID functionality. # def self.sid_available?: () -> bool # # Switch the effective and real group IDs of the current process. If a *block* # is given, the group IDs will be switched back after the block is executed. # Returns the new effective group ID if called without a block, and the return # value of the block if one is given. # def self.switch: () -> Integer | [T] () { () -> T } -> T def self.eid=: (Integer group) -> Integer end # # Process::Status encapsulates the information on the status of a running or # terminated system process. The built-in variable `$?` is either `nil` or a # Process::Status object. # # fork { exit 99 } #=> 26557 # Process.wait #=> 26557 # $?.class #=> Process::Status # $?.to_i #=> 25344 # $? >> 8 #=> 99 # $?.stopped? #=> false # $?.exited? #=> true # $?.exitstatus #=> 99 # # Posix systems record information on processes using a 16-bit integer. The # lower bits record the process status (stopped, exited, signaled) and the upper # bits possibly contain additional information (for example the program's return # code in the case of exited processes). Pre Ruby 1.8, these bits were exposed # directly to the Ruby program. Ruby now encapsulates these in a Process::Status # object. To maximize compatibility, however, these objects retain a # bit-oriented interface. In the descriptions that follow, when we talk about # the integer value of *stat*, we're referring to this 16 bit value. # class Process::Status < Object # # Logical AND of the bits in *stat* with *num*. # # fork { exit 0x37 } # Process.wait # sprintf('%04x', $?.to_i) #=> "3700" # sprintf('%04x', $? & 0x1e00) #=> "1600" # def &: (Integer num) -> Integer # # Returns `true` if the integer value of *stat* equals *other*. # def ==: (untyped other) -> bool # # Shift the bits in *stat* right *num* places. # # fork { exit 99 } #=> 26563 # Process.wait #=> 26563 # $?.to_i #=> 25344 # $? >> 8 #=> 99 # def >>: (Integer num) -> Integer # # Returns `true` if *stat* generated a coredump when it terminated. Not # available on all platforms. # def coredump?: () -> bool # # Returns `true` if *stat* exited normally (for example using an `exit()` call # or finishing the program). # def exited?: () -> bool # # Returns the least significant eight bits of the return code of *stat*. Only # available if #exited? is `true`. # # fork { } #=> 26572 # Process.wait #=> 26572 # $?.exited? #=> true # $?.exitstatus #=> 0 # # fork { exit 99 } #=> 26573 # Process.wait #=> 26573 # $?.exited? #=> true # $?.exitstatus #=> 99 # def exitstatus: () -> Integer? # # Override the inspection method. # # system("false") # p $?.inspect #=> "#" # def inspect: () -> String # # Returns the process ID that this status object represents. # # fork { exit } #=> 26569 # Process.wait #=> 26569 # $?.pid #=> 26569 # def pid: () -> Integer # # Returns `true` if *stat* terminated because of an uncaught signal. # def signaled?: () -> bool # # Returns `true` if this process is stopped. This is only returned if the # corresponding #wait call had the Process::WUNTRACED flag set. # def stopped?: () -> bool # # Returns the number of the signal that caused *stat* to stop (or `nil` if self # is not stopped). # def stopsig: () -> Integer? # # Returns `true` if *stat* is successful, `false` if not. Returns `nil` if # #exited? is not `true`. # def success?: () -> bool # # Returns the number of the signal that caused *stat* to terminate (or `nil` if # self was not terminated by an uncaught signal). # def termsig: () -> Integer? # # Returns the bits in *stat* as an Integer. Poking around in these bits is # platform dependent. # # fork { exit 0xab } #=> 26566 # Process.wait #=> 26566 # sprintf('%04x', $?.to_i) #=> "ab00" # def to_i: () -> Integer # # Show pid and exit status as a string. # # system("false") # p $?.to_s #=> "pid 12766 exit 1" # def to_s: () -> String end # # The Process::Sys module contains UID and GID functions which provide direct # bindings to the system calls of the same names instead of the more-portable # versions of the same functionality found in the Process, Process::UID, and # Process::GID modules. # module Process::Sys # # Returns the effective user ID for this process. # # Process.euid #=> 501 # def self.geteuid: () -> Integer # # Returns the (real) group ID for this process. # # Process.gid #=> 500 # def self.getgid: () -> Integer # # Returns the (real) user ID of this process. # # Process.uid #=> 501 # def self.getuid: () -> Integer # # Returns `true` if the process was created as a result of an execve(2) system # call which had either of the setuid or setgid bits set (and extra privileges # were given as a result) or if it has changed any of its real, effective or # saved user or group IDs since it began execution. # def self.issetugid: () -> bool # # Set the effective group ID of the calling process to *group*. Not available # on all platforms. # def self.setegid: (Integer group) -> nil # # Set the effective user ID of the calling process to *user*. Not available on # all platforms. # def self.seteuid: (Integer user) -> nil # # Set the group ID of the current process to *group*. Not available on all # platforms. # def self.setgid: (Integer group) -> nil # # Sets the (group) real and/or effective group IDs of the current process to # *rid* and *eid*, respectively. A value of `-1` for either means to leave that # ID unchanged. Not available on all platforms. # def self.setregid: (Integer rid, Integer eid) -> nil # # Sets the (group) real, effective, and saved user IDs of the current process to # *rid*, *eid*, and *sid* respectively. A value of `-1` for any value means to # leave that ID unchanged. Not available on all platforms. # def self.setresgid: (Integer rid, Integer eid, Integer sid) -> nil # # Sets the (user) real, effective, and saved user IDs of the current process to # *rid*, *eid*, and *sid* respectively. A value of `-1` for any value means to # leave that ID unchanged. Not available on all platforms. # def self.setresuid: (Integer rid, Integer eid, Integer sid) -> nil # # Sets the (user) real and/or effective user IDs of the current process to *rid* # and *eid*, respectively. A value of `-1` for either means to leave that ID # unchanged. Not available on all platforms. # def self.setreuid: (Integer rid, Integer eid) -> nil # # Set the real group ID of the calling process to *group*. Not available on all # platforms. # def self.setrgid: (Integer group) -> nil # # Set the real user ID of the calling process to *user*. Not available on all # platforms. # def self.setruid: (Integer user) -> nil # # Set the user ID of the current process to *user*. Not available on all # platforms. # def self.setuid: (Integer user) -> nil end # # The Process::UID module contains a collection of module functions which can be # used to portably get, set, and switch the current process's real, effective, # and saved user IDs. # module Process::UID # # Change the current process's real and effective user ID to that specified by # *user*. Returns the new user ID. Not available on all platforms. # # [Process.uid, Process.euid] #=> [0, 0] # Process::UID.change_privilege(31) #=> 31 # [Process.uid, Process.euid] #=> [31, 31] # def self.change_privilege: (Integer user) -> Integer # # Returns the effective user ID for this process. # # Process.euid #=> 501 # def self.eid: () -> Integer # # Get the user ID by the *name*. If the user is not found, `ArgumentError` will # be raised. # # Process::UID.from_name("root") #=> 0 # Process::UID.from_name("nosuchuser") #=> can't find user for nosuchuser (ArgumentError) # def self.from_name: (String name) -> Integer # # Set the effective user ID, and if possible, the saved user ID of the process # to the given *user*. Returns the new effective user ID. Not available on all # platforms. # # [Process.uid, Process.euid] #=> [0, 0] # Process::UID.grant_privilege(31) #=> 31 # [Process.uid, Process.euid] #=> [0, 31] # def self.grant_privilege: (Integer user) -> Integer # # Exchange real and effective user IDs and return the new effective user ID. Not # available on all platforms. # # [Process.uid, Process.euid] #=> [0, 31] # Process::UID.re_exchange #=> 0 # [Process.uid, Process.euid] #=> [31, 0] # def self.re_exchange: () -> Integer # # Returns `true` if the real and effective user IDs of a process may be # exchanged on the current platform. # def self.re_exchangeable?: () -> bool # # Returns the (real) user ID of this process. # # Process.uid #=> 501 # def self.rid: () -> Integer # # Returns `true` if the current platform has saved user ID functionality. # def self.sid_available?: () -> bool # # Switch the effective and real user IDs of the current process. If a *block* is # given, the user IDs will be switched back after the block is executed. Returns # the new effective user ID if called without a block, and the return value of # the block if one is given. # def self.switch: () -> Integer | [T] () { () -> T } -> T def self.eid=: (Integer user) -> Integer end class Process::Tms < Struct[Float] end class Process::Waiter < Thread def pid: () -> Integer end