c5d972
commit 5fb7fc96350575c9adb1316833e48ca11553be49
c5d972
Author: Adhemerval Zanella <adhemerval.zanella@linaro.org>
c5d972
Date:   Wed Oct 24 16:29:38 2018 -0300
c5d972
c5d972
    posix: Use posix_spawn on system
c5d972
    
c5d972
    This patch uses posix_spawn on system implementation.  On Linux this has
c5d972
    the advantage of much lower memory consumption (usually 32 Kb minimum for
c5d972
    the mmap stack area).
c5d972
    
c5d972
    Although POSIX does not require, glibc system implementation aims to be
c5d972
    thread and cancellation safe.  The cancellation code is moved to generic
c5d972
    implementation and enabled iff SIGCANCEL is defined (similar on how the
c5d972
    cancellation handler is enabled on nptl-init.c).
c5d972
    
c5d972
    Checked on x86_64-linux-gnu, i686-linux-gnu, aarch64-linux-gnu,
c5d972
    arm-linux-gnueabihf, and powerpc64le-linux-gnu.
c5d972
    
c5d972
            * sysdeps/unix/sysv/linux/spawni.c (__spawni_child): Use
c5d972
            __sigismember instead of sigismember.
c5d972
            * sysdeps/posix/system.c [SIGCANCEL] (cancel_handler_args,
c5d972
            cancel_handler): New definitions.
c5d972
            (CLEANUP_HANDLER, CLEANUP_RESET): Likewise.
c5d972
            (DO_LOCK, DO_UNLOCK, INIT_LOCK, ADD_REF, SUB_REF): Remove.
c5d972
            (do_system): Use posix_spawn instead of fork and execl and remove
c5d972
            reentracy code.
c5d972
            * sysdeps/generic/not-errno.h (__kill_noerrno): New prototype.
c5d972
            * sysdeps/unix/sysv/linux/not-errno.h (__kill_noerrno): Likewise.
c5d972
            * sysdeps/unix/sysv/linux/ia64/system.c: Remove file.
c5d972
            * sysdeps/unix/sysv/linux/s390/system.c: Likewise.
c5d972
            * sysdeps/unix/sysv/linux/sparc/system.c: Likewise.
c5d972
            * sysdeps/unix/sysv/linux/system.c: Likewise.
c5d972
c5d972
diff --git a/sysdeps/generic/not-errno.h b/sysdeps/generic/not-errno.h
c5d972
index 93617a3266fd4aad..0fd66b5c5ed82315 100644
c5d972
--- a/sysdeps/generic/not-errno.h
c5d972
+++ b/sysdeps/generic/not-errno.h
c5d972
@@ -17,3 +17,5 @@
c5d972
    <http://www.gnu.org/licenses/>.  */
c5d972
 
c5d972
 extern __typeof (__access) __access_noerrno attribute_hidden;
c5d972
+
c5d972
+extern __typeof (__kill) __kill_noerrno attribute_hidden;
c5d972
diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c
c5d972
index d7594436ed59906f..8a51a6b9919ec39b 100644
c5d972
--- a/sysdeps/posix/system.c
c5d972
+++ b/sysdeps/posix/system.c
c5d972
@@ -17,20 +17,36 @@
c5d972
 
c5d972
 #include <errno.h>
c5d972
 #include <signal.h>
c5d972
-#include <stddef.h>
c5d972
 #include <stdlib.h>
c5d972
 #include <unistd.h>
c5d972
+#include <sigsetops.h>
c5d972
+#include <spawn.h>
c5d972
+#include <pthread.h>
c5d972
 #include <sys/types.h>
c5d972
 #include <sys/wait.h>
c5d972
-#include <libc-lock.h>
c5d972
-#include <sysdep-cancel.h>
c5d972
-#include <sigsetops.h>
c5d972
+#include <stdio.h>
c5d972
 
c5d972
+#include <libc-lock.h>
c5d972
+#include <not-errno.h>
c5d972
+#include <not-cancel.h>
c5d972
+#include <internal-signals.h>
c5d972
 
c5d972
 #define	SHELL_PATH	"/bin/sh"	/* Path of the shell.  */
c5d972
 #define	SHELL_NAME	"sh"		/* Name to give it.  */
c5d972
 
c5d972
 
