The module contains several groups of functionality for handling OSprocesses:
Low-level property introspection and management of the current process,like::argv0,::pid;
Low-level introspection of other processes, like::getpgid,::getpriority;
Management of the current process:::abort,::exit,::daemon, etc. (for convenience,most of those are also available as global functions and module functionsofKernel);
Creation and management of child processes:::fork,::spawn, and related methods;
Management of low-level system clock:::times and::clock_gettime, which couldbe important for proper benchmarking and other elapsed time measurementtasks.
Maximum size of the process's virtual memory (address space) in bytes.
see the system getrlimit(2) manual for details.
Maximum size of the core file.
see the system getrlimit(2) manual for details.
CPU time limit in seconds.
see the system getrlimit(2) manual for details.
Maximum size of the process's data segment.
see the system getrlimit(2) manual for details.
Maximum size of files that the process may create.
see the system getrlimit(2) manual for details.
Maximum number of bytes of memory that may be locked into RAM.
see the system getrlimit(2) manual for details.
Specifies the limit on the number of bytes that can be allocated for POSIXmessage queues for the real user ID of the calling process.
see the system getrlimit(2) manual for details.
Specifies a ceiling to which the process's nice value can be raised.
see the system getrlimit(2) manual for details.
Specifies a value one greater than the maximum file descriptor number thatcan be opened by this process.
see the system getrlimit(2) manual for details.
The maximum number of processes that can be created for the real user ID ofthe calling process.
see the system getrlimit(2) manual for details.
Specifies the limit (in pages) of the process's resident set.
see the system getrlimit(2) manual for details.
Specifies a ceiling on the real-time priority that may be set for thisprocess.
see the system getrlimit(2) manual for details.
Specifies limit on CPU time this process scheduled under a real-timescheduling policy can consume.
see the system getrlimit(2) manual for details.
Maximum size of the socket buffer.
Specifies a limit on the number of signals that may be queued for the realuser ID of the calling process.
see the system getrlimit(2) manual for details.
Maximum size of the stack, in bytes.
see the system getrlimit(2) manual for details.
see::setrlimit
see::setrlimit
see::setrlimit
see::wait
see::wait
Returns the name of the script being executed. The value is not affectedby assigning a new value to $0.
This method first appeared in Ruby 2.1 to serve as a global variable freemeans to get the script name.
static VALUEproc_argv0(VALUE process){ return rb_orig_progname;}
Returns an estimate of the resolution of aclock_id
using thePOSIXclock_getres()
function.
Note the reported resolution is often inaccurate on most platforms due tounderlying bugs for this function and therefore the reported resolutionoften differs from the actual resolution of the clock in practice.Inaccurate reported resolutions have been observed for various clocksincludingCLOCK_MONOTONIC andCLOCK_MONOTONIC_RAW when usingLinux, macOS, BSD or AIX platforms, when using ARM processors, or whenusing virtualization.
clock_id
specifies a kind of clock. See the document ofProcess.clock_gettime
for details.clock_id
canbe a symbol as forProcess.clock_gettime
.
If the givenclock_id
is not supported, Errno::EINVAL israised.
unit
specifies the type of the return value.Process.clock_getres
acceptsunit
asProcess.clock_gettime
. The default value,:float_second
, is also the same asProcess.clock_gettime
.
Process.clock_getres
also accepts:hertz
asunit
.:hertz
means the reciprocal of:float_second
.
:hertz
can be used to obtain the exact value of the clockticks per second for the times() function and CLOCKS_PER_SEC for theclock() 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.
pProcess.clock_getres(Process::CLOCK_MONOTONIC)#=> 1.0e-09
static VALUErb_clock_getres(int argc, VALUE *argv, VALUE _){ 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]; if (SYMBOL_P(clk_id)) {#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 defined(HAVE_CLOCK_GETRES) struct timespec ts; clockid_t c = NUM2CLOCKID(clk_id); int ret = clock_getres(c, &ts); if (ret == -1) rb_sys_fail("clock_getres"); tt.count = (int32_t)ts.tv_nsec; tt.giga_count = ts.tv_sec; denominators[num_denominators++] = 1000000000; goto success;#endif } /* EINVAL emulates clock_getres behavior when clock_id is invalid. */ rb_syserr_fail(EINVAL, 0); 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 time returned by POSIX::clock_gettime() function.
pProcess.clock_gettime(Process::CLOCK_MONOTONIC)#=> 896053.968060096
clock_id
specifies a kind of clock. It is specified as aconstant which begins withProcess::CLOCK_
such asProcess::CLOCK_REALTIME andProcess::CLOCK_MONOTONIC.
The supported constants depends on OS and version. Ruby provides followingtypes ofclock_id
if available.
SUSv2 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 2.1, macOS 10.12
SUSv3 to 4, Linux 2.5.63, FreeBSD 3.0, NetBSD 2.0, OpenBSD 3.4, macOS 10.12
SUSv3 to 4, Linux 2.5.63, FreeBSD 9.3, OpenBSD 5.4, macOS 10.12
SUSv3 to 4, Linux 2.5.63, FreeBSD 7.1, OpenBSD 5.4, macOS 10.12
FreeBSD 3.0, OpenBSD 2.1
FreeBSD 3.0, OpenBSD 2.1
FreeBSD 8.1
FreeBSD 8.1
Linux 2.6.32
Linux 3.0
FreeBSD 8.1
FreeBSD 8.1
Linux 2.6.32
Linux 2.6.28, macOS 10.12
macOS 10.12
Linux 2.6.39
Linux 3.0
FreeBSD 7.0, OpenBSD 5.5
FreeBSD 8.1
macOS 10.12
macOS 10.12
FreeBSD 8.1
FreeBSD 8.1
Linux 3.10
Note that SUS stands for Single Unix Specification. SUS contains POSIX and::clock_gettime isdefined in the POSIX part. SUS definesCLOCK_REALTIME mandatory butCLOCK_MONOTONIC,CLOCK_PROCESS_CPUTIME_IDandCLOCK_THREAD_CPUTIME_ID areoptional.
Also, several symbols are accepted asclock_id
. There areemulations for::clock_gettime().
For example,Process::CLOCK_REALTIME is definedas:GETTIMEOFDAY_BASED_CLOCK_REALTIME
when::clock_gettime() is notavailable.
Emulations forCLOCK_REALTIME
:
Use gettimeofday() defined by SUS. (SUSv4 obsoleted it, though.) Theresolution is 1 microsecond.
Use time() defined by ISO C. The resolution is 1 second.
Emulations forCLOCK_MONOTONIC
:
Use mach_absolute_time(), available on Darwin. The resolution is CPUdependent.
Use the result value of times() defined by POSIX. POSIX defines it as“times() shall return the elapsed real time, in clock ticks, since anarbitrary point in the past (for example, system start-up time)”. Forexample, 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 isdefined by HZ macro in older systems.) If it is 100 and clock_t is 32 bitsinteger type, the resolution is 10 millisecond and cannot represent over497 days.
Emulations forCLOCK_PROCESS_CPUTIME_ID
:
Use getrusage() defined by SUS. getrusage() is used with RUSAGE_SELF toobtain the time only for the calling process (excluding the time for childprocesses). The result is addition of user time (ru_utime) and system time(ru_stime). The resolution is 1 microsecond.
Use times() defined by POSIX. The result is addition of user time(tms_utime) and system time (tms_stime). tms_cutime and tms_cstime areignored to exclude the time for child processes. The resolution is theclock 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 itis 100, the resolution is 10 millisecond.
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 definesCLOCKS_PER_SEC is 1000000. Non-Unix systems may define it a differentvalue, though. If CLOCKS_PER_SEC is 1000000 as SUS, the resolution is 1microsecond. If CLOCKS_PER_SEC is 1000000 and clock_t is 32 bits integertype, it cannot represent over 72 minutes.
If the givenclock_id
is not supported, Errno::EINVAL israised.
unit
specifies a type of the return value.
number of seconds as a float (default)
number of milliseconds as a float
number of microseconds as a float
number of seconds as an integer
number of milliseconds as an integer
number of microseconds as an integer
number of nanoseconds as an integer
The underlying function,::clock_gettime(), returns anumber of nanoseconds.Float object (IEEE 754double) is not enough to represent the return value forCLOCK_REALTIME. If the exactnanoseconds value is required, use:nanoseconds
as theunit
.
The origin (zero) of the returned value varies. For example, system startup time, process start up time, the Epoch, etc.
The origin inCLOCK_REALTIME isdefined as the Epoch (1970-01-01 00:00:00 UTC). But some systems count leapseconds and others doesn't. So the result can be interpreteddifferently across systems.Time.nowis recommended overCLOCK_REALTIME.
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]; if (SYMBOL_P(clk_id)) { /* * 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__#define RUBY_MACH_ABSOLUTE_TIME_BASED_CLOCK_MONOTONIC ID2SYM(id_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(); 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 defined(HAVE_CLOCK_GETTIME) struct timespec ts; clockid_t c; c = NUM2CLOCKID(clk_id); ret = clock_gettime(c, &ts); if (ret == -1) rb_sys_fail("clock_gettime"); tt.count = (int32_t)ts.tv_nsec; tt.giga_count = ts.tv_sec; denominators[num_denominators++] = 1000000000; goto success;#endif } /* EINVAL emulates clock_gettime behavior when clock_id is invalid. */ rb_syserr_fail(EINVAL, 0); success: return make_clock_result(&tt, numerators, num_numerators, denominators, num_denominators, unit);}
Detach the process from controlling terminal and run in the background assystem daemon. Unless the argument nochdir is true (i.e. non false), itchanges the current working directory to the root (“/”). Unless theargument noclose is true, daemon() will redirect standard input, standardoutput and standard error to /dev/null. Return zero on success, or raiseone of Errno::*.
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);}
Some operating systems retain the status of terminated child processesuntil the parent collects that status (normally using some variant ofwait()
). If the parent never collects this status, the childstays around as azombie process.::detach prevents this by settingup a separate Ruby thread whose sole job is to reap the status of theprocesspid when it terminates. Use detach only when you do notintend to explicitly wait for the child to terminate.
The waiting thread returns the exit status of the detached process when itterminates, so you can useThread#join to know the result. Ifspecifiedpid is not a valid child process ID, the thread returnsnil
immediately.
The waiting thread has pid method which returns the pid.
In this first example, we don't reap the first child process, so itappears as a zombie in the process status display.
p1 =fork {sleep0.1 }p2 =fork {sleep0.2 }Process.waitpid(p2)sleep2system("ps -ho pid,state -p #{p1}")
produces:
27389 Z
In the next example,::detach isused to reap the child automatically.
p1 =fork {sleep0.1 }p2 =fork {sleep0.2 }Process.detach(p1)Process.waitpid(p2)sleep2system("ps -ho pid,state -p #{p1}")
(produces no output)
static VALUEproc_detach(VALUE obj, VALUE pid){ return rb_detach_process(NUM2PIDT(pid));}
Returns the effective group ID for this process. Not available on allplatforms.
Process.egid#=> 500
static VALUEproc_getegid(VALUE obj){ rb_gid_t egid = getegid(); return GIDT2NUM(egid);}
Sets the effective group ID for this process. Not available on allplatforms.
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;}
Returns the effective user ID for this process.
Process.euid#=> 501
static VALUEproc_geteuid(VALUE obj){ rb_uid_t euid = geteuid(); return UIDT2NUM(euid);}
Sets the effective user ID for this process. Not available on allplatforms.
static VALUEproc_seteuid_m(VALUE mod, VALUE euid){ check_uid_switch(); proc_seteuid(OBJ2UID(euid)); return euid;}
Creates a subprocess. If a block is specified, that block is run in thesubprocess, and the subprocess terminates with a status of zero. Otherwise,thefork
call returns twice, once in the parent, returning theprocess ID of the child, and once in the child, returningnil. Thechild process can exit usingKernel#exit! to avoid running anyat_exit
functions. The parent process should use::wait to collect the terminationstatuses of its children or use::detach to register disinterest intheir status; otherwise, the operating system may accumulate zombieprocesses.
The thread calling fork is the only thread in the created child process.fork doesn't copy other threads.
If fork is not usable, Process.respond_to?(:fork) returns false.
Note that fork(2) is not available on some platforms like Windows andNetBSD 4. Therefore you should use spawn() instead of fork().
static VALUErb_f_fork(VALUE obj){ rb_pid_t pid; switch (pid = rb_fork_ruby(NULL)) { case 0: rb_thread_atfork(); if (rb_block_given_p()) { int status; rb_protect(rb_yield, Qundef, &status); ruby_stop(status); } return Qnil; case -1: rb_sys_fail("fork(2)"); return Qnil; default: return PIDT2NUM(pid); }}
Returns the process group ID for the given process id. Not available on allplatforms.
Process.getpgid(Process.ppid())#=> 25527
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 this process. Not available on allplatforms.
Process.getpgid(0)#=> 25527Process.getpgrp#=> 25527
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}
Gets the scheduling priority for specified process, process group, or user.kind indicates the kind of entity to find: one ofProcess::PRIO_PGRP,Process::PRIO_USER, orProcess::PRIO_PROCESS.integer is an id indicating the particular process, process group,or user (an id of 0 meanscurrent). Lower priorities are morefavorable for scheduling. Not available on all platforms.
Process.getpriority(Process::PRIO_USER,0)#=> 19Process.getpriority(Process::PRIO_PROCESS,0)#=> 19
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);}
Gets the resource limit of the process.cur_limit means current(soft) limit andmax_limit means maximum (hard) limit.
resource indicates the kind of resource to limit. It is specifiedas a symbol such as:CORE
, a string such as"CORE"
or a constant such asProcess::RLIMIT_CORE. See::setrlimit for details.
cur_limit andmax_limit may beProcess::RLIM_INFINITY,Process::RLIM_SAVED_MAX orProcess::RLIM_SAVED_CUR. See::setrlimit and the systemgetrlimit(2) manual for details.
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 the session ID for the given process id. If not given, returncurrent process sid. Not available on all platforms.
Process.getsid()#=> 27422Process.getsid(0)#=> 27422Process.getsid(Process.pid())#=> 27422
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 (real) group ID for this process.
Process.gid#=> 500
static VALUEproc_getgid(VALUE obj){ rb_gid_t gid = getgid(); return GIDT2NUM(gid);}
Sets the group ID for this process.
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);}
Get anArray of the group IDs in the supplementalgroup access list for this process.
Process.groups#=> [27, 6, 10, 11]
Note that this method is just a wrapper of getgroups(2). This means thatthe following characteristics of the result completely depend on yoursystem:
the result is sorted
the result includes effective GIDs
the result does not include duplicated GIDs
You can make sure to get a sorted uniqueGIDlist of the current process by this expression:
Process.groups.uniq.sort
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;}
Set the supplemental group access list to the givenArray 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]
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);}
Initializes the supplemental group access list by reading the system groupdatabase and using all groups of which the given user is a member. Thegroup with the specifiedgid is also added to the list. Returnsthe resultingArray of the gids of all the groupsin 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]
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);}
Sends the given signal to the specified process id(s) ifpid ispositive. Ifpid is zero,signal is sent to all processeswhose group ID is equal to the group ID of the process. Ifpid isnegative, results are dependent on the operating system.signalmay be an integer signal number or a POSIX signal name (either with orwithout aSIG
prefix). Ifsignal is negative (orstarts with a minus sign), kills process groups instead of processes. Notall signals are available on all platforms. The keys and values ofSignal.list are known signal names andnumbers, respectively.
pid =forkdoSignal.trap("HUP") {puts"Ouch!";exit }# ... do some work ...end# ...Process.kill("HUP",pid)Process.wait
produces:
Ouch!
Ifsignal is an integer but wrong for signal, Errno::EINVAL orRangeError will be raised. Otherwise unlesssignal is aString or aSymbol, and a known signal name,ArgumentError will be raised.
Also, Errno::ESRCH orRangeError for invalidpid, Errno::EPERM when failed because of no privilege, will beraised. In these cases, signals may have been sent to preceding processes.
static VALUEproc_rb_f_kill(int c, const VALUE *v, VALUE _){ return rb_f_kill(c, v);}
Returns the status of the last executed child process in the currentthread.
Process.waitProcess.spawn("ruby","-e","exit 13")Process.last_status#=> #<Process::Status: pid 4825 exit 13>
If no child process has ever been executed in the current thread, thisreturnsnil
.
Process.last_status#=> nil
static VALUEproc_s_last_status(VALUE mod){ return rb_last_status_get();}
Returns the maximum number of gids allowed in the supplemental group accesslist.
Process.maxgroups#=> 32
static VALUEproc_getmaxgroups(VALUE obj){ return INT2FIX(maxgroups());}
Sets the maximum number of gids allowed in the supplemental group accesslist.
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);}
Returns the process id of this process. Not available on all platforms.
Process.pid#=> 27415
static VALUEproc_get_pid(VALUE _){ return get_pid();}
Returns the process id of the parent of this process. Returns untrustworthyvalue on Win32/64. Not available on all platforms.
puts"I am #{Process.pid}"Process.fork {puts"Dad is #{Process.ppid}" }
produces:
Iam27417Dadis27417
static VALUEproc_get_ppid(VALUE _){ return get_ppid();}
Sets the process group ID ofpid (0 indicates this process) tointeger. Not available on all platforms.
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);}
Equivalent tosetpgid(0,0)
. Not available on all platforms.
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);}
See::getpriority.
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
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);}
Sets the process title that appears on the ps(1) command. Not necessarilyeffective on all platforms. No exception will be raised regardless of theresult, nor willNotImplementedErrorbe 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 freemeans to change the process title.
static VALUEproc_setproctitle(VALUE process, VALUE title){ return ruby_setproctitle(title);}
Sets the resource limit of the process.cur_limit means current(soft) limit andmax_limit means maximum (hard) limit.
Ifmax_limit is not given,cur_limit is used.
resource indicates the kind of resource to limit. It should be asymbol such as:CORE
, a string such as"CORE"
or a constant such asProcess::RLIMIT_CORE. The availableresources are OS dependent. Ruby may support following resources.
total available memory (bytes) (SUSv3, NetBSD, FreeBSD, OpenBSD but4.4BSD-Lite)
core size (bytes) (SUSv3)
CPU time (seconds) (SUSv3)
data segment (bytes) (SUSv3)
file size (bytes) (SUSv3)
total size for mlock(2) (bytes) (4.4BSD, GNU/Linux)
allocation for POSIX message queues (bytes) (GNU/Linux)
ceiling on process's nice(2) value (number) (GNU/Linux)
file descriptors (number) (SUSv3)
number of processes for the user (number) (4.4BSD, GNU/Linux)
resident memory size (bytes) (4.2BSD, GNU/Linux)
ceiling on the process's real-time priority (number) (GNU/Linux)
CPU time for real-time process (us) (GNU/Linux)
all socket buffers (bytes) (NetBSD, FreeBSD)
number of queued signals allowed (signals) (GNU/Linux)
stack size (bytes) (SUSv3)
cur_limit andmax_limit may be:INFINITY
,"INFINITY"
orProcess::RLIM_INFINITY, which meansthat the resource is not limited. They may beProcess::RLIM_SAVED_MAX,Process::RLIM_SAVED_CUR andcorresponding symbols and strings too. See system setrlimit(2) manual fordetails.
The following example raises the soft limit of core size to the hard limitto try to make core dump possible.
Process.setrlimit(:CORE,Process.getrlimit(:CORE)[1])
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;}
Establishes this process as a new session and process group leader, with nocontrolling tty. Returns the session id. Not available on all platforms.
Process.setsid#=> 27422
static VALUEproc_setsid(VALUE _){ rb_pid_t pid; pid = setsid(); if (pid < 0) rb_sys_fail(0); return PIDT2NUM(pid);}
spawn executes specified command and return its pid.
pid =spawn("tar xf ruby-2.0.0-p195.tar.bz2")Process.waitpidpid =spawn(RbConfig.ruby,"-eputs'Hello, world!'")Process.waitpid
This method is similar toKernel#system but it doesn'twait for the command to finish.
The parent process should use::wait to collect the terminationstatus of its child or use::detach to register disinterest intheir status; otherwise, the operating system may accumulate zombieprocesses.
spawn has bunch of options to specify process attributes:
env: hash name => val : set the environment variable name => nil : unset the environment variable the keys and the values except for +nil+ must be strings.command...: commandline : command line string which is passed to the standard shell cmdname, arg1, ... : command name and one or more arguments (This form does not use the shell. See below for caveats.) [cmdname, argv0], arg1, ... : command name, argv[0] and zero or more arguments (no shell)options: hash clearing environment variables: :unsetenv_others => true : clear environment variables except specified by env :unsetenv_others => false : don't clear (default) process group: :pgroup => true or 0 : make a new process group :pgroup => pgid : join the specified process group :pgroup => nil : don't change the process group (default) create new process group: Windows only :new_pgroup => true : the new process is the root process of a new process group :new_pgroup => false : don't create a new process group (default) resource limit: resourcename is core, cpu, data, etc. See Process.setrlimit. :rlimit_resourcename => limit :rlimit_resourcename => [cur_limit, max_limit] umask: :umask => int redirection: key: FD : single file descriptor in child process [FD, FD, ...] : multiple file descriptor in child process value: FD : redirect to the file descriptor in parent process string : redirect to file with open(string, "r" or "w") [string] : redirect to file with open(string, File::RDONLY) [string, open_mode] : redirect to file with open(string, open_mode, 0644) [string, open_mode, perm] : redirect to file with open(string, open_mode, perm) [:child, FD] : redirect to the redirected file descriptor :close : close the file descriptor in child process FD is one of follows :in : the file descriptor 0 which is the standard input :out : the file descriptor 1 which is the standard output :err : the file descriptor 2 which is the standard error integer : the file descriptor of specified the integer io : the file descriptor specified as io.fileno file descriptor inheritance: close non-redirected non-standard fds (3, 4, 5, ...) or not :close_others => false : inherit current directory: :chdir => str
Thecmdname, arg1, ...
form does not use the shell. However,on different OSes, different things are provided as built-in commands. Anexample of this is +'echo'+, which is a built-in on Windows, but isa normal program on Linux and Mac OS X. This means thatProcess.spawn'echo', '%Path%'
will display the contents of the%Path%
environment variable on Windows, butProcess.spawn 'echo', '$PATH'
prints theliteral$PATH
.
If a hash is given asenv
, the environment is updated byenv
beforeexec(2)
in the child process. If apair inenv
has nil as the value, the variable is deleted.
# set FOO as BAR and unset BAZ.pid =spawn({"FOO"=>"BAR","BAZ"=>nil},command)
If a hash is given asoptions
, it specifies process group,create new process group, resource limit, current directory, umask andredirects for the child process. Also, it can be specified to clearenvironment variables.
The:unsetenv_others
key inoptions
specifies toclear environment variables, other than specified byenv
.
pid =spawn(command, :unsetenv_others=>true)# no environment variablepid =spawn({"FOO"=>"BAR"},command, :unsetenv_others=>true)# FOO only
The:pgroup
key inoptions
specifies a processgroup. The corresponding value should be true, zero, a positive integer, ornil. true and zero cause the process to be a process leader of a newprocess group. A non-zero positive integer causes the process to join theprovided process group. The default value, nil, causes the process toremain in the same process group.
pid =spawn(command, :pgroup=>true)# process leaderpid =spawn(command, :pgroup=>10)# belongs to the process group 10
The:new_pgroup
key inoptions
specifies to passCREATE_NEW_PROCESS_GROUP
flag toCreateProcessW()
that is Windows API. This option is only for Windows. true means the newprocess is the root process of the new process group. The new process hasCTRL+C disabled. This flag is necessary forProcess.kill(:SIGINT,pid)
on the subprocess. :new_pgroup is false by default.
pid =spawn(command, :new_pgroup=>true)# new process grouppid =spawn(command, :new_pgroup=>false)# same process group
The:rlimit_
foo key specifies a resource limit.foo should be one of resource types such ascore
. Thecorresponding value should be an integer or an array which have one or twointegers: same as cur_limit and max_limit arguments for::setrlimit.
cur,max =Process.getrlimit(:CORE)pid =spawn(command, :rlimit_core=>[0,max])# disable core temporary.pid =spawn(command, :rlimit_core=>max)# enable core dumppid =spawn(command, :rlimit_core=>0)# never dump core.
The:umask
key inoptions
specifies the umask.
pid =spawn(command, :umask=>077)
The :in, :out, :err, an integer, anIO and an arraykey specifies a redirection. The redirection maps a file descriptor in thechild process.
For example, stderr can be merged into stdout as follows:
pid =spawn(command, :err=>:out)pid =spawn(command,2=>1)pid =spawn(command,STDERR=>:out)pid =spawn(command,STDERR=>STDOUT)
The hash keys specifies a file descriptor in the child process started byspawn. :err, 2 and STDERR specifies the standard error stream (stderr).
The hash values specifies a file descriptor in the parent process whichinvokes spawn. :out, 1 and STDOUT specifies the standard output stream(stdout).
In the above example, the standard output in the child process is notspecified. So it is inherited from the parent process.
The standard input stream (stdin) can be specified by :in, 0 and STDIN.
A filename can be specified as a hash value.
pid =spawn(command, :in=>"/dev/null")# read modepid =spawn(command, :out=>"/dev/null")# write modepid =spawn(command, :err=>"log")# write modepid =spawn(command, [:out, :err]=>"/dev/null")# write modepid =spawn(command,3=>"/dev/null")# read mode
For stdout and stderr (and combination of them), it is opened in writemode. Otherwise read mode is used.
For specifying flags and permission of file creation explicitly, an arrayis used instead.
pid =spawn(command, :in=>["file"])# read mode is assumedpid =spawn(command, :in=>["file","r"])pid =spawn(command, :out=>["log","w"])# 0644 assumedpid =spawn(command, :out=>["log","w",0600])pid =spawn(command, :out=>["log",File::WRONLY|File::EXCL|File::CREAT,0600])
The array specifies a filename, flags and permission. The flags can be astring or an integer. If the flags is omitted or nil, File::RDONLY isassumed. The permission should be an integer. If the permission is omittedor nil, 0644 is assumed.
If an array of IOs and integers are specified as a hash key, all theelements are redirected.
# stdout and stderr is redirected to log file.# The file "log" is opened just once.pid =spawn(command, [:out, :err]=>["log","w"])
Another way to merge multiple file descriptors is [:child, fd]. [:child,fd] means the file descriptor in the child process. This is different fromfd. For example, :err=>:out means redirecting child stderr to parentstdout. But :err=>[:child, :out] means redirecting child stderr to childstdout. They differ if stdout is redirected in the child process asfollows.
# stdout and stderr is redirected to log file.# The file "log" is opened just once.pid =spawn(command, :out=>["log","w"], :err=>[:child, :out])
[:child, :out] can be used to merge stderr into stdout inIO.popen. In this case,IO.popen redirects stdout to a pipe inthe child process and [:child, :out] refers the redirected stdout.
io =IO.popen(["sh","-c","echo out; echo err >&2", :err=>[:child, :out]])pio.read#=> "out\nerr\n"
The:chdir
key inoptions
specifies the currentdirectory.
pid =spawn(command, :chdir=>"/var/tmp")
spawn closes all non-standard unspecified descriptors by default. The“standard” descriptors are 0, 1 and 2. This behavior is specified by:close_others option. :close_others doesn't affect the standarddescriptors which are closed only if :close is specified explicitly.
pid =spawn(command, :close_others=>true)# close 3,4,5,... (default)pid =spawn(command, :close_others=>false)# don't close 3,4,5,...
:close_others is false by default for spawn andIO.popen.
Note that fds which close-on-exec flag is already set are closed regardlessof :close_others option.
SoIO.pipe and spawn can be used asIO.popen.
# similar to r = IO.popen(command)r,w =IO.pipepid =spawn(command, :out=>w)# r, w is closed in the child process.w.close
:close is specified as a hash value to close a fd individually.
f =open(foo)system(command,f=>:close)# don't inherit f.
If a file descriptor need to be inherited, io=>io can be used.
# valgrind has --log-fd option for log destination.# log_w=>log_w indicates log_w.fileno inherits to child process.log_r,log_w =IO.pipepid =spawn("valgrind","--log-fd=#{log_w.fileno}","echo","a",log_w=>log_w)log_w.closeplog_r.read
It is also possible to exchange file descriptors.
pid =spawn(command, :out=>:err, :err=>:out)
The hash keys specify file descriptors in the child process. The hashvalues specifies file descriptors in the parent process. So the abovespecifies exchanging stdout and stderr. Internally,spawn
usesan extra file descriptor to resolve such cyclic file descriptor mapping.
SeeKernel#exec for the standardshell.
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}
Returns aTms
structure (see Process::Tms) that contains userand 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]
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 the (real) user ID of this process.
Process.uid#=> 501
static VALUEproc_getuid(VALUE obj){ rb_uid_t uid = getuid(); return UIDT2NUM(uid);}
Sets the (user) user ID for this process. Not available on all platforms.
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;}
Waits for a child process to exit, returns its process id, and sets$?
to aProcess::Statusobject containing information on that process. Which child it waits ondepends on the value ofpid:
Waits for the child whose process ID equalspid.
Waits for any child whose process group ID equals that of the callingprocess.
Waits for any child process (the default if nopid is given).
Waits for any child whose process group ID equals the absolute value ofpid.
Theflags argument may be a logical or of the flag valuesProcess::WNOHANG (do not block if no childavailable) orProcess::WUNTRACED(return stopped children that haven't been reported). Not all flags areavailable on all platforms, but a flag value of zero will work on allplatforms.
Calling this method raises aSystemCallError if there are no childprocesses. Not available on all platforms.
includeProcessfork {exit99 }#=> 27429wait#=> 27429$?.exitstatus#=> 99pid =fork {sleep3 }#=> 27440Time.now#=> 2008-03-08 19:56:16 +0900waitpid(pid,Process::WNOHANG)#=> nilTime.now#=> 2008-03-08 19:56:16 +0900waitpid(pid,0)#=> 27440Time.now#=> 2008-03-08 19:56:19 +0900
static VALUEproc_m_wait(int c, VALUE *v, VALUE _){ return proc_wait(c, v);}
Waits for a child process to exit (see::waitpid for exact semantics) andreturns an array containing the process id and the exit status (aProcess::Status object) of that child.Raises aSystemCallError if there are nochild processes.
Process.fork {exit99 }#=> 27437pid,status =Process.wait2pid#=> 27437status.exitstatus#=> 99
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());}
Waits for all children, returning an array ofpid/statuspairs (wherestatus is aProcess::Status object).
fork {sleep0.2;exit2 }#=> 27432fork {sleep0.1;exit1 }#=> 27433fork {exit0 }#=> 27434pProcess.waitall
produces:
[[30982, #<Process::Status: pid 30982 exit 0>], [30979, #<Process::Status: pid 30979 exit 1>], [30976, #<Process::Status: pid 30976 exit 2>]]
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 a child process to exit, returns its process id, and sets$?
to aProcess::Statusobject containing information on that process. Which child it waits ondepends on the value ofpid:
Waits for the child whose process ID equalspid.
Waits for any child whose process group ID equals that of the callingprocess.
Waits for any child process (the default if nopid is given).
Waits for any child whose process group ID equals the absolute value ofpid.
Theflags argument may be a logical or of the flag valuesProcess::WNOHANG (do not block if no childavailable) orProcess::WUNTRACED(return stopped children that haven't been reported). Not all flags areavailable on all platforms, but a flag value of zero will work on allplatforms.
Calling this method raises aSystemCallError if there are no childprocesses. Not available on all platforms.
includeProcessfork {exit99 }#=> 27429wait#=> 27429$?.exitstatus#=> 99pid =fork {sleep3 }#=> 27440Time.now#=> 2008-03-08 19:56:16 +0900waitpid(pid,Process::WNOHANG)#=> nilTime.now#=> 2008-03-08 19:56:16 +0900waitpid(pid,0)#=> 27440Time.now#=> 2008-03-08 19:56:19 +0900
static VALUEproc_m_wait(int c, VALUE *v, VALUE _){ return proc_wait(c, v);}
Waits for a child process to exit (see::waitpid for exact semantics) andreturns an array containing the process id and the exit status (aProcess::Status object) of that child.Raises aSystemCallError if there are nochild processes.
Process.fork {exit99 }#=> 27437pid,status =Process.wait2pid#=> 27437status.exitstatus#=> 99
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());}
This page was generated for Ruby 3.0.0
Generated with Ruby-doc Rdoc Generator 0.42.0.