public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: libc-alpha@sourceware.org
Subject: Re: [PATCH v2 3/5] posix: Optimize stack Linux posix_spawn
Date: Wed, 28 Aug 2019 14:09:00 -0000	[thread overview]
Message-ID: <11104fa2-d420-e8eb-9fc6-bd5dbdfea042@linaro.org> (raw)
In-Reply-To: <20190731183136.21545-3-adhemerval.zanella@linaro.org>

Ping.

On 31/07/2019 15:31, Adhemerval Zanella wrote:
> Changes from previous version:
> 
>   * Move the logic of stack mapping creation to stackmap.h and
>     added a guard page allocation for the compatibility case.
> 
> --
> 
> The current internal posix_spawn symbol for Linux (__spawni) requires
> to allocate a dynamic stack based on input arguments to handle the
> SPAWN_XFLAGS_USE_PATH internal flag, which re-issue the input binary
> as a shell script if execve call return ENOEXEC (to execute shell
> scripts with an initial shebang).
> 
> This is done only for compatibility mode and the generic case does not
> require the extra calculation plus the potential large mmap/munmap
> call.  For default case, a pre-defined buffer is sufficed to use on the
> clone call instead.
> 
> This patch optimizes Linux spawni by allocating a dynamic stack only
> for compatibility symbol (SPAWN_XFLAGS_USE_PATH).  For generic case,
> an mmap allocated buffer is used along with a guard page, similar to
> what NPTL uses for thread stacks hardening.
> 
> For default case, it is a fixed code path with fixed stack usage in helper
> process, so assuming a large enough stack buffer it would never overflow.
> It also does not prevent to adapt to the vfork-like to re-use process
> stack, once it is implemented.
> 
> Checked x86_64-linux-gnu and i686-linux-gnu.
> 
> 	* sysdeps/unix/sysv/linux/spawni.c (posix_spawn_args): Remove
> 	argc member.
> 	(maybe_script_execute): Remove function.
> 	(execve_compat, __spawni_clone, __spawnix_compat): New function.
> 	(__spawni_child): Remove maybe_script_execute call.
> 	(__spawnix): Remove magic stack slack constant with stack_slack
> 	identifier.
> 	(__spawni): Only allocates a variable stack when
> 	SPAWN_XFLAGS_TRY_SHELL is used.
> 	* posix/stackmap.h: New file.
> 	* sysdeps/ia64/nptl/pthreaddef.h (NEED_SEPARATE_REGISTER_STACK): Move
> 	to ...
> 	* sysdeps/ia64/stackinfo.h: ... here.
> ---
>  posix/stackmap.h                 | 115 +++++++++++++
>  sysdeps/ia64/nptl/pthreaddef.h   |   3 -
>  sysdeps/ia64/stackinfo.h         |   3 +
>  sysdeps/unix/sysv/linux/spawni.c | 277 +++++++++++++++++++------------
>  4 files changed, 285 insertions(+), 113 deletions(-)
>  create mode 100644 posix/stackmap.h
> 
> diff --git a/posix/stackmap.h b/posix/stackmap.h
> new file mode 100644
> index 0000000000..be500e378a
> --- /dev/null
> +++ b/posix/stackmap.h
> @@ -0,0 +1,115 @@
> +/* Functions to create stack mappings for helper processes.
> +   Copyright (C) 2019 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <http://www.gnu.org/licenses/>.  */
> +
> +#ifndef _STACKMAP_H
> +#define _STACKMAP_H
> +
> +#include <unistd.h>
> +#include <sys/mman.h>
> +#include <ldsodefs.h>
> +#include <stdbool.h>
> +
> +static inline int
> +stack_prot (void)
> +{
> +  return (PROT_READ | PROT_WRITE
> +	  | ((GL(dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
> +}
> +
> +static inline size_t
> +stack_guard_size (void)
> +{
> + return GLRO (dl_pagesize);
> +}
> +
> +/* Return a aligning mask based on system pagesize.  */
> +static inline size_t
> +stack_pagesize_m1_mask (void)
> +{
> +  size_t pagesize_m1 = __getpagesize () - 1;
> +  return ~pagesize_m1;
> +}
> +
> +/* Return the guard page position on memory segment MEM with total size SIZE
> +   and with a guard page of size GUARDIZE.  */
> +static inline void *
> +stack_guard_position (void *mem, size_t size, size_t guardsize)
> +{
> +#ifdef NEED_SEPARATE_REGISTER_STACK
> +  return mem + (((size - guardsize) / 2) & stack_pagesize_m1_mask ());
> +#elif _STACK_GROWS_DOWN
> +  return mem;
> +#elif _STACK_GROWS_UP
> +  return (void *) (((uintptr_t)(mem + size)- guardsize)
> +		   & stack_pagesize_m1_mask ());
> +#endif
> +}
> +
> +/* Setup the expected stack memory protection value (based on stack_prot)
> +   for the memory segment MEM with size SIZE based on the guard page
> +   GUARD with size GUARDSIZE.  The memory segment is expected to be allocated
> +   with PROT_NOTE.  */
> +static inline bool
> +stack_setup_prot (char *mem, size_t size, char *guard, size_t guardsize)
> +{
> +  const int prot = stack_prot ();
> +
> +  char *guardend = guard + guardsize;
> +#if _STACK_GROWS_DOWN && !defined(NEED_SEPARATE_REGISTER_STACK)
> +  /* As defined at guard_position, for architectures with downward stack
> +     the guard page is always at start of the allocated area.  */
> +  if (__mprotect (guardend, size - guardsize, prot) != 0)
> +    return false;
> +#else
> +  size_t mprots1 = (uintptr_t) guard - (uintptr_t) mem;
> +  if (__mprotect (mem, mprots1, prot) != 0)
> +    return false;
> +  size_t mprots2 = ((uintptr_t) mem + size) - (uintptr_t) guardend;
> +  if (__mprotect (guardend, mprots2, prot) != 0)
> +    return false;
> +#endif
> +  return true;
> +}
> +
> +/* Allocated a memory segment with size SIZE plus GUARSIZE with mmap and
> +   setup the expected protection for both a guard page and the stack
> +   itself.  */
> +static inline void *
> +stack_allocate (size_t size, size_t guardsize)
> +{
> +  const int prot = stack_prot ();
> +
> +  /* If a guard page is required, avoid committing memory by first
> +     allocate with PROT_NONE and then reserve with required permission
> +     excluding the guard page.  */
> +  void *mem = __mmap (NULL, size, (guardsize == 0) ? prot : PROT_NONE,
> +		      MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
> +  if (guardsize)
> +    {
> +      void *guard = stack_guard_position (mem, size, guardsize);
> +      if (!stack_setup_prot (mem, size, guard, guardsize))
> +	{
> +	  __munmap (mem, size);
> +	  return MAP_FAILED;
> +	}
> +    }
> +
> +  return mem;
> +}
> +
> +#endif /* _STACKMAP_H  */
> diff --git a/sysdeps/ia64/nptl/pthreaddef.h b/sysdeps/ia64/nptl/pthreaddef.h
> index bf52d5af62..11579f11b4 100644
> --- a/sysdeps/ia64/nptl/pthreaddef.h
> +++ b/sysdeps/ia64/nptl/pthreaddef.h
> @@ -18,9 +18,6 @@
>  /* Default stack size.  */
>  #define ARCH_STACK_DEFAULT_SIZE	(32 * 1024 * 1024)
>  
> -/* IA-64 uses a normal stack and a register stack.  */
> -#define NEED_SEPARATE_REGISTER_STACK
> -
>  /* Required stack pointer alignment at beginning.  */
>  #define STACK_ALIGN		16
>  
> diff --git a/sysdeps/ia64/stackinfo.h b/sysdeps/ia64/stackinfo.h
> index 6433a89945..d942426fcf 100644
> --- a/sysdeps/ia64/stackinfo.h
> +++ b/sysdeps/ia64/stackinfo.h
> @@ -30,4 +30,7 @@
>  /* Default to a non-executable stack.  */
>  #define DEFAULT_STACK_PERMS (PF_R|PF_W)
>  
> +/* IA-64 uses a normal stack and a register stack.  */
> +#define NEED_SEPARATE_REGISTER_STACK
> +
>  #endif	/* stackinfo.h */
> diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
> index ca7bf99825..0f7a8ca5df 100644
> --- a/sysdeps/unix/sysv/linux/spawni.c
> +++ b/sysdeps/unix/sysv/linux/spawni.c
> @@ -23,10 +23,11 @@
>  #include <not-cancel.h>
>  #include <local-setxid.h>
>  #include <shlib-compat.h>
> -#include <sigsetops.h>
> -#include <internal-signals.h>
> -#include <ldsodefs.h>
> +#include <nptl/pthreadP.h>
>  #include <ctype.h>
> +#include <dl-sysdep.h>
> +#include <libc-pointer-arith.h>
> +#include <stackmap.h>
>  #include "spawn_int.h"
>  
>  /* The Linux implementation of posix_spawn{p} uses the clone syscall directly
> @@ -70,7 +71,6 @@
>  # define STACK(__stack, __stack_size) (__stack + __stack_size)
>  #endif
>  
> -
>  struct posix_spawn_args
>  {
>    sigset_t oldmask;
> @@ -79,37 +79,11 @@ struct posix_spawn_args
>    const posix_spawn_file_actions_t *fa;
>    const posix_spawnattr_t *restrict attr;
>    char *const *argv;
> -  ptrdiff_t argc;
>    char *const *envp;
>    int xflags;
>    int err;
>  };
>  
> -/* Older version requires that shell script without shebang definition
> -   to be called explicitly using /bin/sh (_PATH_BSHELL).  */
> -static void
> -maybe_script_execute (struct posix_spawn_args *args)
> -{
> -  if (SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15)
> -      && (args->xflags & SPAWN_XFLAGS_TRY_SHELL) && errno == ENOEXEC)
> -    {
> -      char *const *argv = args->argv;
> -      ptrdiff_t argc = args->argc;
> -
> -      /* Construct an argument list for the shell.  */
> -      char *new_argv[argc + 2];
> -      new_argv[0] = (char *) _PATH_BSHELL;
> -      new_argv[1] = (char *) args->file;
> -      if (argc > 1)
> -	memcpy (new_argv + 2, argv + 1, argc * sizeof (char *));
> -      else
> -	new_argv[2] = NULL;
> -
> -      /* Execute the shell.  */
> -      args->exec (new_argv[0], new_argv, args->envp);
> -    }
> -}
> -
>  /* Close all file descriptor up to FROM by interacting /proc/self/fd.  */
>  static bool
>  spawn_closefrom (int from)
> @@ -152,7 +126,7 @@ spawn_closefrom (int from)
>     attributes, and file actions.  It run on its own stack (provided by the
>     posix_spawn call).  */
>  static int
> -__spawni_child (void *arguments)
> +spawni_child (void *arguments)
>  {
>    struct posix_spawn_args *args = arguments;
>    const posix_spawnattr_t *restrict attr = args->attr;
> @@ -330,11 +304,6 @@ __spawni_child (void *arguments)
>  
>    args->exec (args->file, args->argv, args->envp);
>  
> -  /* This is compatibility function required to enable posix_spawn run
> -     script without shebang definition for older posix_spawn versions
> -     (2.15).  */
> -  maybe_script_execute (args);
> -
>  fail:
>    /* errno should have an appropriate non-zero value; otherwise,
>       there's a bug in glibc or the kernel.  For lack of an error code
> @@ -345,71 +314,12 @@ fail:
>    _exit (SPAWN_ERROR);
>  }
>  
> -/* Spawn a new process executing PATH with the attributes describes in *ATTRP.
> -   Before running the process perform the actions described in FILE-ACTIONS. */
>  static int
> -__spawnix (pid_t * pid, const char *file,
> -	   const posix_spawn_file_actions_t * file_actions,
> -	   const posix_spawnattr_t * attrp, char *const argv[],
> -	   char *const envp[], int xflags,
> -	   int (*exec) (const char *, char *const *, char *const *))
> +spawni_clone (struct posix_spawn_args *args, void *stack, size_t stack_size,
> +	      pid_t *pid)
>  {
> -  pid_t new_pid;
> -  struct posix_spawn_args args;
>    int ec;
> -
> -  /* 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.  */
> -  ptrdiff_t argc = 0;
> -  /* Linux allows at most max (0x7FFFFFFF, 1/4 stack size) arguments
> -     to be used in a execve call.  We limit to INT_MAX minus one due the
> -     compatiblity code that may execute a shell script (maybe_script_execute)
> -     where it will construct another argument list with an additional
> -     argument.  */
> -  ptrdiff_t limit = INT_MAX - 1;
> -  while (argv[argc++] != NULL)
> -    if (argc == limit)
> -      {
> -	errno = E2BIG;
> -	return errno;
> -      }
> -
> -  int prot = (PROT_READ | PROT_WRITE
> -	     | ((GL (dl_stack_flags) & PF_X) ? PROT_EXEC : 0));
> -
> -  size_t argv_size = (argc * sizeof (void *));
> -  /* We need at least a few pages in case the compiler's stack checking is
> -     enabled.  In some configs, it is known to use at least 24KiB.  We use
> -     32KiB to be "safe" from anything the compiler might do.  Besides, the
> -     extra pages won't actually be allocated unless they get used.
> -     It also acts the slack for spawn_closefrom (including MIPS64 getdents64
> -     where it might use about 1k extra stack space.  */
> -  argv_size += (32 * 1024);
> -  size_t stack_size = ALIGN_UP (argv_size, GLRO(dl_pagesize));
> -  void *stack = __mmap (NULL, stack_size, prot,
> -			MAP_PRIVATE | MAP_ANONYMOUS | MAP_STACK, -1, 0);
> -  if (__glibc_unlikely (stack == MAP_FAILED))
> -    return errno;
> -
> -  /* Disable asynchronous cancellation.  */
> -  int state;
> -  __libc_ptf_call (__pthread_setcancelstate,
> -                   (PTHREAD_CANCEL_DISABLE, &state), 0);
> -
> -  /* Child must set args.err to something non-negative - we rely on
> -     the parent and child sharing VM.  */
> -  args.err = 0;
> -  args.file = file;
> -  args.exec = exec;
> -  args.fa = file_actions;
> -  args.attr = attrp ? attrp : &(const posix_spawnattr_t) { 0 };
> -  args.argv = argv;
> -  args.argc = argc;
> -  args.envp = envp;
> -  args.xflags = xflags;
> -
> -  __libc_signal_block_all (&args.oldmask);
> +  pid_t new_pid;
>  
>    /* 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
> @@ -419,8 +329,8 @@ __spawnix (pid_t * pid, const char *file,
>       need for CLONE_SETTLS.  Although parent and child share the same TLS
>       namespace, there will be no concurrent access for TLS variables (errno
>       for instance).  */
> -  new_pid = CLONE (__spawni_child, STACK (stack, stack_size), stack_size,
> -		   CLONE_VM | CLONE_VFORK | SIGCHLD, &args);
> +  new_pid = CLONE (spawni_child, STACK (stack, stack_size), stack_size,
> +		   CLONE_VM | CLONE_VFORK | SIGCHLD, args);
>  
>    /* It needs to collect the case where the auxiliary process was created
>       but failed to execute the file (due either any preparation step or
> @@ -433,7 +343,7 @@ __spawnix (pid_t * pid, const char *file,
>  	 only in case of failure, so in case of premature termination
>  	 due a signal args.err will remain zeroed and it will be up to
>  	 caller to actually collect it.  */
> -      ec = args.err;
> +      ec = args->err;
>        if (ec > 0)
>  	/* There still an unlikely case where the child is cancelled after
>  	   setting args.err, due to a positive error value.  Also there is
> @@ -446,14 +356,139 @@ __spawnix (pid_t * pid, const char *file,
>    else
>      ec = -new_pid;
>  
> -  __munmap (stack, stack_size);
> -
>    if ((ec == 0) && (pid != NULL))
>      *pid = new_pid;
>  
> -  __libc_signal_restore_set (&args.oldmask);
> +  return ec;
> +}
>  
> -  __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
> +#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15)
> +/* This is compatibility function required to enable posix_spawn run
> +   script without shebang definition for older posix_spawn versions
> +   (2.15).  */
> +static int
> +execve_compat (const char *filename, char *const argv[], char *const envp[])
> +{
> +  __execve (filename, argv, envp);
> +
> +  if (errno == ENOEXEC)
> +    {
> +      char *const *cargv = argv;
> +      ptrdiff_t argc = 0;
> +      while (cargv[argc++] != NULL);
> +
> +      /* Construct an argument list for the shell.  */
> +      char *new_argv[argc + 2];
> +      new_argv[0] = (char *) _PATH_BSHELL;
> +      new_argv[1] = (char *) filename;
> +      if (argc > 1)
> +	memcpy (new_argv + 2, argv + 1, argc * sizeof (char *));
> +      else
> +	new_argv[2] = NULL;
> +
> +      /* Execute the shell.  */
> +      __execve (new_argv[0], new_argv, envp);
> +    }
> +
> +  return -1;
> +}
> +
> +/* Allocates a stack using mmap to call clone.  The stack size is based on
> +   number of arguments since it would be used on compat mode which may call
> +   execvpe/execve_compat.  */
> +static int
> +spawnix_compat (struct posix_spawn_args *args, pid_t *pid)
> +{
> +  char *const *argv = args->argv;
> +
> +  /* 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.  */
> +  ptrdiff_t argc = 0;
> +  /* Linux allows at most max (0x7FFFFFFF, 1/4 stack size) arguments
> +     to be used in a execve call.  We limit to INT_MAX minus one due the
> +     compatiblity code that may execute a shell script (maybe_script_execute)
> +     where it will construct another argument list with an additional
> +     argument.  */
> +  ptrdiff_t limit = INT_MAX - 1;
> +  while (argv[argc++] != NULL)
> +    if (argc == limit)
> +      {
> +	errno = E2BIG;
> +	return errno;
> +      }
> +
> +  size_t argv_size = (argc * sizeof (void *));
> +  /* We need at least a few pages in case the compiler's stack checking is
> +     enabled.  In some configs, it is known to use at least 24KiB.  We use
> +     32KiB to be "safe" from anything the compiler might do.  Besides, the
> +     extra pages won't actually be allocated unless they get used.
> +     It also acts the slack for spawn_closefrom (including MIPS64 getdents64
> +     where it might use about 1k extra stack space.  */
> +  argv_size += (32 * 1024);
> +
> +  /* Allocate a stack with an extra guard page.  */
> +  size_t guard_size = stack_guard_size ();
> +  size_t stack_size = guard_size + ALIGN_UP (argv_size, __getpagesize ());
> +  void *stack = stack_allocate (stack_size, guard_size);
> +  if (__glibc_unlikely (stack == MAP_FAILED))
> +    return errno;
> +
> +  int ec = spawni_clone (args, stack, stack_size, pid);
> +
> +  __munmap (stack, stack_size);
> +
> +  return ec;
> +}
> +#endif
> +
> +/* For SPAWN_XFLAGS_TRY_SHELL we need to execute a script even without
> +   a shebang.  To accomplish it we pass as callback to spawni_child
> +   __execvpe (which call maybe_script_execute for such case) or
> +   execve_compat (which mimics the semantic using execve).  */
> +static int
> +spawn_process (struct posix_spawn_args *args, pid_t *pid)
> +{
> +  int ec;
> +
> +#if SHLIB_COMPAT (libc, GLIBC_2_2, GLIBC_2_15)
> +  if (args->xflags & SPAWN_XFLAGS_TRY_SHELL)
> +    {
> +      args->exec = args->xflags & SPAWN_XFLAGS_USE_PATH
> +		   ? __execvpe  : execve_compat;
> +      ec = spawnix_compat (args, pid);
> +    }
> +  else
> +#endif
> +    {
> +      args->exec = args->xflags & SPAWN_XFLAGS_USE_PATH
> +		   ? __execvpex : __execve;
> +
> +      /* spawni_clone stack usage need to take in consideration spawni_child
> +	 stack usage and subsequent functions called:
> +
> +	 - sigprocmask: might allocate an extra sigset_t (128 bytes).
> +	 - __libc_sigaction: allocate a struct kernel_sigaction (144 bytes on
> +	   64-bit, 136 on 32-bit).
> +	 - __sched_setparam, __sched_setscheduler, __setsig, __setpgid,
> +	   local_seteuid, local_setegid, __close_nocancel, __getrlimit64,
> +	   __close_nocancel, __open_nocancel, __dup2, __chdir, __fchdir:
> +	   and direct syscall.
> +	 - __fcntl: wrapper only uses local variables.
> +	 - spawn_closefrom: uses up to 1024 bytes as local buffer
> +	   - __direntries_read
> +	     - __getdents64: MIPS64 uses up to buffer size used, 1024 in this
> +	       specific usage.
> +	   - __direntries_next: local variables.
> +	   - __close_nocancel: direct syscall.
> +         - execvpe allocates at least (NAME_MAX + 1) + PATH_MAX to create the
> +	   combination of PATH entry and program name (1024 + 255 + 1).
> +
> +	 It allocates 2048 plus some stack for automatic variables and function
> +	 calls.  */
> +      char stack[2560];
> +      ec = spawni_clone (args, stack, sizeof stack, pid);
> +    }
>  
>    return ec;
>  }
> @@ -462,12 +497,34 @@ __spawnix (pid_t * pid, const char *file,
>     Before running the process perform the actions described in FILE-ACTIONS. */
>  int
>  __spawni (pid_t * pid, const char *file,
> -	  const posix_spawn_file_actions_t * acts,
> +	  const posix_spawn_file_actions_t * file_actions,
>  	  const posix_spawnattr_t * attrp, char *const argv[],
>  	  char *const envp[], int xflags)
>  {
> -  /* It uses __execvpex to avoid run ENOEXEC in non compatibility mode (it
> -     will be handled by maybe_script_execute).  */
> -  return __spawnix (pid, file, acts, attrp, argv, envp, xflags,
> -		    xflags & SPAWN_XFLAGS_USE_PATH ? __execvpex :__execve);
> +  /* Child must set args.err to something non-negative - we rely on
> +     the parent and child sharing VM.  */
> +  struct posix_spawn_args args = {
> +    .err = 0,
> +    .file = file,
> +    .fa = file_actions,
> +    .attr = attrp ? attrp : &(const posix_spawnattr_t) { 0 },
> +    .argv = argv,
> +    .envp = envp,
> +    .xflags = xflags
> +  };
> +
> +  /* Disable asynchronous cancellation.  */
> +  int state;
> +  __libc_ptf_call (__pthread_setcancelstate,
> +                   (PTHREAD_CANCEL_DISABLE, &state), 0);
> +
> +  __libc_signal_block_all (&args.oldmask);
> +
> +  int ec = spawn_process (&args, pid);
> +
> +  __libc_signal_restore_set (&args.oldmask);
> +
> +  __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
> +
> +  return ec;
>  }
> 

  reply	other threads:[~2019-08-28 14:09 UTC|newest]

Thread overview: 59+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-07-31 18:31 [PATCH v2 1/5] mips: Do not malloc on getdents64 fallback Adhemerval Zanella
2019-07-31 18:31 ` [PATCH v2 2/5] posix: Add posix_spawn_file_actions_closefrom Adhemerval Zanella
2019-08-28 14:09   ` Adhemerval Zanella
2019-08-28 17:22     ` Joseph Myers
2019-08-28 21:03       ` Adhemerval Zanella
2019-07-31 18:31 ` [PATCH v2 3/5] posix: Optimize stack Linux posix_spawn Adhemerval Zanella
2019-08-28 14:09   ` Adhemerval Zanella [this message]
2019-10-07 17:50     ` Adhemerval Zanella
2019-07-31 18:31 ` [PATCH v2 5/5] posix: Use posix_spawn for wordexp Adhemerval Zanella
2019-08-28 14:10   ` Adhemerval Zanella
2019-10-07 17:51     ` Adhemerval Zanella
2019-10-07 19:33   ` Florian Weimer
2019-10-07 21:04     ` Carlos O'Donell
2019-10-08  9:58       ` Florian Weimer
2019-10-08 17:41     ` Adhemerval Zanella
2019-10-09  9:11       ` Florian Weimer
2019-10-09 12:18         ` Adhemerval Zanella
2019-07-31 18:31 ` [PATCH 4/5] linux: Optimize posix_spawn spurious sigaction calls Adhemerval Zanella
2019-08-28 14:09   ` Adhemerval Zanella
2019-08-29  8:38   ` Florian Weimer
2019-08-29 11:26     ` Adhemerval Zanella
2019-08-30 10:07       ` Florian Weimer
2019-08-30 13:05         ` Adhemerval Zanella
2019-09-02 13:14           ` Florian Weimer
2019-09-02 19:47             ` Adhemerval Zanella
2019-10-07 17:51               ` Adhemerval Zanella
2019-10-07 18:25                 ` Christian Brauner
2019-10-07 18:32                   ` Florian Weimer
2019-10-07 21:08                     ` Christian Brauner
2019-10-07 18:35                   ` Adhemerval Zanella
2019-10-07 18:40                     ` Florian Weimer
2019-10-07 19:20                       ` Adhemerval Zanella
2019-10-09  9:37                         ` Florian Weimer
2019-10-09 10:25                           ` Christian Brauner
2019-10-09 12:17                           ` Adhemerval Zanella
2019-10-09 19:16                             ` Florian Weimer
2019-10-07 21:00                     ` Joseph Myers
2019-10-07 18:41                 ` Florian Weimer
2019-08-28 14:09 ` [PATCH v2 1/5] mips: Do not malloc on getdents64 fallback Adhemerval Zanella
2019-08-28 14:35 ` Andreas Schwab
2019-08-28 17:01   ` Adhemerval Zanella
2019-08-28 14:42 ` Florian Weimer
2019-08-28 21:02   ` Adhemerval Zanella
2019-08-28 21:23     ` Florian Weimer
2019-08-29 11:04       ` Adhemerval Zanella
2019-08-30  9:53 ` Florian Weimer
2019-08-30 12:53   ` Adhemerval Zanella
2019-09-02 12:59     ` Florian Weimer
2019-09-02 17:38       ` Adhemerval Zanella
2019-10-07 17:49         ` Adhemerval Zanella
2019-10-07 18:29         ` Florian Weimer
2019-10-08 17:38           ` Adhemerval Zanella
2019-10-08 18:52             ` Florian Weimer
2019-10-08 19:52               ` Adhemerval Zanella
2019-10-08 19:59                 ` Florian Weimer
2019-10-09 13:02                   ` Adhemerval Zanella
2020-11-02 19:51             ` Joseph Myers
2020-11-02 22:10               ` Adhemerval Zanella
2020-11-03 10:27                 ` Florian Weimer

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=11104fa2-d420-e8eb-9fc6-bd5dbdfea042@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).