module Process

ModuleProcess 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; seeArgument command_line or exe_path.

In addition:

Execution Environment

Optional leading argumentenv is a hash of name/value pairs, where each name is a string and each value is a string ornil; each name/value pair is added toENV 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 argumentenv, where each named environment variable is created or updated (if the value is non-nil), or deleted (if the value isnil).

However, some modifications to the calling process may remain if the new process fails. For example, hard resource limits are not restored.

Argumentcommand_line orexe_path

The required string argument is one of the following:

Argumentcommand_line

String argumentcommand_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('exit')# => true  # Built-in.system('date > /tmp/date.tmp')# => true  # Contains meta character.system('date > /nop/date.tmp')# => falsesystem('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

SeeExecution Shell for details about the shell.

Argumentexe_path

Argumentexe_path is one of the following:

Argumentsargs

Ifcommand_line does not contain shell meta characters except for spaces and tabs, orexe_path is given, Ruby invokes the executable directly. This form does not use the shell:

spawn("doesnt_exist")# Raises Errno::ENOENTspawn("doesnt_exist","\n")# Raises Errno::ENOENTspawn("doesnt_exist\n")# => false# sh: 1: doesnot_exist: not found

The error message is from a shell and would vary depending on your system.

If one or moreargs is given afterexe_path, each is an argument or option to be passed to the executable:

Example:

system('echo','<','C*','|','$SHELL','>')# => true

Output:

< C* | $SHELL >

However, there are exceptions on Windows. SeeExecution Shell on Windows.

If you want to invoke a path containing spaces with no arguments without shell, you will need to use a 2-element arrayexe_path.

Example:

path ='/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'spawn(path)# Raises Errno::ENOENT; No such file or directory - /Applications/Googlespawn([path]*2)

Execution Options

Optional trailing argumentoptions 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:

There are these shorthand symbols for fds:

The value given with a source is one of:

SeeAccess Modes andFile Permissions.

Environment Variables (:unsetenv_others)

By default, the new process inherits environment variables from the parent process; use execution option key:unsetenv_others with valuetrue to clear environment variables in the new process.

Any changes specified by execution optionenv are made after the new process inherits or clears its environment variables; seeExecution Environment.

File-Creation Access (:umask)

Use execution option:umask to set the file-creation access for the new process; seeAccess Modes:

command ='ruby -e "puts sprintf(\"0%o\", File.umask)"'options = {:umask=>0644}Process.spawn(command,options)

Output:

0644

Process Groups (:pgroup and:new_pgroup)

By default, the new process belongs to the sameprocess group as the parent process.

To specify a different process group. use execution option:pgroup with one of the following values:

On Windows only, use execution option:new_pgroup with valuetrue 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, whereresource_name is the downcased form of one of the string resource names described at methodProcess.setrlimit. For example, key:rlimit_cpu corresponds to resource limit'CPU'.

The value for such as key is one of:

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; the entire stringcommand_line is passed as an argument toshell option -c.

The shell performs normal shell expansion on the command line:

Example:

system('echo $SHELL: C*')# => true

Output:

/bin/bash: CONTRIBUTING.md COPYING COPYING.ja

Execution Shell on Windows

On Windows, the shell invoked is determined by environment variableRUBYSHELL, if defined, orCOMSPEC otherwise; the entire stringcommand_line is passed as an argument to-c option forRUBYSHELL, as well as/bin/sh, and/c option forCOMSPEC. The shell is invoked automatically in the following cases:

Note that the command will still be invoked ascommand_line form even when called inexe_path form, becausecmd.exe does not accept a script name like/bin/sh does but only works with/c option.

The standard shellcmd.exe performs environment variable expansion but does not have globbing functionality:

Example:

system("echo %COMSPEC%: C*")' # => true

Output:

C:\WINDOWS\system32\cmd.exe: C*

What’s Here

Current-Process Getters

Current-Process Setters

Current-Process Execution

Child Processes

Process Groups

Timing

Constants

