civodul pushed a commit to branch wip-posix-spawn in repository guile. commit 354a7e91ef059468c8c31778d73fee2044261f27 Author: Ludovic Courtès <l...@gnu.org> AuthorDate: Fri Jan 13 15:37:56 2023 +0100
squash! Add 'spawn'. * NEWS: Update. --- NEWS | 15 ++++++++++++++- doc/ref/posix.texi | 17 +++++++++++------ libguile/posix.c | 20 +++++++++++++------- 3 files changed, 38 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index 07011c3c6..b3d31cf89 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,5 @@ Guile NEWS --- history of user-visible changes. -Copyright (C) 1996-2022 Free Software Foundation, Inc. +Copyright (C) 1996-2023 Free Software Foundation, Inc. See the end for copying conditions. Please send Guile bug reports to bug-gu...@gnu.org. @@ -11,6 +11,19 @@ Changes in 3.0.9 (since 3.0.8) * New interfaces and functionality +** New `spawn' procedure to spawn child processes + +The new `spawn' procedure creates a child processes executing the given +program. It lets you control the environment variables of that process +and redirect its standard input, standard output, and standard error +streams. + +Being implemented in terms of `posix_spawn', it is more portable, more +robust, and more efficient than the combination of `primitive-fork' and +`execl'. See "Processes" in the manual for details, and see the 2019 +paper entitled "A fork() in the road" (Andrew Baumann et al.) for +background information. + ** `open-file' now supports an "e" flag for O_CLOEXEC Until now, the high-level `open-file' facility did not provide a way to diff --git a/doc/ref/posix.texi b/doc/ref/posix.texi index cb737204f..5653d3758 100644 --- a/doc/ref/posix.texi +++ b/doc/ref/posix.texi @@ -2046,10 +2046,14 @@ Guile issues a warning if it detects a fork from a multi-threaded program. @quotation Note -If you are only looking to fork+exec with some pipes set up, using pipes -or the more @code{spawn} procedure described below will be more robust -(in particular in multi-threaded contexts), more portable, and usually -more efficient. +If you are looking to spawn a process with some pipes set up, using the +@code{spawn} procedure described below will be more robust (in +particular in multi-threaded contexts), more portable, and usually more +efficient than the combination of @code{primitive-fork} and +@code{execl}. + +@c Recommended reading: ``A fork() in the road'', HotOS 2019, +@c <https://dx.doi.org/10.1145/3317550.3321435> (paywalled :-/). @end quotation This procedure has been renamed from @code{fork} to avoid a naming conflict @@ -2063,8 +2067,9 @@ with the scsh fork. [#:error=(current-error-port)] @ [#:search-path?=#t] Spawn a new child process executing @var{program} with the -given @var{arguments}, a list of one or more strings, and -return its PID. Raise a @code{system-error} exception if +given @var{arguments}, a list of one or more strings (by +convention, the first argument is typically @var{program}), +and return its PID. Raise a @code{system-error} exception if @var{program} could not be found or could not be executed. If the keyword argument @code{#:search-path?} is true, it diff --git a/libguile/posix.c b/libguile/posix.c index 79f96192f..ae9792890 100644 --- a/libguile/posix.c +++ b/libguile/posix.c @@ -1420,8 +1420,9 @@ SCM_KEYWORD (kw_search_path, "search-path?"); SCM_DEFINE (scm_spawn_process, "spawn", 2, 0, 1, (SCM program, SCM arguments, SCM keyword_args), "Spawn a new child process executing @var{program} with the\n" - "given @var{arguments}, a list of one or more strings, and\n" - "return its PID. Raise a @code{system-error} exception if\n" + "given @var{arguments}, a list of one or more strings (by\n" + "convention, the first argument is typically @var{program}),\n" + "and return its PID. Raise a @code{system-error} exception if\n" "@var{program} could not be found or could not be executed.\n\n" "If the keyword argument @code{#:search-path?} is true, it\n" "selects whether the @env{PATH} environment variable should be\n" @@ -1441,6 +1442,12 @@ SCM_DEFINE (scm_spawn_process, "spawn", 2, 0, 1, char *exec_file, **exec_argv, **exec_env; int in, out, err; + /* In theory 'exec' accepts zero arguments, but programs are typically + not prepared for that and POSIX says: "The value in argv[0] should + point to a filename string that is associated with the process + image being started" (see + <https://pubs.opengroup.org/onlinepubs/9699919799/functions/posix_spawn.html>). */ + SCM_VALIDATE_NONEMPTYLIST (1, arguments); env = SCM_UNDEFINED; in_scm = SCM_UNDEFINED; @@ -1456,14 +1463,12 @@ SCM_DEFINE (scm_spawn_process, "spawn", 2, 0, 1, kw_search_path, &use_path, SCM_UNDEFINED); - exec_file = scm_to_locale_string (program); - scm_dynwind_begin (0); + + exec_file = scm_to_locale_string (program); scm_dynwind_free (exec_file); exec_argv = scm_i_allocate_string_pointers (arguments); - if (exec_argv[0] == NULL) - SCM_MISC_ERROR ("empty argument list", SCM_EOL); if (SCM_UNBNDP (env)) exec_env = environ; @@ -1562,7 +1567,8 @@ piped_process (pid_t *pid, SCM prog, SCM args, SCM from, SCM to) break; default: /* ENOENT, etc. */ - /* Create a dummy process that exits with value 127. */ + /* Report the error on the console (before switching to + 'posix_spawn', the child process would do exactly that.) */ dprintf (err, "In execvp of %s: %s\n", exec_file, strerror (errno_save)); }