From 15255b303c7fffa146550f69df6f9f772af38ea3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?= Date: Tue, 2 Mar 2021 18:02:30 +0900 Subject: include/ruby/internal/intern/process.h: add doxygen Must not be a bad idea to improve documents. [ci skip] --- include/ruby/internal/intern/process.h | 237 ++++++++++++++++++++++++++++++++- 1 file changed, 232 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/ruby/internal/intern/process.h b/include/ruby/internal/intern/process.h index 2f7255ccf8..7a7b24ed4b 100644 --- a/include/ruby/internal/intern/process.h +++ b/include/ruby/internal/intern/process.h @@ -20,6 +20,7 @@ * extension libraries. They could be written in C++98. * @brief Public APIs related to ::rb_mProcess. */ +#include "ruby/internal/attr/nonnull.h" #include "ruby/internal/attr/noreturn.h" #include "ruby/internal/config.h" /* rb_pid_t is defined here. */ #include "ruby/internal/dllexport.h" @@ -28,17 +29,243 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() /* process.c */ + +/** + * Sets the "last status", or the `$?`. + * + * @param[in] status The termination status, as defined in `waitpid(3posix)`. + * @param[in] pid The last child of the current process. + * @post `$?` is updated. + */ void rb_last_status_set(int status, rb_pid_t pid); + +/** + * Queries the "last status", or the `$?`. + * + * @retval RUBY_Qnil The current thread has no dead children. + * @retval otherwise An instance of Process::Status describing the status of + * the child that was most recently `wait`-ed. + */ VALUE rb_last_status_get(void); -int rb_proc_exec(const char*); + +RBIMPL_ATTR_NONNULL(()) +/** + * Executes a shell command. + * + * @warning THIS FUNCTION RETURNS on error! + * @param[in] cmd Passed to the shell. + * @retval -1 Something prevented the command execution. + * @post Upon successful execution this function doesn't return. + * @post In case it returns the `errno` is set properly. + */ +int rb_proc_exec(const char *cmd); RBIMPL_ATTR_NORETURN() -VALUE rb_f_exec(int, const VALUE*); +/** + * Replaces the current process by running the given external command. This is + * the implementation of `Kernel#exec`. + * + * @param[in] argc Number of objects in `argv`. + * @param[in] argv Command and its options to execute. + * @exception rb_eTypeError Invalid options e.g. non-String argv. + * @exception rb_eArgError Invalid options e.g. redirection cycle. + * @exception rb_eNotImpError Not implemented e.g. no `setuid(2)`. + * @exception rb_eRuntimeError `Process::UID.switch` in operation. + * @exception rb_eSystemCallError `execve(2)` failed. + * @warning This function doesn't return. + * @warning On failure it raises. On success the process is replaced. + * + * @internal + * + * @shyouhei have to say that the rdoc for `Kernel#exec` is fairly incomplete. + * AFAIK this function ultimately takes the following signature: + * + * ```rbs + * type boolx = bool | nil # != `boolish` + * + * type rlim_t = Integer # rlim_cur + * | [ Integer, Integer ] # rlim_cur, rlim_max + * + * type uid_t = String # e.g. "root" + * | Integer # e.g. 0 + * + * type gid_t = String # e.g. "wheel" + * | Integer # e.g. 0 + * + * type fmode = String # e.g. "rb" + * | Integer # e.g. O_RDONLY | O_BINARY + * + * type mode_t = Integer # e.g. 0644 + * + * type pgrp = true # Creates a dedicated pgroup + * | 0 # ditto + * | nil # Uses the current one + * | Integer # Uses this specific pgroup + * + * type fd = :in # STDIN + * | :out # STDOUT + * | :err # STDERR + * | IO # This specific IO + * | Integer # A file descriptor of this # + * + * type src = fd | [ fd ] + * type dst = :close # Intuitive + * | fd # Intuitive + * | String # Open a file at this path + * | [ String ] # ... using O_RDONLY + * | [ String, fmode ] # ... using this mode + * | [ String, fmode, mode_t ] # ... with a permission + * | [ :child, fd ] # fd of child side + * + * type redir = Hash[ src, dst ] + * + * # ---- + * + * # Key-value pair of environment variables + * type envp = Hash[ String, String ] + * + * # Actual name (and the name passed to the subprocess if any) + * type arg0 = String | [ String, String ] + * + * # Arbitrary string parameters + * type argv = String + * + * # Exec options: + * type argh = redir | { + * chdir: String, # Working directory + * close_others: boolx, # O_CLOEXEC like behaviour + * gid: gid_t, # setegid(2) + * pgrooup: pgrp, # setpgrp(2) + * rlimit_as: rlim_t, # setrlimit(2) + * rlimit_core: rlim_t, # ditto + * rlimit_cpu: rlim_t, # ditto + * rlimit_data: rlim_t, # ditto + * rlimit_fsize: rlim_t, # ditto + * rlimit_memlock: rlim_t, # ditto + * rlimit_msgqueue: rlim_t, # ditto + * rlimit_nice: rlim_t, # ditto + * rlimit_nofile: rlim_t, # ditto + * rlimit_nproc: rlim_t, # ditto + * rlimit_rss: rlim_t, # ditto + * rlimit_rtprio: rlim_t, # ditto + * rlimit_rttime: rlim_t, # ditto + * rlimit_sbsize: rlim_t, # ditto + * rlimit_sigpending: rlim_t, # ditto + * rlimit_stack: rlim_t, # ditto + * uid: uid_t, # seteuid(2) + * umask: mode_t, # umask(2) + * unsetenv_others: boolx # Unset everything except the passed envp + * } + * + * # ==== + * + * class Kernel + * def self?.exec + * : ( arg0 cmd, *argv args ) -> void + * | ( arg0 cmd, *argv args, argh opts) -> void + * | (envp env, arg0 cmd, *argv args ) -> void + * | (envp env, arg0 cmd, *argv args, argh opts) -> void + * end + * ``` + */ +VALUE rb_f_exec(int argc, const VALUE *argv); + +/** + * Waits for a process, with releasing GVL. + * + * @param[in] pid Process ID. + * @param[out] status The wait status is filled back. + * @param[in] flags Wait options. + * @retval -1 System call failed, errno set. + * @retval 0 WNOHANG but no waitable children. + * @retval otherwise A process ID that was `wait()`-ed. + * @post Upon successful return `status` is updated to have the process' + * status. + * @note `status` can be NULL. + * @note The arguments are passed through to underlying system call(s). + * Can have special meanings. For instance passing `(rb_pid_t)-1` + * to `pid` means it waits for any processes, under + * POSIX-compliant situations. + */ rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags); + +/** + * This is a shorthand of rb_waitpid without status and flags. It has been + * like this since the very beginning. The initial revision already did the + * same thing. Not sure why, then, it has been named `syswait`. AFAIK this is + * different from how `wait(3posix)` works. + * + * @param[in] pid Passed to rb_waitpid(). + */ void rb_syswait(rb_pid_t pid); -rb_pid_t rb_spawn(int, const VALUE*); -rb_pid_t rb_spawn_err(int, const VALUE*, char*, size_t); -VALUE rb_proc_times(VALUE); + +/** + * Identical to rb_f_exec(), except it spawns a child process instead of + * replacing the current one. + * + * @param[in] argc Number of objects in `argv`. + * @param[in] argv Command and its options to execute. + * @exception rb_eTypeError Invalid options e.g. non-String argv. + * @exception rb_eArgError Invalid options e.g. redirection cycle. + * @exception rb_eNotImpError Not implemented e.g. no `setuid(2)`. + * @exception rb_eRuntimeError `Process::UID.switch` in operation. + * @retval -1 Child process died for some reason. + * @retval otherwise The ID of the born child. + * + * @internal + * + * This is _really_ identical to rb_f_exec() until ultimately calling the + * system call. Almost everything are shared among these two (and + * rb_f_system()). + */ +rb_pid_t rb_spawn(int argc, const VALUE *argv); + +/** + * Identical to rb_spawn(), except you can additionally know the detailed + * situation in case of abnormal parturitions. + * + * @param[in] argc Number of objects in `argv`. + * @param[in] argv Command and its options to execute. + * @param[out] errbuf Error description write-back buffer. + * @param[in] buflen Number of bytes of `errbuf`, including NUL. + * @exception rb_eTypeError Invalid options e.g. non-String argv. + * @exception rb_eArgError Invalid options e.g. redirection cycle. + * @exception rb_eNotImpError Not implemented e.g. no `setuid(2)`. + * @exception rb_eRuntimeError `Process::UID.switch` in operation. + * @retval -1 Child process died for some reason. + * @retval otherwise The ID of the born child. + * @post In case of `-1`, at most `buflen` bytes of the reason why is + * written back to `errbuf`. + */ +rb_pid_t rb_spawn_err(int argc, const VALUE *argv, char *errbuf, size_t buflen); + +/** + * Gathers info about resources consumed by the current process. + * + * @param[in] _ Not used. Pass anything. + * @return An instance of `Process::Tms`. + * + * @internal + * + * This function might or might not exist depending on `./confiugre` result. + * It must be a portability hell. Better not use. + */ +VALUE rb_proc_times(VALUE _); + +/** + * "Detaches" a subprocess. In POSIX systems every child processes that a + * process creates must be `wait(2)`-ed. A child process that died yet has not + * been waited so far is called a "zombie", which more or less consumes + * resources. This function automates reclamation of such processes. Once + * after this function successfully returns you can basically forget about the + * child process. + * + * @param[in] pid Process to wait. + * @return An instance of ::rb_cThread which is `waitpid(2)`-ing `pid`. + * @post You can just forget about the return value. GC reclaims it. + * @post You can know the exit status by querying `#value` of the + * return value (which is a blocking operation). + */ VALUE rb_detach_process(rb_pid_t pid); RBIMPL_SYMBOL_EXPORT_END() -- cgit v1.2.3