CLOCK_BOOTTIME

seeProcess.clock_gettime

CLOCK_BOOTTIME_ALARM

seeProcess.clock_gettime

CLOCK_MONOTONIC

seeProcess.clock_gettime

CLOCK_MONOTONIC_COARSE

seeProcess.clock_gettime

CLOCK_MONOTONIC_FAST

seeProcess.clock_gettime

CLOCK_MONOTONIC_PRECISE

seeProcess.clock_gettime

CLOCK_MONOTONIC_RAW

seeProcess.clock_gettime

CLOCK_MONOTONIC_RAW_APPROX

seeProcess.clock_gettime

CLOCK_PROCESS_CPUTIME_ID

seeProcess.clock_gettime

CLOCK_PROF

seeProcess.clock_gettime

CLOCK_REALTIME

seeProcess.clock_gettime

CLOCK_REALTIME_ALARM

seeProcess.clock_gettime

CLOCK_REALTIME_COARSE

seeProcess.clock_gettime

CLOCK_REALTIME_FAST

seeProcess.clock_gettime

CLOCK_REALTIME_PRECISE

seeProcess.clock_gettime

CLOCK_SECOND

seeProcess.clock_gettime

CLOCK_TAI

seeProcess.clock_gettime

CLOCK_THREAD_CPUTIME_ID

seeProcess.clock_gettime

CLOCK_UPTIME

seeProcess.clock_gettime

CLOCK_UPTIME_FAST

seeProcess.clock_gettime

CLOCK_UPTIME_PRECISE

seeProcess.clock_gettime

CLOCK_UPTIME_RAW

seeProcess.clock_gettime

CLOCK_UPTIME_RAW_APPROX

seeProcess.clock_gettime

CLOCK_VIRTUAL

seeProcess.clock_gettime

PRIO_PGRP

seeProcess.setpriority

PRIO_PROCESS

seeProcess.setpriority

PRIO_USER

seeProcess.setpriority

RLIMIT_AS

Maximum size of the process’s virtual memory (address space) in bytes.

see the system getrlimit(2) manual for details.

RLIMIT_CORE

Maximum size of the core file.

see the system getrlimit(2) manual for details.

RLIMIT_CPU

CPU time limit in seconds.

see the system getrlimit(2) manual for details.

RLIMIT_DATA

Maximum size of the process’s data segment.

see the system getrlimit(2) manual for details.

RLIMIT_FSIZE

Maximum size of files that the process may create.

see the system getrlimit(2) manual for details.

RLIMIT_MEMLOCK

Maximum number of bytes of memory that may be locked into RAM.

see the system getrlimit(2) manual for details.

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.

RLIMIT_NICE

Specifies a ceiling to which the process’s nice value can be raised.

see the system getrlimit(2) manual for details.

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.

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.

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.

RLIMIT_RSS

Specifies the limit (in pages) of the process’s resident set.

see the system getrlimit(2) manual for details.

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.

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.

RLIMIT_SBSIZE

Maximum size of the socket buffer.

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.

RLIMIT_STACK

Maximum size of the stack, in bytes.

see the system getrlimit(2) manual for details.

RLIM_INFINITY

seeProcess.setrlimit

RLIM_SAVED_CUR

seeProcess.setrlimit

RLIM_SAVED_MAX

seeProcess.setrlimit

WNOHANG

seeProcess.wait

WUNTRACED

seeProcess.wait

Public Class Methods

Source
VALUErb_proc__fork(VALUE _obj){    rb_pid_t pid = proc_fork_pid();    return PIDT2NUM(pid);}

An internal API for fork. Do not call this method directly. Currently, this is called viaKernel#fork,Process.fork, andIO.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. Seethis issue for a more detailed discussion of this.

Source
static VALUEf_abort(int c, const VALUE *a, VALUE _){    rb_f_abort(c, a);    UNREACHABLE_RETURN(Qnil);}

Terminates execution immediately, effectively by callingKernel.exit(false).