c5d972
+/* This system implementation aims to be thread-safe, which requires to
c5d972
+   restore the signal dispositions for SIGINT and SIGQUIT correctly and to
c5d972
+   deal with cancellation by terminating the child process.
c5d972
+
c5d972
+   The signal disposition restoration on the single-thread case is
c5d972
+   straighfoward.  For multithreaded case, a reference-counter with a lock
c5d972
+   is used, so the first thread will set the SIGINT/SIGQUIT dispositions and
c5d972
+   last thread will restore them.
c5d972
+
c5d972
+   Cancellation handling is done with thread cancellation clean-up handlers
c5d972
+   on waitpid call.  */
c5d972
+
c5d972
 #ifdef _LIBC_REENTRANT
c5d972
 static struct sigaction intr, quit;
c5d972
 static int sa_refcntr;
c5d972
@@ -50,17 +66,45 @@ __libc_lock_define_initialized (static, lock);
c5d972
 #endif
c5d972
 
c5d972
 
c5d972
+#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
c5d972
+struct cancel_handler_args
c5d972
+{
c5d972
+  struct sigaction *quit;
c5d972
+  struct sigaction *intr;
c5d972
+  pid_t pid;
c5d972
+};
c5d972
+
c5d972
+static void
c5d972
+cancel_handler (void *arg)
c5d972
+{
c5d972
+  struct cancel_handler_args *args = (struct cancel_handler_args *) (arg);
c5d972
+
c5d972
+  __kill_noerrno (args->pid, SIGKILL);
c5d972
+
c5d972
+  TEMP_FAILURE_RETRY (__waitpid_nocancel (args->pid, NULL, 0));
c5d972
+
c5d972
+  DO_LOCK ();
c5d972
+  if (SUB_REF () == 0)
c5d972
+    {
c5d972
+      __sigaction (SIGQUIT, args->quit, NULL);
c5d972
+      __sigaction (SIGINT, args->intr, NULL);
c5d972
+    }
c5d972
+  DO_UNLOCK ();
c5d972
+}
c5d972
+#endif
c5d972
+
c5d972
 /* Execute LINE as a shell command, returning its status.  */
c5d972
 static int
c5d972
 do_system (const char *line)
