From 2053c11331991818882f7cf023ed2ce4ff44b274 Mon Sep 17 00:00:00 2001 From: Adhemerval Zanella Netto Date: Thu, 12 Jan 2023 10:58:51 -0300 Subject: linux: Add clone3 CLONE_CLEAR_SIGHAND optimization to posix_spawn The clone3 flag resets all signal handlers of the child not set to SIG_IGN to SIG_DFL. It allows to skip most of the sigaction calls to setup child signal handling, where previously a posix_spawn had to issue 2 times NSIG sigaction calls (one to obtain the current disposition and another to set either SIG_DFL or SIG_IGN). With POSIX_SPAWN_SETSIGDEF the child will setup the signal for the case where the disposition is SIG_IGN. The code must handle the fallback where clone3 is not available. This is done by splitting __clone_internal_fallback from __clone_internal. Checked on x86_64-linux-gnu. Reviewed-by: Carlos O'Donell --- posix/Makefile | 3 +- posix/tst-spawn7.c | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 181 insertions(+), 1 deletion(-) create mode 100644 posix/tst-spawn7.c (limited to 'posix') diff --git a/posix/Makefile b/posix/Makefile index 38a4279599..7e4f252a40 100644 --- a/posix/Makefile +++ b/posix/Makefile @@ -109,7 +109,7 @@ tests := test-errno tstgetopt testfnm runtests runptests \ tst-glob-tilde test-ssize-max tst-spawn4 bug-regex37 \ bug-regex38 tst-regcomp-truncated tst-spawn-chdir \ tst-wordexp-nocmd tst-execveat tst-spawn5 \ - tst-sched_getaffinity tst-spawn6 + tst-sched_getaffinity tst-spawn6 tst-spawn7 # Test for the glob symbol version that was replaced in glibc 2.27. ifeq ($(have-GLIBC_2.26)$(build-shared),yesyes) @@ -291,6 +291,7 @@ tst-spawn-ARGS = -- $(host-test-program-cmd) tst-spawn-static-ARGS = $(tst-spawn-ARGS) tst-spawn5-ARGS = -- $(host-test-program-cmd) tst-spawn6-ARGS = -- $(host-test-program-cmd) +tst-spawn7-ARGS = -- $(host-test-program-cmd) tst-dir-ARGS = `pwd` `cd $(common-objdir)/$(subdir); pwd` `cd $(common-objdir); pwd` $(objpfx)tst-dir tst-chmod-ARGS = $(objdir) tst-vfork3-ARGS = --test-dir=$(objpfx) diff --git a/posix/tst-spawn7.c b/posix/tst-spawn7.c new file mode 100644 index 0000000000..a1c0d9d942 --- /dev/null +++ b/posix/tst-spawn7.c @@ -0,0 +1,179 @@ +/* Tests for posix_spawn signal handling. + Copyright (C) 2023 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 + . */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Nonzero if the program gets called via `exec'. */ +#define CMDLINE_OPTIONS \ + { "restart", no_argument, &restart, 1 }, +static int restart; + +/* Hold the four initial argument used to respawn the process, plus the extra + '--direct', '--restart', the check type ('SIG_IGN' or 'SIG_DFL'), and a + final NULL. */ +static char *spargs[8]; +static int check_type_argc; + +/* Called on process re-execution. */ +_Noreturn static void +handle_restart (int argc, char *argv[]) +{ + assert (argc == 1); + + if (strcmp (argv[0], "SIG_DFL") == 0) + { + for (int i = 1; i < NSIG; i++) + { + struct sigaction sa; + int r = sigaction (i, NULL, &sa); + /* Skip internal signals (such as SIGCANCEL). */ + if (r == -1) + continue; + TEST_VERIFY_EXIT (sa.sa_handler == SIG_DFL); + } + exit (EXIT_SUCCESS); + } + else if (strcmp (argv[0], "SIG_IGN") == 0) + { + for (int i = 1; i < NSIG; i++) + { + struct sigaction sa; + int r = sigaction (i, NULL, &sa); + /* Skip internal signals (such as SIGCANCEL). */ + if (r == -1) + continue; + if (i == SIGUSR1 || i == SIGUSR2) + TEST_VERIFY_EXIT (sa.sa_handler == SIG_IGN); + else + TEST_VERIFY_EXIT (sa.sa_handler == SIG_DFL); + } + exit (EXIT_SUCCESS); + } + + exit (EXIT_FAILURE); +} + +static void +spawn_signal_test (const char *type, const posix_spawnattr_t *attr) +{ + spargs[check_type_argc] = (char*) type; + + pid_t pid; + int status; + + TEST_COMPARE (posix_spawn (&pid, spargs[0], NULL, attr, spargs, environ), 0); + TEST_COMPARE (xwaitpid (pid, &status, 0), pid); + TEST_VERIFY (WIFEXITED (status)); + TEST_VERIFY (!WIFSIGNALED (status)); + TEST_COMPARE (WEXITSTATUS (status), 0); +} + +static void +dummy_sa_handler (int) +{ +} + +static void +do_test_signals (void) +{ + { + /* Check if all signals handler are set to SIG_DFL on spawned process. */ + spawn_signal_test ("SIG_DFL", NULL); + } + + { + /* Same as before, but set SIGUSR1 and SIGUSR2 to a handler different than + SIG_IGN or SIG_DFL. */ + struct sigaction sa = { 0 }; + sa.sa_handler = dummy_sa_handler; + xsigaction (SIGUSR1, &sa, NULL); + xsigaction (SIGUSR2, &sa, NULL); + spawn_signal_test ("SIG_DFL", NULL); + } + + { + /* Check if SIG_IGN is keep as is. */ + struct sigaction sa = { 0 }; + sa.sa_handler = SIG_IGN; + xsigaction (SIGUSR1, &sa, NULL); + xsigaction (SIGUSR2, &sa, NULL); + spawn_signal_test ("SIG_IGN", NULL); + } + + { + /* Check if SIG_IGN handlers are set to SIG_DFL. */ + posix_spawnattr_t attr; + posix_spawnattr_init (&attr); + sigset_t mask; + sigemptyset (&mask); + sigaddset (&mask, SIGUSR1); + sigaddset (&mask, SIGUSR2); + posix_spawnattr_setsigdefault (&attr, &mask); + posix_spawnattr_setflags (&attr, POSIX_SPAWN_SETSIGDEF); + spawn_signal_test ("SIG_DFL", &attr); + posix_spawnattr_destroy (&attr); + } +} + +static int +do_test (int argc, char *argv[]) +{ + /* We must have either: + + - one or four parameters if called initially: + + argv[1]: path for ld.so optional + + argv[2]: "--library-path" optional + + argv[3]: the library path optional + + argv[4]: the application name + + - six parameters left if called through re-execution: + + argv[1]: the application name + + argv[2]: check SIG_IGN/SIG_DFL. + + * When built with --enable-hardcoded-path-in-tests or issued without + using the loader directly. */ + + if (restart) + handle_restart (argc - 1, &argv[1]); + + TEST_VERIFY_EXIT (argc == 2 || argc == 5); + + int i; + for (i = 0; i < argc - 1; i++) + spargs[i] = argv[i + 1]; + spargs[i++] = (char *) "--direct"; + spargs[i++] = (char *) "--restart"; + check_type_argc = i++; + spargs[i] = NULL; + + + do_test_signals (); + + return 0; +} + +#define TEST_FUNCTION_ARGV do_test +#include -- cgit 1.4.1