If string argumentmsg is given, it is written to STDERR prior to termination; otherwise, if an exception was raised, prints its message and backtrace.

Source
static VALUEproc_argv0(VALUE process){    return rb_orig_progname;}

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.

Source
static VALUErb_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);    }}

Returns a clock resolution as determined by POSIX functionclock_getres():

Process.clock_getres(:CLOCK_REALTIME)# => 1.0e-09

SeeProcess.clock_gettime for the values ofclock_id andunit.

Examples:

Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID,:float_microsecond)# => 0.001Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID,:float_millisecond)# => 1.0e-06Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID,:float_second)# => 1.0e-09Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID,:microsecond)# => 0Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID,:millisecond)# => 0Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID,:nanosecond)# => 1Process.clock_getres(:CLOCK_PROCESS_CPUTIME_ID,:second)# => 0

In addition to the values forunit supported inProcess.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.0Process.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.

Source
static VALUErb_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);}

Returns a clock time as determined by POSIX functionclock_gettime():

Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID)# => 198.650379677

Argumentclock_id should be a symbol or a constant that specifies the clock whose time is to be returned; see below.

Optional argumentunit should be a symbol that specifies the unit to be used in the returned clock time; see below.

Argumentclock_id

Argumentclock_id specifies the clock whose time is to be returned; it may be a constant such asProcess::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 andclock_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 givenclock_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.

Argumentunit

Optional argumentunit (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.825Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID,:float_millisecond)# => 203643.696848Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID,:float_second)# => 203.762181929Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID,:microsecond)# => 204123212Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID,:millisecond)# => 204298Process.clock_gettime(:CLOCK_PROCESS_CPUTIME_ID,:nanosecond)# => 204602286036Process.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 theunit.

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.

Source
static VALUEproc_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);}

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 argumentnochdir istrue, does not change the current working directory.

If optional argumentnoclose istrue, does not redirect $stdin, $stdout, or $stderr.

Source
static VALUEproc_detach(VALUE obj, VALUE pid){    return rb_detach_process(NUM2PIDT(pid));}

Avoids the potential for a child process to become azombie process.Process.detach prevents this by setting up a separate Ruby thread whose sole job is to reap the status of the processpid 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')# => 312691sleep(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')# => 313213thread =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
Source
static VALUEproc_getegid(VALUE obj){    rb_gid_t egid = getegid();    return GIDT2NUM(egid);}

Returns the effective group ID for the current process:

Process.egid# => 500

Not available on all platforms.

