aboutsummaryrefslogtreecommitdiffstats
path: root/process.c
diff options
context:
space:
mode:
authorBurdette Lamar <BurdetteLamar@Yahoo.com>2023-08-23 22:21:44 -0500
committerGitHub <noreply@github.com>2023-08-23 23:21:44 -0400
commit7e0d2c614341521a958f84adbeca738c6824f222 (patch)
tree8075ec03d98b361f6844844d89ee2dec47a19c3b /process.c
parentd4c720a91bc7bb9ff31810e1720acffb939f7a2f (diff)
downloadruby-7e0d2c614341521a958f84adbeca738c6824f222.tar.gz
[DOC] RDoc for Process (#8253)
Diffstat (limited to 'process.c')
-rw-r--r--process.c359
1 files changed, 249 insertions, 110 deletions
diff --git a/process.c b/process.c
index 467efa181b..930a96d3f4 100644
--- a/process.c
+++ b/process.c
@@ -1419,21 +1419,18 @@ proc_m_wait(int c, VALUE *v, VALUE _)
return proc_wait(c, v);
}
-
/*
* call-seq:
- * Process.wait2(pid=-1, flags=0) -> [pid, status]
- * Process.waitpid2(pid=-1, flags=0) -> [pid, status]
- *
- * Waits for a child process to exit (see Process::waitpid for exact
- * semantics) and returns an array containing the process ID and the
- * exit status (a Process::Status object) of that
- * child. Raises a SystemCallError if there are no child processes.
- *
- * Process.fork { exit 99 } #=> 27437
- * pid, status = Process.wait2
- * pid #=> 27437
- * status.exitstatus #=> 99
+ * Process.wait2(pid = -1, flags = 0) -> [pid, status]
+ *
+ * Like Process.waitpid, but returns an array
+ * containing the child process +pid+ and Process::Status +status+:
+ *
+ * pid = Process.spawn('ruby', '-e', 'exit 13') # => 309581
+ * Process.wait2(pid)
+ * # => [309581, #<Process::Status: pid 309581 exit 13>]
+ *
+ * Process.waitpid2 is an alias for Process.waitpid.
*/
static VALUE
@@ -1447,22 +1444,17 @@ proc_wait2(int argc, VALUE *argv, VALUE _)
/*
* call-seq:
- * Process.waitall -> [ [pid1,status1], ...]
- *
- * Waits for all children, returning an array of
- * _pid_/_status_ pairs (where _status_ is a
- * Process::Status object).
+ * Process.waitall -> array
*
- * fork { sleep 0.2; exit 2 } #=> 27432
- * fork { sleep 0.1; exit 1 } #=> 27433
- * fork { exit 0 } #=> 27434
- * p Process.waitall
+ * Waits for all children, returns an array of 2-element arrays;
+ * each subarray contains the integer pid and Process::Status status
+ * for one of the reaped child processes:
*
- * <em>produces</em>:
+ * pid0 = Process.spawn('ruby', '-e', 'exit 13') # => 325470
+ * pid1 = Process.spawn('ruby', '-e', 'exit 14') # => 325495
+ * Process.waitall
+ * # => [[325470, #<Process::Status: pid 325470 exit 13>], [325495, #<Process::Status: pid 325495 exit 14>]]
*
- * [[30982, #<Process::Status: pid 30982 exit 0>],
- * [30979, #<Process::Status: pid 30979 exit 1>],
- * [30976, #<Process::Status: pid 30976 exit 2>]]
*/
static VALUE
@@ -1520,48 +1512,41 @@ rb_detach_process(rb_pid_t pid)
/*
* call-seq:
- * Process.detach(pid) -> thread
+ * Process.detach(pid) -> thread
*
- * Some operating systems retain the status of terminated child
- * processes until the parent collects that status (normally using
- * some variant of <code>wait()</code>). If the parent never collects
- * this status, the child stays around as a <em>zombie</em> process.
- * Process::detach prevents this by setting up a separate Ruby thread
- * whose sole job is to reap the status of the process _pid_ when it
- * terminates. Use #detach only when you do not intend to explicitly
- * wait for the child to terminate.
+ * Avoids the potential for a child process to become a
+ * {zombie process}[https://en.wikipedia.org/wiki/Zombie_process].
+ * Process.detach prevents this by setting up a separate Ruby thread
+ * whose sole job is to reap the status of the process _pid_ when it terminates.
*
- * The waiting thread returns the exit status of the detached process
- * when it terminates, so you can use Thread#join to
- * know the result. If specified _pid_ is not a valid child process
- * ID, the thread returns +nil+ immediately.
+ * This method is needed only when the parent process will never wait
+ * for the child process.
*
- * The waiting thread has #pid method which returns the pid.
+ * This example does not reap the second child process;
+ * that process appears as a zombie in the process status (+ps+) output:
*
- * In this first example, we don't reap the first child process, so
- * it appears as a zombie in the process status display.
+ * pid = Process.spawn('ruby', '-e', 'exit 13') # => 312691
+ * sleep(1)
+ * # Find zombies.
+ * system("ps -ho pid,state -p #{pid}")
*
- * p1 = fork { sleep 0.1 }
- * p2 = fork { sleep 0.2 }
- * Process.waitpid(p2)
- * sleep 2
- * system("ps -ho pid,state -p #{p1}")
+ * Output:
*
- * <em>produces:</em>
+ * 312716 Z
*
- * 27389 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:
*
- * In the next example, Process::detach is used to reap
- * the child automatically.
+ * pid = Process.spawn('ruby', '-e', 'exit 13') # => 313213
+ * thread = Process.detach(pid)
+ * sleep(1)
+ * # => #<Process::Waiter:0x00007f038f48b838 run>
+ * system("ps -ho pid,state -p #{pid}") # Finds no zombies.
*
- * p1 = fork { sleep 0.1 }
- * p2 = fork { sleep 0.2 }
- * Process.detach(p1)
- * Process.waitpid(p2)
- * sleep 2
- * system("ps -ho pid,state -p #{p1}")
+ * The waiting thread can return the pid of the detached child process:
+ *
+ * thread.join.pid # => 313262
*
- * <em>(produces no output)</em>
*/
static VALUE
@@ -3020,77 +3005,65 @@ NORETURN(static VALUE f_exec(int c, const VALUE *a, VALUE _));
/*
* call-seq:
- * exec([env,] command... [,options])
- *
- * Replaces the current process by running the given external _command_, which
- * can take one of the following forms:
+ * exec([env, ] command_line, options = {})
+ * exec([env, ] exe_path, *args, options = {})
*
- * [<code>exec(commandline)</code>]
- * command line string which is passed to the standard shell
- * [<code>exec(cmdname, arg1, ...)</code>]
- * command name and one or more arguments (no shell)
- * [<code>exec([cmdname, argv0], arg1, ...)</code>]
- * command name, +argv[0]+ and zero or more arguments (no shell)
+ * Replaces the current process by doing one of the following:
*
- * In the first form, the string is taken as a command line that is subject to
- * shell expansion before being executed.
+ * - Passing string +command_line+ to the shell.
+ * - Invoking the executable at +exe_path+.
*
- * The standard shell always means <code>"/bin/sh"</code> on Unix-like systems,
- * otherwise, <code>ENV["RUBYSHELL"]</code> or <code>ENV["COMSPEC"]</code> on
- * Windows and similar. The command is passed as an argument to the
- * <code>"-c"</code> switch to the shell, except in the case of +COMSPEC+.
+ * The new process is created using the
+ * {exec system call}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/functions/execve.html];
+ * it may inherit some of its environment from the calling program
+ * (possibly including open file descriptors).
*
- * If the string from the first form (<code>exec("command")</code>) follows
- * these simple rules:
+ * Argument +env+, if given, is a hash that affects +ENV+ for the new process;
+ * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
*
- * * no meta characters,
- * * not starting with shell reserved word or special built-in,
+ * Argument +options+ is a hash of options for the new process;
+ * see {Execution Options}[rdoc-ref:Process@Execution+Options].
*
- * Ruby invokes the command directly without shell.
+ * The first required argument is one of the following:
*
- * You can force shell invocation by adding ";" to the string (because ";" is
- * a meta character).
+ * - +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 metacharacters.
+ * - +exe_path+ otherwise.
*
- * Note that this behavior is observable by pid obtained
- * (return value of spawn() and IO#pid for IO.popen) is the pid of the invoked
- * command, not shell.
+ * <b>Argument +command_line+</b>
*
- * In the second form (<code>exec("command1", "arg1", ...)</code>), the first
- * is taken as a command name and the rest are passed as parameters to command
- * with no shell expansion.
+ * \String argument +command_line+ is a command line to be passed to a shell;
+ * it must begin with a shell reserved word, begin with a special built-in,
+ * or contain meta characters.
+ * It may also contain arguments and options for that command.
*
- * In the third form (<code>exec(["command", "argv0"], "arg1", ...)</code>),
- * starting a two-element array at the beginning of the command, the first
- * element is the command to be executed, and the second argument is used as
- * the <code>argv[0]</code> value, which may show up in process listings.
+ * On a Unix-like system, the shell is <tt>/bin/sh</tt>;
+ * otherwise the shell is determined by environment variable
+ * <tt>ENV['RUBYSHELL']</tt>, if defined, or <tt>ENV['COMSPEC']</tt> otherwise.
*
- * In order to execute the command, one of the <code>exec(2)</code> system
- * calls are used, so the running command may inherit some of the environment
- * of the original program (including open file descriptors).
+ * Except for the +COMSPEC+ case,
+ * the entire string +command_line+ is passed as an argument
+ * to {shell option -c}[https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/sh.html].
*
- * This behavior is modified by the given +env+ and +options+ parameters. See
- * ::spawn for details.
+ * The shell performs normal shell expansion on the command line.
*
- * If the command fails to execute (typically Errno::ENOENT when
- * it was not found) a SystemCallError exception is raised.
+ * Raises an exception if the new process fails to execute.
*
- * This method modifies process attributes according to given +options+ before
- * <code>exec(2)</code> system call. See ::spawn for more details about the
- * given +options+.
+ * <b>Argument +exe_path+</b>
*
- * The modified attributes may be retained when <code>exec(2)</code> system
- * call fails.
+ * Argument +exe_path+ is one of the following:
*
- * For example, hard resource limits are not restorable.
+ * - 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.
*
- * Consider to create a child process using ::spawn or Kernel#system if this
- * is not acceptable.
+ * Ruby invokes the executable directly, with no shell and no shell expansion.
*
- * exec "echo *" # echoes list of files in current directory
- * # never get here
+ * If one or more +args+ is given, each is an argument or option
+ * to be passed to the executable.
*
- * exec "echo", "*" # echoes an asterisk
- * # never get here
+ * Raises an exception if the new process fails to execute.
*/
static VALUE
@@ -8669,6 +8642,172 @@ proc_warmup(VALUE _)
* \Module +Process+ represents a process in the underlying operating system.
* Its methods support management of the current process and its child processes.
*
+ * == \Process Creation
+ *
+ * Each of these methods creates a process:
+ *
+ * - Process.exec: Replaces the current process by running a given external command.
+ * - Process.spawn, Kernel#spawn: Executes the given command and returns its pid without waiting for completion.
+ * - Kernel#system: Executes the given command in a subshell.
+ *
+ * Each of these methods accepts:
+ *
+ * - An optional hash of environment variable names and values.
+ * - An optional hash of execution options.
+ *
+ * === Execution Environment
+ *
+ * Optional leading argument +env+ is a hash of name/value pairs,
+ * where each name is a string and each value is a string or +nil+;
+ * each name/value pair is added to ENV in the new process.
+ *
+ * Process.spawn( 'ruby -e "p ENV[\"Foo\"]"')
+ * Process.spawn({'Foo' => '0'}, 'ruby -e "p ENV[\"Foo\"]"')
+ *
+ * Output:
+ *
+ * nil
+ * "0"
+ *
+ * The effect is usually similar to that of calling ENV#update with argument +env+,
+ * where each named environment variable is created or updated
+ * (if the value is non-+nil+),
+ * or deleted (if the value is +nil+).
+ *
+ * However, some modifications to the calling process may remain
+ * if the new process fails.
+ * For example, hard resource limits are not restored.
+ *
+ * === Execution Options
+ *
+ * Optional trailing argument +options+ is a hash of execution options.
+ *
+ * ==== Working Directory (+:chdir+)
+ *
+ * By default, the working directory for the new process is the same as
+ * that of the current process:
+ *
+ * Dir.chdir('/var')
+ * Process.spawn('ruby -e "puts Dir.pwd"')
+ *
+ * Output:
+ *
+ * /var
+ *
+ * Use option +:chdir+ to set the working directory for the new process:
+ *
+ * Process.spawn('ruby -e "puts Dir.pwd"', {chdir: '/tmp'})
+ *
+ * Output:
+ *
+ * /tmp
+ *
+ * The working directory of the current process is not changed:
+ *
+ * Dir.pwd # => "/var"
+ *
+ * ==== \File Redirection (\File Descriptor)
+ *
+ * Use execution options for file redirection in the new process.
+ *
+ * The key for such an option may be an integer file descriptor (fd),
+ * specifying a source,
+ * or an array of fds, specifying multiple sources.
+
+ * An integer source fd may be specified as:
+ *
+ * - _n_: Specifies file descriptor _n_.
+ *
+ * There are these shorthand symbols for fds:
+ *
+ * - +:in+: Specifies file descriptor 0 (STDIN).
+ * - +:out+: Specifies file descriptor 1 (STDOUT).
+ * - +:err+: Specifies file descriptor 2 (STDERR).
+ *
+ * The value given with a source is one of:
+ *
+ * - _n_:
+ * Redirects to fd _n_ in the parent process.
+ * - +filepath+:
+ * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, 0644)</tt>,
+ * where +mode+ is <tt>'r'</tt> for source +:in+,
+ * or <tt>'w'</tt> for source +:out+ or +:err+.
+ * - <tt>[filepath]</tt>:
+ * Redirects from the file at +filepath+ via <tt>open(filepath, 'r', 0644)</tt>.
+ * - <tt>[filepath, mode]</tt>:
+ * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, 0644)</tt>.
+ * - <tt>[filepath, mode, perm]</tt>:
+ * Redirects from or to the file at +filepath+ via <tt>open(filepath, mode, perm)</tt>.
+ * - <tt>[:child, fd]</tt>:
+ * Redirects to the redirected +fd+.
+ * - +:close+: Closes the file descriptor in child process.
+ *
+ * See {Access Modes}[rdoc-ref:File@Access+Modes]
+ * and {File Permissions}[rdoc-ref:File@File+Permissions].
+ *
+ * ==== Environment Variables (+:unsetenv_others+)
+ *
+ * By default, the new process inherits environment variables
+ * from the parent process;
+ * use execution option key +:unsetenv_others+ with value +true+
+ * to clear environment variables in the new process.
+ *
+ * Any changes specified by execution option +env+ are made after the new process
+ * inherits or clears its environment variables;
+ * see {Execution Environment}[rdoc-ref:Process@Execution+Environment].
+ *
+ * ==== \File-Creation Access (+:umask+)
+ *
+ * Use execution option +:umask+ to set the file-creation access
+ * for the new process;
+ * see {Access Modes}[rdoc-ref:File@Access+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 same
+ * {process group}[https://en.wikipedia.org/wiki/Process_group]
+ * as the parent process.
+ *
+ * To specify a different process group.
+ * use execution option +:pgroup+ with one of the following values:
+ *
+ * - +true+: Create a new process group for the new process.
+ * - _pgid_: Create the new process in the process group
+ * whose id is _pgid_.
+ *
+ * On Windows only, use execution option +:new_pgroup+ with value +true+
+ * to create a new process group for the new process.
+ *
+ * ==== Resource Limits
+ *
+ * Use execution options to set resource limits.
+ *
+ * The keys for these options are symbols of the form
+ * <tt>:rlimit_<i>resource_name</i></tt>,
+ * where _resource_name_ is the downcased form of one of the string
+ * resource names described at method Process.setrlimit.
+ * For example, key +:rlimit_cpu+ corresponds to resource limit <tt>'CPU'</tt>.
+ *
+ * The value for such as key is one of:
+ *
+ * - An integer, specifying both the current and maximum limits.
+ * - A 2-element array of integers, specifying the current and maximum limits.
+ *
+ * ==== \File Descriptor Inheritance
+ *
+ * By default, the new process inherits file descriptors from the parent process.
+ *
+ * Use execution option <tt>:close_others => true</tt> to modify that inheritance
+ * by closing non-standard fds (3 and greater) that are not otherwise redirected.
+ *
* == What's Here
*
* === Current-Process Getters