From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: libc-alpha@sourceware.org
Subject: Re: [PATCH] linux: spawni.c: simplify error reporting to parent
Date: Thu, 22 Sep 2016 20:54:00 -0000 [thread overview]
Message-ID: <0b37fd86-671e-9b79-17e7-0efe8345178b@linaro.org> (raw)
In-Reply-To: <1474405260-16657-1-git-send-email-rv@rasmusvillemoes.dk>
LGTM, I think it addressed all the comments.
On 20/09/2016 18:01, Rasmus Villemoes wrote:
> Using VFORK already ensures that the parent does not run until the
> child has either exec'ed succesfully or called _exit. Hence we don't
> need to read from a CLOEXEC pipe to ensure proper synchronization - we
> just make explicit use of the fact the the child and parent run in the
> same VM, so the child can write an error code to a field of the
> posix_spawn_args struct instead of sending it through a pipe.
>
> To ensure that this mechanism really works, the parent initializes the
> field to -1 and the child writes 0 before execing.
>
> This eliminates some annoying bookkeeping that is necessary to avoid
> the file actions from clobbering the write end of the pipe, and
> getting rid of the pipe creation in the first place means fewer system
> calls (four in the parent, usually one in the child) and fewer
> chanches for the spawn to fail (e.g. if we're close to EMFILE).
>
> Signed-off-by: Rasmus Villemoes <rv@rasmusvillemoes.dk>
> ---
> sysdeps/unix/sysv/linux/spawni.c | 71 ++++++++++++++--------------------------
> 1 file changed, 25 insertions(+), 46 deletions(-)
>
> diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
> index bb3eecf..c0e15ac 100644
> --- a/sysdeps/unix/sysv/linux/spawni.c
> +++ b/sysdeps/unix/sysv/linux/spawni.c
> @@ -17,6 +17,7 @@
> <http://www.gnu.org/licenses/>. */
>
> #include <spawn.h>
> +#include <assert.h>
> #include <fcntl.h>
> #include <paths.h>
> #include <string.h>
> @@ -44,11 +45,12 @@
> 3. Child must synchronize with parent to enforce 2. and to possible
> return execv issues.
>
> - The first issue is solved by blocking all signals in child, even the
> - NPTL-internal ones (SIGCANCEL and SIGSETXID). The second and third issue
> - is done by a stack allocation in parent and a synchronization with using
> - a pipe or waitpid (in case or error). The pipe has the advantage of
> - allowing the child the communicate an exec error. */
> + The first issue is solved by blocking all signals in child, even
> + the NPTL-internal ones (SIGCANCEL and SIGSETXID). The second and
> + third issue is done by a stack allocation in parent, and by using a
> + field in struct spawn_args where the child can write an error
> + code. CLONE_VFORK ensures that the parent does not run until the
> + child has either exec'ed successfully or exited. */
>
>
> /* The Unix standard contains a long explanation of the way to signal
> @@ -79,7 +81,6 @@
>
> struct posix_spawn_args
> {
> - int pipe[2];
> sigset_t oldmask;
> const char *file;
> int (*exec) (const char *, char *const *, char *const *);
> @@ -89,6 +90,7 @@ struct posix_spawn_args
> ptrdiff_t argc;
> char *const *envp;
> int xflags;
> + int err;
> };
>
> /* Older version requires that shell script without shebang definition
> @@ -125,11 +127,8 @@ __spawni_child (void *arguments)
> struct posix_spawn_args *args = arguments;
> const posix_spawnattr_t *restrict attr = args->attr;
> const posix_spawn_file_actions_t *file_actions = args->fa;
> - int p = args->pipe[1];
> int ret;
>
> - close_not_cancel (args->pipe[0]);
> -
> /* The child must ensure that no signal handler are enabled because it shared
> memory with parent, so the signal disposition must be either SIG_DFL or
> SIG_IGN. It does by iterating over all signals and although it could
> @@ -203,17 +202,6 @@ __spawni_child (void *arguments)
> {
> struct __spawn_action *action = &file_actions->__actions[cnt];
>
> - /* Dup the pipe fd onto an unoccupied one to avoid any file
> - operation to clobber it. */
> - if ((action->action.close_action.fd == p)
> - || (action->action.open_action.fd == p)
> - || (action->action.dup2_action.fd == p))
> - {
> - if ((ret = __dup (p)) < 0)
> - goto fail;
> - p = ret;
> - }
> -
> switch (action->tag)
> {
> case spawn_do_close:
> @@ -273,6 +261,7 @@ __spawni_child (void *arguments)
> __sigprocmask (SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK)
> ? &attr->__ss : &args->oldmask, 0);
>
> + args->err = 0;
> args->exec (args->file, args->argv, args->envp);
>
> /* This is compatibility function required to enable posix_spawn run
> @@ -280,14 +269,13 @@ __spawni_child (void *arguments)
> (2.15). */
> maybe_script_execute (args);
>
> - ret = -errno;
> -
> fail:
> - /* Since sizeof errno < PIPE_BUF, the write is atomic. */
> - ret = -ret;
> - if (ret)
> - while (write_not_cancel (p, &ret, sizeof ret) < 0)
> - continue;
> + /* errno should have an appropriate non-zero value; otherwise,
> + there's a bug in glibc or the kernel. For lack of an error code
> + (EINTERNALBUG) describing that, use ECHILD. Another option would
> + be to set args->err to some negative sentinel and have the parent
> + abort(), but that seems needlessly harsh. */
> + args->err = errno ? : ECHILD;
> _exit (SPAWN_ERROR);
> }
>
> @@ -304,9 +292,6 @@ __spawnix (pid_t * pid, const char *file,
> struct posix_spawn_args args;
> int ec;
>
> - if (__pipe2 (args.pipe, O_CLOEXEC))
> - return errno;
> -
> /* To avoid imposing hard limits on posix_spawn{p} the total number of
> arguments is first calculated to allocate a mmap to hold all possible
> values. */
> @@ -333,15 +318,14 @@ __spawnix (pid_t * pid, const char *file,
> void *stack = __mmap (NULL, stack_size, prot,
> MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
> if (__glibc_unlikely (stack == MAP_FAILED))
> - {
> - close_not_cancel (args.pipe[0]);
> - close_not_cancel (args.pipe[1]);
> - return errno;
> - }
> + return errno;
>
> /* Disable asynchronous cancellation. */
> int cs = LIBC_CANCEL_ASYNC ();
>
> + /* Child must set args.err to something non-negative - we rely on
> + the parent and child sharing VM. */
> + args.err = -1;
> args.file = file;
> args.exec = exec;
> args.fa = file_actions;
> @@ -355,9 +339,8 @@ __spawnix (pid_t * pid, const char *file,
>
> /* The clone flags used will create a new child that will run in the same
> memory space (CLONE_VM) and the execution of calling thread will be
> - suspend until the child calls execve or _exit. These condition as
> - signal below either by pipe write (_exit with SPAWN_ERROR) or
> - a successful execve.
> + suspend until the child calls execve or _exit.
> +
> Also since the calling thread execution will be suspend, there is not
> need for CLONE_SETTLS. Although parent and child share the same TLS
> namespace, there will be no concurrent access for TLS variables (errno
> @@ -365,22 +348,18 @@ __spawnix (pid_t * pid, const char *file,
> new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size,
> CLONE_VM | CLONE_VFORK | SIGCHLD, &args);
>
> - close_not_cancel (args.pipe[1]);
> -
> if (new_pid > 0)
> {
> - if (__read (args.pipe[0], &ec, sizeof ec) != sizeof ec)
> - ec = 0;
> - else
> - __waitpid (new_pid, NULL, 0);
> + ec = args.err;
> + assert (ec >= 0);
> + if (ec != 0)
> + __waitpid (new_pid, NULL, 0);
> }
> else
> ec = -new_pid;
>
> __munmap (stack, stack_size);
>
> - close_not_cancel (args.pipe[0]);
> -
> if ((ec == 0) && (pid != NULL))
> *pid = new_pid;
>
>
next prev parent reply other threads:[~2016-09-22 20:54 UTC|newest]
Thread overview: 45+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-02-01 16:21 [PATCH 0/3] posix: Execute file function fixes Adhemerval Zanella
2016-02-01 16:21 ` [PATCH v2 3/3] posix: New Linux posix_spawn{p} implementation Adhemerval Zanella
2016-02-02 13:06 ` Florian Weimer
2016-02-02 13:31 ` Adhemerval Zanella
2016-02-03 11:07 ` Torvald Riegel
2016-02-03 12:05 ` Adhemerval Zanella
2016-02-03 12:06 ` Torvald Riegel
2016-02-03 12:14 ` Adhemerval Zanella
2016-08-31 21:13 ` Rasmus Villemoes
2016-08-31 22:08 ` Joseph Myers
2016-09-01 9:28 ` Rasmus Villemoes
2016-09-14 13:13 ` Adhemerval Zanella
2016-09-14 18:58 ` Rasmus Villemoes
2016-09-14 19:59 ` Adhemerval Zanella
2016-09-20 20:25 ` Florian Weimer
2016-09-20 20:54 ` Rasmus Villemoes
2016-09-20 21:01 ` [PATCH] linux: spawni.c: simplify error reporting to parent Rasmus Villemoes
2016-09-22 20:54 ` Adhemerval Zanella [this message]
2016-09-23 5:21 ` Florian Weimer
2016-09-23 19:09 ` Rasmus Villemoes
2016-09-23 19:28 ` Adhemerval Zanella
2016-09-23 20:37 ` Florian Weimer
2016-09-27 20:26 ` Rasmus Villemoes
2016-09-27 21:14 ` Adhemerval Zanella
2016-09-28 14:14 ` Rich Felker
2016-09-28 15:03 ` Andreas Schwab
2016-09-28 15:22 ` Rich Felker
2016-09-28 18:13 ` Adhemerval Zanella
2016-10-06 12:52 ` Florian Weimer
2016-09-06 20:43 ` [PATCH v2 3/3] posix: New Linux posix_spawn{p} implementation Rasmus Villemoes
2016-09-14 19:37 ` Adhemerval Zanella
2016-02-01 16:21 ` [PATCH v2 1/3] posix: Remove dynamic memory allocation from execl{e,p} Adhemerval Zanella
2016-02-01 16:52 ` Joseph Myers
2016-02-01 17:18 ` Adhemerval Zanella
2016-02-01 17:54 ` Joseph Myers
2016-02-01 18:09 ` Adhemerval Zanella
2016-02-02 11:24 ` Florian Weimer
2016-02-02 12:46 ` Szabolcs Nagy
2016-02-02 12:47 ` Adhemerval Zanella
2016-02-02 16:33 ` Rich Felker
2016-02-07 21:28 ` Rasmus Villemoes
2016-02-09 11:36 ` Richard Henderson
2016-02-09 13:30 ` Szabolcs Nagy
2016-02-10 16:36 ` Adhemerval Zanella
2016-02-01 16:21 ` [PATCH v4 2/3] posix: execvpe cleanup Adhemerval Zanella
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0b37fd86-671e-9b79-17e7-0efe8345178b@linaro.org \
--to=adhemerval.zanella@linaro.org \
--cc=libc-alpha@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).