Source
static VALUEproc_setegid(VALUE obj, VALUE egid){#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)    rb_gid_t gid;#endif    check_gid_switch();#if defined(HAVE_SETRESGID) || defined(HAVE_SETREGID) || defined(HAVE_SETEGID) || defined(HAVE_SETGID)    gid = OBJ2GID(egid);#endif#if defined(HAVE_SETRESGID)    if (setresgid(-1, gid, -1) < 0) rb_sys_fail(0);#elif defined HAVE_SETREGID    if (setregid(-1, gid) < 0) rb_sys_fail(0);#elif defined HAVE_SETEGID    if (setegid(gid) < 0) rb_sys_fail(0);#elif defined HAVE_SETGID    if (gid == getgid()) {        if (setgid(gid) < 0) rb_sys_fail(0);    }    else {        rb_notimplement();    }#else    rb_notimplement();#endif    return egid;}

Sets the effective group ID for the current process.

Not available on all platforms.

Source
static VALUEproc_geteuid(VALUE obj){    rb_uid_t euid = geteuid();    return UIDT2NUM(euid);}

Returns the effective user ID for the current process.

Process.euid# => 501
Source
static VALUEproc_seteuid_m(VALUE mod, VALUE euid){    check_uid_switch();    proc_seteuid(OBJ2UID(euid));    return euid;}

Sets the effective user ID for the current process.

Not available on all platforms.

Source
static VALUEf_exec(int c, const VALUE *a, VALUE _){    rb_f_exec(c, a);    UNREACHABLE_RETURN(Qnil);}

Replaces the current process by doing one of the following:

  • Passing stringcommand_line to the shell.

  • Invoking the executable atexe_path.

This method has potential security vulnerabilities if called with untrusted input; seeCommand Injection.

The new process is created using theexec system call; it may inherit some of its environment from the calling program (possibly including open file descriptors).

Argumentenv, if given, is a hash that affectsENV for the new process; seeExecution Environment.

Argumentoptions is a hash of options for the new process; seeExecution 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.

Argumentcommand_line

String argumentcommand_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('exit')# 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

SeeExecution Shell for details about the shell.

Raises an exception if the new process could not execute.

Argumentexe_path

Argumentexe_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. This form does not use the shell; seeArguments args for caveats.

exec('doesnt_exist')# Raises Errno::ENOENT

If one or moreargs 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.

Source
static VALUEf_exit(int c, const VALUE *a, VALUE _){    rb_f_exit(c, a);    UNREACHABLE_RETURN(Qnil);}

Initiates termination of the Ruby script by raisingSystemExit; the exception may be caught. Returns exit statusstatus to the underlying operating system.

Valuestrue andfalse for argumentstatus indicate, respectively, success and failure; The meanings of integer values are system-dependent.

Example:

beginexitputs'Never get here.'rescueSystemExitputs'Rescued a SystemExit exception.'endputs'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 (seeObjectSpace::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.
Source
static VALUErb_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);}

Exits the process immediately; no exit handlers are called. Returns exit statusstatus to the underlying operating system.

Process.exit!(true)

Valuestrue andfalse for argumentstatus indicate, respectively, success and failure; The meanings of integer values are system-dependent.

Source
static VALUErb_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);}

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}"forkdoputs"In the child process: #{Process.pid}"end# => 382141puts"After the fork: #{Process.pid}"

Output:

Beforethefork:420496Afterthefork:420496Inthechildprocess:420520

With no block given, thefork call returns twice:

  • Once in the parent process, returning the pid of the child process.

  • Once in the child process, returningnil.

Example:

puts"This is the first line before the fork (pid #{Process.pid})"putsforkputs"This is the second line after the fork (pid #{Process.pid})"

Output:

Thisisthefirstlinebeforethefork (pid420199)420223Thisisthesecondlineafterthefork (pid420199)Thisisthesecondlineafterthefork (pid420223)

In either case, the child process may exit usingKernel.exit! to avoid the call toKernel#at_exit.

To avoid zombie processes, the parent process should call either:

The thread callingfork is the only thread in the created child process;fork doesn’t copy other threads.

Note that methodfork 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 offork.

Source
static VALUEproc_getpgid(VALUE obj, VALUE pid){    rb_pid_t i;    i = getpgid(NUM2PIDT(pid));    if (i < 0) rb_sys_fail(0);    return PIDT2NUM(i);}
Returns the process group ID for the given process ID +pid+:  Process.getpgid(Process.ppid) # => 25527

Not available on all platforms.

Source
static VALUEproc_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}

Returns the process group ID for the current process:

Process.getpgid(0)# => 25527Process.getpgrp# => 25527
Source
static VALUEproc_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);}

Returns the scheduling priority for specified process, process group, or user.

Argumentkind is one of:

Argumentid is the ID for the process, process group, or user; zero specified the current ID forkind.

Examples:

Process.getpriority(Process::PRIO_USER,0)# => 19Process.getpriority(Process::PRIO_PROCESS,0)# => 19

Not available on all platforms.

Source
static VALUEproc_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));}

Returns a 2-element array of the current (soft) limit and maximum (hard) limit for the givenresource.

Argumentresource specifies the resource whose limits are to be returned; seeProcess.setrlimit.

Each of the returned valuescur_limit andmax_limit is an integer; seeProcess.setrlimit.

Example:

Process.getrlimit(:CORE)# => [0, 18446744073709551615]