c5d972
 {
c5d972
-  int status, save;
c5d972
+  int status;
c5d972
   pid_t pid;
c5d972
   struct sigaction sa;
c5d972
 #ifndef _LIBC_REENTRANT
c5d972
   struct sigaction intr, quit;
c5d972
 #endif
c5d972
   sigset_t omask;
c5d972
+  sigset_t reset;
c5d972
 
c5d972
   sa.sa_handler = SIG_IGN;
c5d972
   sa.sa_flags = 0;
c5d972
@@ -69,105 +113,72 @@ do_system (const char *line)
c5d972
   DO_LOCK ();
c5d972
   if (ADD_REF () == 0)
c5d972
     {
c5d972
-      if (__sigaction (SIGINT, &sa, &intr) < 0)
c5d972
-	{
c5d972
-	  (void) SUB_REF ();
c5d972
-	  goto out;
c5d972
-	}
c5d972
-      if (__sigaction (SIGQUIT, &sa, &quit) < 0)
c5d972
-	{
c5d972
-	  save = errno;
c5d972
-	  (void) SUB_REF ();
c5d972
-	  goto out_restore_sigint;
c5d972
-	}
c5d972
+      /* sigaction can not fail with SIGINT/SIGQUIT used with SIG_IGN.  */
c5d972
+      __sigaction (SIGINT, &sa, &intr;;
c5d972
+      __sigaction (SIGQUIT, &sa, &quit);
c5d972
     }
c5d972
   DO_UNLOCK ();
c5d972
 
c5d972
-  /* We reuse the bitmap in the 'sa' structure.  */
c5d972
   __sigaddset (&sa.sa_mask, SIGCHLD);
c5d972
-  save = errno;
c5d972
-  if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
c5d972
+  /* sigprocmask can not fail with SIG_BLOCK used with valid input
c5d972
+     arguments.  */
c5d972
+  __sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask);
c5d972
+
c5d972
+  __sigemptyset (&reset);
c5d972
+  if (intr.sa_handler != SIG_IGN)
c5d972
+    __sigaddset(&reset, SIGINT);
c5d972
+  if (quit.sa_handler != SIG_IGN)
c5d972
+    __sigaddset(&reset, SIGQUIT);
c5d972
+
c5d972
+  posix_spawnattr_t spawn_attr;
c5d972
+  /* None of the posix_spawnattr_* function returns an error, including
c5d972
+     posix_spawnattr_setflags for the follow specific usage (using valid
c5d972
+     flags).  */
c5d972
+  __posix_spawnattr_init (&spawn_attr);
c5d972
+  __posix_spawnattr_setsigmask (&spawn_attr, &omask);
c5d972
+  __posix_spawnattr_setsigdefault (&spawn_attr, &reset);
c5d972
+  __posix_spawnattr_setflags (&spawn_attr,
c5d972
+			      POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK);
c5d972
+
c5d972
+  status = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr,
c5d972
+			  (char *const[]){ (char*) SHELL_NAME,
c5d972
+					   (char*) "-c",
c5d972
+					   (char *) line, NULL },
c5d972
+			  __environ);
c5d972
+  __posix_spawnattr_destroy (&spawn_attr);
c5d972
+
c5d972
+  if (status == 0)
c5d972
     {
c5d972
-#ifndef _LIBC
c5d972
-      if (errno == ENOSYS)
c5d972
-	__set_errno (save);
c5d972
-      else
c5d972
-#endif
c5d972
-	{
c5d972
-	  DO_LOCK ();
c5d972
-	  if (SUB_REF () == 0)
c5d972
-	    {
c5d972
-	      save = errno;
c5d972
-	      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
c5d972
-	    out_restore_sigint:
c5d972
-	      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
c5d972
-	      __set_errno (save);
c5d972
-	    }
c5d972
-	out:
c5d972
-	  DO_UNLOCK ();
c5d972
-	  return -1;
c5d972
-	}
c5d972
-    }
c5d972
-
c5d972
-#ifdef CLEANUP_HANDLER
c5d972
-  CLEANUP_HANDLER;
c5d972
-#endif
c5d972
-
c5d972
-#ifdef FORK
c5d972
-  pid = FORK ();
c5d972
-#else
c5d972
-  pid = __fork ();
c5d972
+      /* Cancellation results in cleanup handlers running as exceptions in
c5d972
+	 the block where they were installed, so it is safe to reference
c5d972
+	 stack variable allocate in the broader scope.  */
c5d972
+#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
c5d972
+      struct cancel_handler_args cancel_args =
c5d972
+      {
c5d972
+	.quit = &quit,
c5d972
+	.intr = &intr,
c5d972
+	.pid = pid
c5d972
+      };
c5d972
+      __libc_cleanup_region_start (1, cancel_handler, &cancel_args);
c5d972
 #endif
c5d972
-  if (pid == (pid_t) 0)
c5d972
-    {
c5d972
-      /* Child side.  */
c5d972
-      const char *new_argv[4];
c5d972
-      new_argv[0] = SHELL_NAME;
c5d972
-      new_argv[1] = "-c";
c5d972
-      new_argv[2] = line;
c5d972
-      new_argv[3] = NULL;
c5d972
-
c5d972
-      /* Restore the signals.  */
c5d972
-      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
c5d972
-      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
c5d972
-      (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
c5d972
-      INIT_LOCK ();
c5d972
-
c5d972
-      /* Exec the shell.  */
c5d972
-      (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ);
c5d972
-      _exit (127);
c5d972
-    }
c5d972
-  else if (pid < (pid_t) 0)
c5d972
-    /* The fork failed.  */
c5d972
-    status = -1;
c5d972
-  else
c5d972
-    /* Parent side.  */
c5d972
-    {
c5d972
       /* Note the system() is a cancellation point.  But since we call
c5d972
 	 waitpid() which itself is a cancellation point we do not
c5d972
 	 have to do anything here.  */
c5d972
       if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid)
c5d972
 	status = -1;
c5d972
-    }
c5d972
-
c5d972
-#ifdef CLEANUP_HANDLER
c5d972
-  CLEANUP_RESET;
c5d972
+#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
c5d972
+      __libc_cleanup_region_end (0);
c5d972
 #endif
c5d972
+    }
c5d972
 
c5d972
-  save = errno;
c5d972
   DO_LOCK ();
