aboutsummaryrefslogtreecommitdiff
path: root/support/support_subprocess.c
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2019-04-12 17:39:53 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2019-04-17 11:35:59 -0300
commit0e169691290a6d2187a4ff41495fc5678cbfdcdc (patch)
tree22a279438012ed4e10b4477fe8a9d0a03a2630e6 /support/support_subprocess.c
parentbae8cf0e930d82133e96c4e2547548ed53938de1 (diff)
downloadglibc-0e169691290a6d2187a4ff41495fc5678cbfdcdc.tar.xz
glibc-0e169691290a6d2187a4ff41495fc5678cbfdcdc.zip
support: Add support_capture_subprogram
Its API is similar to support_capture_subprocess, but rather creates a new process based on the input path and arguments. Under the hoods it uses posix_spawn to create the new process. It also allows the use of other support_capture_* functions to check for expected results and free the resources. Checked on x86_64-linux-gnu. * support/Makefile (libsupport-routines): Add support_subprocess, xposix_spawn, xposix_spawn_file_actions_addclose, and xposix_spawn_file_actions_adddup2. (tst-support_capture_subprocess-ARGS): New rule. * support/capture_subprocess.h (support_capture_subprogram): New prototype. * support/support_capture_subprocess.c (support_capture_subprocess): Refactor to use support_subprocess and support_capture_poll. (support_capture_subprogram): New function. * support/tst-support_capture_subprocess.c (write_mode_to_str, str_to_write_mode, test_common, parse_int, handle_restart, do_subprocess, do_subprogram, do_multiple_tests): New functions. (do_test): Add support_capture_subprogram tests. * support/subprocess.h: New file. * support/support_subprocess.c: Likewise. * support/xposix_spawn.c: Likewise. * support/xposix_spawn_file_actions_addclose.c: Likewise. * support/xposix_spawn_file_actions_adddup2.c: Likewise. * support/xspawn.h: Likewise. Reviewed-by: Carlos O'Donell <carlos@redhat.com>
Diffstat (limited to 'support/support_subprocess.c')
-rw-r--r--support/support_subprocess.c152
1 files changed, 152 insertions, 0 deletions
diff --git a/support/support_subprocess.c b/support/support_subprocess.c
new file mode 100644
index 0000000000..0c8cc6af30
--- /dev/null
+++ b/support/support_subprocess.c
@@ -0,0 +1,152 @@
+/* Create subprocess.
+ 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/>. */
+
+#include <stdio.h>
+#include <signal.h>
+#include <time.h>
+#include <sys/wait.h>
+#include <stdbool.h>
+#include <support/xspawn.h>
+#include <support/check.h>
+#include <support/xunistd.h>
+#include <support/subprocess.h>
+
+static struct support_subprocess
+support_suprocess_init (void)
+{
+ struct support_subprocess result;
+
+ xpipe (result.stdout_pipe);
+ TEST_VERIFY (result.stdout_pipe[0] > STDERR_FILENO);
+ TEST_VERIFY (result.stdout_pipe[1] > STDERR_FILENO);
+
+ xpipe (result.stderr_pipe);
+ TEST_VERIFY (result.stderr_pipe[0] > STDERR_FILENO);
+ TEST_VERIFY (result.stderr_pipe[1] > STDERR_FILENO);
+
+ TEST_VERIFY (fflush (stdout) == 0);
+ TEST_VERIFY (fflush (stderr) == 0);
+
+ return result;
+}
+
+struct support_subprocess
+support_subprocess (void (*callback) (void *), void *closure)
+{
+ struct support_subprocess result = support_suprocess_init ();
+
+ result.pid = xfork ();
+ if (result.pid == 0)
+ {
+ xclose (result.stdout_pipe[0]);
+ xclose (result.stderr_pipe[0]);
+ xdup2 (result.stdout_pipe[1], STDOUT_FILENO);
+ xdup2 (result.stderr_pipe[1], STDERR_FILENO);
+ xclose (result.stdout_pipe[1]);
+ xclose (result.stderr_pipe[1]);
+ callback (closure);
+ _exit (0);
+ }
+ xclose (result.stdout_pipe[1]);
+ xclose (result.stderr_pipe[1]);
+
+ return result;
+}
+
+struct support_subprocess
+support_subprogram (const char *file, char *const argv[])
+{
+ struct support_subprocess result = support_suprocess_init ();
+
+ posix_spawn_file_actions_t fa;
+ /* posix_spawn_file_actions_init does not fail. */
+ posix_spawn_file_actions_init (&fa);
+
+ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[0]);
+ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[0]);
+ xposix_spawn_file_actions_adddup2 (&fa, result.stdout_pipe[1], STDOUT_FILENO);
+ xposix_spawn_file_actions_adddup2 (&fa, result.stderr_pipe[1], STDERR_FILENO);
+ xposix_spawn_file_actions_addclose (&fa, result.stdout_pipe[1]);
+ xposix_spawn_file_actions_addclose (&fa, result.stderr_pipe[1]);
+
+ result.pid = xposix_spawn (file, &fa, NULL, argv, NULL);
+
+ xclose (result.stdout_pipe[1]);
+ xclose (result.stderr_pipe[1]);
+
+ return result;
+}
+
+int
+support_process_wait (struct support_subprocess *proc)
+{
+ xclose (proc->stdout_pipe[0]);
+ xclose (proc->stderr_pipe[0]);
+
+ int status;
+ xwaitpid (proc->pid, &status, 0);
+ return status;
+}
+
+
+static bool
+support_process_kill (int pid, int signo, int *status)
+{
+ /* Kill the whole process group. */
+ kill (-pid, signo);
+ /* In case setpgid failed in the child, kill it individually too. */
+ kill (pid, signo);
+
+ /* Wait for it to terminate. */
+ pid_t killed;
+ for (int i = 0; i < 5; ++i)
+ {
+ int status;
+ killed = xwaitpid (pid, &status, WNOHANG|WUNTRACED);
+ if (killed != 0)
+ break;
+
+ /* Delay, give the system time to process the kill. If the
+ nanosleep() call return prematurely, all the better. We
+ won't restart it since this probably means the child process
+ finally died. */
+ nanosleep (&((struct timespec) { 0, 100000000 }), NULL);
+ }
+ if (killed != 0 && killed != pid)
+ return false;
+
+ return true;
+}
+
+int
+support_process_terminate (struct support_subprocess *proc)
+{
+ xclose (proc->stdout_pipe[0]);
+ xclose (proc->stderr_pipe[0]);
+
+ int status;
+ pid_t killed = xwaitpid (proc->pid, &status, WNOHANG|WUNTRACED);
+ if (killed != 0 && killed == proc->pid)
+ return status;
+
+ /* Subprocess is still running, terminate it. */
+ if (!support_process_kill (proc->pid, SIGTERM, &status) )
+ support_process_kill (proc->pid, SIGKILL, &status);
+
+ return status;
+}