SeeProcess.setrlimit.

Not available on all platforms.

Source
static VALUEproc_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);}

Returns the session ID of the given process IDpid, or of the current process if not given:

Process.getsid# => 27422Process.getsid(0)# => 27422Process.getsid(Process.pid())# => 27422

Not available on all platforms.

Source
static VALUEproc_getgid(VALUE obj){    rb_gid_t gid = getgid();    return GIDT2NUM(gid);}

Returns the (real) group ID for the current process:

Process.gid# => 1000
Source
static VALUEproc_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);}

Sets the group ID for the current process tonew_gid:

Process.gid =1000# => 1000
Source
static VALUEproc_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;}

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 ofProcess.maxgroups.

Use this call to get a sorted and unique array:

Process.groups.uniq.sort
Source
static VALUEproc_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);}

Sets 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]
Source
static VALUEproc_initgroups(VALUE obj, VALUE uname, VALUE base_grp){    if (initgroups(StringValueCStr(uname), OBJ2GID(base_grp)) != 0) {        rb_sys_fail(0);    }    return proc_getgroups(obj);}

Sets the supplemental group access list; the new list includes:

  • The group IDs of those groups to which the user given byusername belongs.

  • The group IDgid.

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.

Source
static VALUEproc_rb_f_kill(int c, const VALUE *v, VALUE _){    return rb_f_kill(c, v);}

Sends a signal to each process specified byids (which must specify at least one ID); returns the count of signals sent.

For each givenid, ifid is:

  • Positive, sends the signal to the process whose process ID isid.

  • Zero, send the signal to all processes in the current process group.

  • Negative, sends the signal to a system-dependent collection of processes.

Argumentsignal 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'.

Ifsignal 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 methodSignal.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, signal0 is useful to determine if the process exists.

Example:

pid =forkdoSignal.trap('HUP') {puts'Ouch!';exit }# ... do some work ...end# ...Process.kill('HUP',pid)Process.wait

Output:

Ouch!

Exceptions:

  • Raises Errno::EINVAL orRangeError ifsignal is an integer but invalid.

  • RaisesArgumentError ifsignal is a string or symbol but invalid.

  • Raises Errno::ESRCH orRangeError if one ofids 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.

Source
static VALUEproc_s_last_status(VALUE mod){    return rb_last_status_get();}

Returns aProcess::Status object representing the most recently exited child process in the current thread, ornil if none:

Process.spawn('ruby','-e','exit 13')Process.waitProcess.last_status# => #<Process::Status: pid 14396 exit 13>Process.spawn('ruby','-e','exit 14')Process.waitProcess.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.waitProcess.last_status# => #<Process::Status: pid 1380 exit 15>
Source
static VALUEproc_getmaxgroups(VALUE obj){    return INT2FIX(maxgroups());}

Returns the maximum number of group IDs allowed in the supplemental group access list:

Process.maxgroups# => 32
Source
static VALUEproc_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);}

Sets the maximum number of group IDs allowed in the supplemental group access list.

Source
static VALUEproc_get_pid(VALUE _){    return get_pid();}

Returns the process ID of the current process:

Process.pid# => 15668
Source
static VALUEproc_get_ppid(VALUE _){    return get_ppid();}

Returns the process ID of the parent of the current process:

puts"Pid is #{Process.pid}."fork {puts"Parent pid is #{Process.ppid}." }

Output:

Pid is 271290.Parent pid is 271290.

May not return a trustworthy value on certain platforms.

Source
static VALUEproc_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);}

Sets the process group ID for the process given by process IDpid topgid.

Not available on all platforms.

Source
static VALUEproc_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);}

Equivalent tosetpgid(0, 0).

Not available on all platforms.

Source
static VALUEproc_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);}

SeeProcess.getpriority.

Examples:

Process.setpriority(Process::PRIO_USER,0,19)# => 0Process.setpriority(Process::PRIO_PROCESS,0,19)# => 0Process.getpriority(Process::PRIO_USER,0)# => 19Process.getpriority(Process::PRIO_PROCESS,0)# => 19