c5d972
-  if ((SUB_REF () == 0
c5d972
-       && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
c5d972
-	   | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
c5d972
-      || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
c5d972
+  if (SUB_REF () == 0)
c5d972
     {
c5d972
-#ifndef _LIBC
c5d972
-      /* glibc cannot be used on systems without waitpid.  */
c5d972
-      if (errno == ENOSYS)
c5d972
-	__set_errno (save);
c5d972
-      else
c5d972
-#endif
c5d972
-	status = -1;
c5d972
+      /* sigaction can not fail with SIGINT/SIGQUIT used with old
c5d972
+	 disposition.  Same applies for sigprocmask.  */
c5d972
+      __sigaction (SIGINT, &intr, NULL);
c5d972
+      __sigaction (SIGQUIT, &quit, NULL);
c5d972
+      __sigprocmask (SIG_SETMASK, &omask, NULL);
c5d972
     }
c5d972
   DO_UNLOCK ();
c5d972
 
c5d972
diff --git a/sysdeps/unix/sysv/linux/ia64/system.c b/sysdeps/unix/sysv/linux/ia64/system.c
c5d972
deleted file mode 100644
c5d972
index d09fefefe64753ab..0000000000000000
c5d972
--- a/sysdeps/unix/sysv/linux/ia64/system.c
c5d972
+++ /dev/null
c5d972
@@ -1,30 +0,0 @@
c5d972
-/* Copyright (C) 2002-2018 Free Software Foundation, Inc.
c5d972
-   This file is part of the GNU C Library.
c5d972
-
c5d972
-   The GNU C Library is free software; you can redistribute it and/or
c5d972
-   modify it under the terms of the GNU Lesser General Public
c5d972
-   License as published by the Free Software Foundation; either
c5d972
-   version 2.1 of the License, or (at your option) any later version.
c5d972
-
c5d972
-   The GNU C Library is distributed in the hope that it will be useful,
c5d972
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
c5d972
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
c5d972
-   Lesser General Public License for more details.
c5d972
-
c5d972
-   You should have received a copy of the GNU Lesser General Public
c5d972
-   License along with the GNU C Library; if not, see
c5d972
-   <http://www.gnu.org/licenses/>.  */
c5d972
-
c5d972
-/* We have to and actually can handle cancelable system().  The big
c5d972
-   problem: we have to kill the child process if necessary.  To do
c5d972
-   this a cleanup handler has to be registered and is has to be able
c5d972
-   to find the PID of the child.  The main problem is to reliable have
c5d972
-   the PID when needed.  It is not necessary for the parent thread to
c5d972
-   return.  It might still be in the kernel when the cancellation
c5d972
-   request comes.  Therefore we have to use the clone() calls ability
c5d972
-   to have the kernel write the PID into the user-level variable.  */
c5d972
-#define FORK() \
c5d972
-  INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
c5d972
-		  &pid, NULL, NULL)
c5d972
-
c5d972
-#include <sysdeps/unix/sysv/linux/system.c>
c5d972
diff --git a/sysdeps/unix/sysv/linux/not-errno.h b/sysdeps/unix/sysv/linux/not-errno.h
c5d972
index 106ba5c72e3d7dda..b2f72cfb3d412c56 100644
c5d972
--- a/sysdeps/unix/sysv/linux/not-errno.h
c5d972
+++ b/sysdeps/unix/sysv/linux/not-errno.h
c5d972
@@ -16,6 +16,9 @@
c5d972
    License along with the GNU C Library; if not, see
c5d972
    <http://www.gnu.org/licenses/>.  */
c5d972
 
c5d972
+#include <sysdep.h>
c5d972
+#include <fcntl.h>
c5d972
+
c5d972
 /* This function is used on maybe_enable_malloc_check (elf/dl-tunables.c)
c5d972
    and to avoid having to build/use multiple versions if stack protection
c5d972
    in enabled it is defined as inline.  */
c5d972
@@ -33,3 +36,14 @@ __access_noerrno (const char *pathname, int mode)
c5d972
     return INTERNAL_SYSCALL_ERRNO (res, err);
c5d972
   return 0;
c5d972
 }