Not available on all platforms.

Source
static VALUEproc_setproctitle(VALUE process, VALUE title){    return ruby_setproctitle(title);}

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 willNotImplementedError 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.

Source
static VALUEproc_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;}

Sets limits for the current process for the givenresource tocur_limit (soft limit) andmax_limit (hard limit); returnsnil.

Argumentresource 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 withProcess::RLIMIT_ (e.g.,:CORE,'CORE', orProcess::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).

Argumentscur_limit andmax_limit may be:

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.

Source
static VALUEproc_setsid(VALUE _){    rb_pid_t pid;    pid = setsid();    if (pid < 0) rb_sys_fail(0);    return PIDT2NUM(pid);}

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.

Source
static VALUErb_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}

Creates a new child process by doing one of the following in that process:

  • Passing stringcommand_line to the shell.

  • Invoking the executable atexe_path.

This method has potential security vulnerabilities if called with untrusted input; seeCommand 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:

The new process is created using theexec system call; it may inherit some of its environment from the calling program (possibly including open file descriptors).

Argumentenv, if given, is a hash that affectsENV for the new process; seeExecution Environment.

Argumentoptions is a hash of options for the new process; seeExecution 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.

Argumentcommand_line

String argumentcommand_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# => 798847spawn('exit')# => 798848 # Built-in.Process.wait# => 798848spawn('date > /tmp/date.tmp')# => 798879 # Contains meta character.Process.wait# => 798849spawn('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"')# => 799031Process.wait# => 799031

Output:

Foo

SeeExecution Shell for details about the shell.

Raises an exception if the new process could not execute.

Argumentexe_path

Argumentexe_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.

    spawn('/usr/bin/date')# Path to date on Unix-style system.Process.wait

    Output:

    Mon Aug 28 11:43:10 AM CDT 2023

Ruby invokes the executable directly. This form does not use the shell; seeArguments args for caveats.

If one or moreargs is given, each is an argument or option to be passed to the executable:

spawn('echo','C*')# => 799392Process.wait# => 799392spawn('echo','hello','world')# => 799393Process.wait# => 799393

Output:

C*hello world

Raises an exception if the new process could not execute.

Source
VALUErb_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;}

Returns aProcess::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.

Source
static VALUEproc_getuid(VALUE obj){    rb_uid_t uid = getuid();    return UIDT2NUM(uid);}

Returns the (real) user ID of the current process.

Process.uid# => 1000
Source
static VALUEproc_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;}

Sets the (user) user ID for the current process tonew_uid:

Process.uid =1000# => 1000

Not available on all platforms.

Source
static VALUEproc_m_wait(int c, VALUE *v, VALUE _){    return proc_wait(c, v);}

Waits for a suitable child process to exit, returns its process ID, and sets$? to aProcess::Status object containing information on that process. Which child it waits for depends on the value of the givenpid:

  • Positive integer: Waits for the child process whose process ID ispid:

    pid0 =Process.spawn('ruby','-e','exit 13')# => 230866pid1 =Process.spawn('ruby','-e','exit 14')# => 230891Process.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 =forkdoputs"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)."endchild1_pid =forkdoputs"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)."endretrieved_pid =Process.wait(0)puts"Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid."beginProcess.wait(0)rescueErrno::ECHILD=>xputs"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 225788Child 0 process group ID is 225764 (same as parent's).Child 1 pid is 225789Child 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 =forkdoputs"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)."endchild1_pid =forkdoputs"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)."sleep3# To force child 1 to exit later than child 0 exit.endchild_pids = [child0_pid,child1_pid]retrieved_pid =Process.wait(-1)putschild_pids.include?(retrieved_pid)retrieved_pid =Process.wait(-1)putschild_pids.include?(retrieved_pid)

    Output:

    Parent process group ID is 228736.Child 0 pid is 228758Child 0 process group ID is 228736 (same as parent's).Child 1 pid is 228759Child 1 process group ID is 228759 (different from parent's).truetrue
  • 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 =forkdoputs"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)."endchild1_pid =forkdoputs"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)."endsleep1retrieved_pid =Process.wait(-child1_pid)puts"Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid."beginProcess.wait(-child1_pid)rescueErrno::ECHILD=>xputs"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 230108Child 0 process group ID is 230083 (same as parent's).Child 1 pid is 230109Child 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.

Argumentflags should be given as one of the following constants, or as the logical OR of both:

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 forProcess.wait.

Source
static VALUEproc_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());}

LikeProcess.waitpid, but returns an array containing the child processpid andProcess::Statusstatus:

pid =Process.spawn('ruby','-e','exit 13')# => 309581Process.wait2(pid)# => [309581, #<Process::Status: pid 309581 exit 13>]

Process.waitpid2 is an alias forProcess.wait2.

Source
static VALUEproc_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;}

Waits for all children, returns an array of 2-element arrays; each subarray contains the integer pid andProcess::Status status for one of the reaped child processes:

pid0 =Process.spawn('ruby','-e','exit 13')# => 325470pid1 =Process.spawn('ruby','-e','exit 14')# => 325495Process.waitall# => [[325470, #<Process::Status: pid 325470 exit 13>], [325495, #<Process::Status: pid 325495 exit 14>]]
Source
static VALUEproc_m_wait(int c, VALUE *v, VALUE _){    return proc_wait(c, v);}

Waits for a suitable child process to exit, returns its process ID, and sets$? to aProcess::Status object containing information on that process. Which child it waits for depends on the value of the givenpid:

  • Positive integer: Waits for the child process whose process ID ispid:

    pid0 =Process.spawn('ruby','-e','exit 13')# => 230866pid1 =Process.spawn('ruby','-e','exit 14')# => 230891Process.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 =forkdoputs"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)."endchild1_pid =forkdoputs"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)."endretrieved_pid =Process.wait(0)puts"Process.wait(0) returned pid #{retrieved_pid}, which is child 0 pid."beginProcess.wait(0)rescueErrno::ECHILD=>xputs"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 225788Child 0 process group ID is 225764 (same as parent's).Child 1 pid is 225789Child 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 =forkdoputs"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)."endchild1_pid =forkdoputs"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)."sleep3# To force child 1 to exit later than child 0 exit.endchild_pids = [child0_pid,child1_pid]retrieved_pid =Process.wait(-1)putschild_pids.include?(retrieved_pid)retrieved_pid =Process.wait(-1)putschild_pids.include?(retrieved_pid)

    Output:

    Parent process group ID is 228736.Child 0 pid is 228758Child 0 process group ID is 228736 (same as parent's).Child 1 pid is 228759Child 1 process group ID is 228759 (different from parent's).truetrue
  • 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 =forkdoputs"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)."endchild1_pid =forkdoputs"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)."endsleep1retrieved_pid =Process.wait(-child1_pid)puts"Process.wait(-child1_pid) returned pid #{retrieved_pid}, which is child 1 pid."beginProcess.wait(-child1_pid)rescueErrno::ECHILD=>xputs"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 230108Child 0 process group ID is 230083 (same as parent's).Child 1 pid is 230109Child 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.

Argumentflags should be given as one of the following constants, or as the logical OR of both:

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 forProcess.wait.

Source
static VALUEproc_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());}

LikeProcess.waitpid, but returns an array containing the child processpid andProcess::Statusstatus:

pid =Process.spawn('ruby','-e','exit 13')# => 309581Process.wait2(pid)# => [309581, #<Process::Status: pid 309581 exit 13>]

Process.waitpid2 is an alias forProcess.wait2.

Source
static VALUEproc_warmup(VALUE _){    RB_VM_LOCKING() {        rb_gc_prepare_heap();    }    return Qtrue;}

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 majorGC.

  • 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.

  • Invokemalloc_trim if available to free empty malloc pages.