c5d972
+
c5d972
+static inline int
c5d972
+__kill_noerrno (pid_t pid, int sig)
c5d972
+{
c5d972
+  int res;
c5d972
+  INTERNAL_SYSCALL_DECL (err);
c5d972
+  res = INTERNAL_SYSCALL_CALL (kill, err, pid, sig);
c5d972
+  if (INTERNAL_SYSCALL_ERROR_P (res, err))
c5d972
+    return INTERNAL_SYSCALL_ERRNO (res, err);
c5d972
+  return 0;
c5d972
+}
c5d972
diff --git a/sysdeps/unix/sysv/linux/s390/system.c b/sysdeps/unix/sysv/linux/s390/system.c
c5d972
deleted file mode 100644
c5d972
index d8ef46133419dd89..0000000000000000
c5d972
--- a/sysdeps/unix/sysv/linux/s390/system.c
c5d972
+++ /dev/null
c5d972
@@ -1,29 +0,0 @@
c5d972
-/* Copyright (C) 2003-2018 Free Software Foundation, Inc.
c5d972
-   This file is part of the GNU C Library.
c5d972
-
c5d972
-   The GNU C Library is free software; you can redistribute it and/or
c5d972
-   modify it under the terms of the GNU Lesser General Public
c5d972
-   License as published by the Free Software Foundation; either
c5d972
-   version 2.1 of the License, or (at your option) any later version.
c5d972
-
c5d972
-   The GNU C Library is distributed in the hope that it will be useful,
c5d972
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
c5d972
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
c5d972
-   Lesser General Public License for more details.
c5d972
-
c5d972
-   You should have received a copy of the GNU Lesser General Public
c5d972
-   License along with the GNU C Library; if not, see
c5d972
-   <http://www.gnu.org/licenses/>.  */
c5d972
-
c5d972
-/* We have to and actually can handle cancelable system().  The big
c5d972
-   problem: we have to kill the child process if necessary.  To do
c5d972
-   this a cleanup handler has to be registered and is has to be able
c5d972
-   to find the PID of the child.  The main problem is to reliable have
c5d972
-   the PID when needed.  It is not necessary for the parent thread to
c5d972
-   return.  It might still be in the kernel when the cancellation
c5d972
-   request comes.  Therefore we have to use the clone() calls ability
c5d972
-   to have the kernel write the PID into the user-level variable.  */
c5d972
-#define FORK() \
c5d972
-  INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid)
c5d972
-
c5d972
-#include "../system.c"
c5d972
diff --git a/sysdeps/unix/sysv/linux/sparc/system.c b/sysdeps/unix/sysv/linux/sparc/system.c
c5d972
deleted file mode 100644
c5d972
index 1f65c83399f920d6..0000000000000000
c5d972
--- a/sysdeps/unix/sysv/linux/sparc/system.c
c5d972
+++ /dev/null
c5d972
@@ -1,29 +0,0 @@
c5d972
-/* Copyright (C) 2003-2018 Free Software Foundation, Inc.
c5d972
-   This file is part of the GNU C Library.
c5d972
-
c5d972
-   The GNU C Library is free software; you can redistribute it and/or
c5d972
-   modify it under the terms of the GNU Lesser General Public
c5d972
-   License as published by the Free Software Foundation; either
c5d972
-   version 2.1 of the License, or (at your option) any later version.
c5d972
-
c5d972
-   The GNU C Library is distributed in the hope that it will be useful,
c5d972
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
c5d972
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
c5d972
-   Lesser General Public License for more details.
c5d972
-
c5d972
-   You should have received a copy of the GNU Lesser General Public
c5d972
-   License along with the GNU C Library; if not, see
c5d972
-   <http://www.gnu.org/licenses/>.  */
c5d972
-
c5d972
-/* We have to and actually can handle cancelable system().  The big
c5d972
-   problem: we have to kill the child process if necessary.  To do
c5d972
-   this a cleanup handler has to be registered and is has to be able
c5d972
-   to find the PID of the child.  The main problem is to reliable have
c5d972
-   the PID when needed.  It is not necessary for the parent thread to
c5d972
-   return.  It might still be in the kernel when the cancellation
c5d972
-   request comes.  Therefore we have to use the clone() calls ability
c5d972
-   to have the kernel write the PID into the user-level variable.  */
c5d972
-#define FORK() \
c5d972
-  INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
c5d972
-
c5d972
-#include "../system.c"
c5d972
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
c5d972
index 85239cedbf2a5ab5..6a8bd2ed2e1c29b7 100644
c5d972
--- a/sysdeps/unix/sysv/linux/spawni.c
c5d972
+++ b/sysdeps/unix/sysv/linux/spawni.c
c5d972
@@ -138,11 +138,11 @@ __spawni_child (void *arguments)
c5d972
   for (int sig = 1; sig < _NSIG; ++sig)
c5d972
     {
c5d972
       if ((attr->__flags & POSIX_SPAWN_SETSIGDEF)
c5d972
-	  && sigismember (&attr->__sd, sig))
c5d972
+	  && __sigismember (&attr->__sd, sig))
c5d972
 	{
c5d972
 	  sa.sa_handler = SIG_DFL;
c5d972
 	}
c5d972
-      else if (sigismember (&hset, sig))
c5d972
+      else if (__sigismember (&hset, sig))
c5d972
 	{
c5d972
 	  if (__is_internal_signal (sig))
c5d972
 	    sa.sa_handler = SIG_IGN;
c5d972
diff --git a/sysdeps/unix/sysv/linux/system.c b/sysdeps/unix/sysv/linux/system.c
c5d972
deleted file mode 100644
c5d972
index 7cc68a1528ee8f99..0000000000000000
c5d972
--- a/sysdeps/unix/sysv/linux/system.c
c5d972
+++ /dev/null
c5d972
@@ -1,76 +0,0 @@
c5d972
-/* Copyright (C) 2002-2018 Free Software Foundation, Inc.
c5d972
-   This file is part of the GNU C Library.
c5d972
-
c5d972
-   The GNU C Library is free software; you can redistribute it and/or
c5d972
-   modify it under the terms of the GNU Lesser General Public
c5d972
-   License as published by the Free Software Foundation; either
c5d972
-   version 2.1 of the License, or (at your option) any later version.
c5d972
-
c5d972
-   The GNU C Library is distributed in the hope that it will be useful,
c5d972
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
c5d972
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
c5d972
-   Lesser General Public License for more details.
c5d972
-
c5d972
-   You should have received a copy of the GNU Lesser General Public
c5d972
-   License along with the GNU C Library; if not, see
c5d972
-   <http://www.gnu.org/licenses/>.  */
c5d972
-
c5d972
-#include <sched.h>
c5d972
-#include <signal.h>
c5d972
-#include <string.h>	/* For the real memset prototype.  */
c5d972
-#include <sysdep.h>
c5d972
-#include <unistd.h>
c5d972
-#include <sys/wait.h>
c5d972
-#include <libc-lock.h>
c5d972
-
c5d972
-/* We have to and actually can handle cancelable system().  The big
c5d972
-   problem: we have to kill the child process if necessary.  To do
c5d972
-   this a cleanup handler has to be registered and is has to be able
c5d972
-   to find the PID of the child.  The main problem is to reliable have
c5d972
-   the PID when needed.  It is not necessary for the parent thread to
c5d972
-   return.  It might still be in the kernel when the cancellation
c5d972
-   request comes.  Therefore we have to use the clone() calls ability
c5d972
-   to have the kernel write the PID into the user-level variable.  */
c5d972
-#ifndef FORK
c5d972
-# define FORK() \
c5d972
-  INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
c5d972
-#endif
c5d972
-
c5d972
-#ifdef _LIBC_REENTRANT
c5d972
-static void cancel_handler (void *arg);
c5d972
-
c5d972
-# define CLEANUP_HANDLER \
c5d972
-  __libc_cleanup_region_start (1, cancel_handler, &pid)
c5d972
-
c5d972
-# define CLEANUP_RESET \
c5d972
-  __libc_cleanup_region_end (0)
c5d972
-#endif
c5d972
-
c5d972
-
c5d972
-/* Linux has waitpid(), so override the generic unix version.  */
c5d972
-#include <sysdeps/posix/system.c>
c5d972
-
c5d972
-
c5d972
-#ifdef _LIBC_REENTRANT
c5d972
-/* The cancellation handler.  */
c5d972
-static void
c5d972
-cancel_handler (void *arg)
c5d972
-{
c5d972
-  pid_t child = *(pid_t *) arg;
c5d972
-
c5d972
-  INTERNAL_SYSCALL_DECL (err);
c5d972
-  INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
c5d972
-
c5d972
-  TEMP_FAILURE_RETRY (__waitpid (child, NULL, 0));
c5d972
-
c5d972
-  DO_LOCK ();
c5d972
-
c5d972
-  if (SUB_REF () == 0)
c5d972
-    {
c5d972
-      (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
c5d972
-      (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
c5d972
-    }
c5d972
-
c5d972
-  DO_UNLOCK ();
c5d972
-}
c5d972
-#endif