aboutsummaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
authorAdhemerval Zanella Netto <adhemerval.zanella@linaro.org>2023-01-12 10:58:51 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2023-02-01 08:42:11 -0300
commit2053c11331991818882f7cf023ed2ce4ff44b274 (patch)
treeb1edaafb8036456c39bff1756ed8827922c0b3b5 /sysdeps
parent2290cf73cce1292d9345a8183fd29ae3994a9481 (diff)
downloadglibc-2053c11331991818882f7cf023ed2ce4ff44b274.zip
glibc-2053c11331991818882f7cf023ed2ce4ff44b274.tar.gz
glibc-2053c11331991818882f7cf023ed2ce4ff44b274.tar.bz2
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 <carlos@redhat.com>
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/unix/sysv/linux/Makefile3
-rw-r--r--sysdeps/unix/sysv/linux/clone-internal.c37
-rw-r--r--sysdeps/unix/sysv/linux/clone3.h7
-rw-r--r--sysdeps/unix/sysv/linux/spawni.c31
4 files changed, 52 insertions, 26 deletions
diff --git a/sysdeps/unix/sysv/linux/Makefile b/sysdeps/unix/sysv/linux/Makefile
index f298878..f8bd12d 100644
--- a/sysdeps/unix/sysv/linux/Makefile
+++ b/sysdeps/unix/sysv/linux/Makefile
@@ -269,8 +269,7 @@ tests-clone-internal = \
tst-align-clone-internal \
tst-clone2-internal \
tst-clone3-internal \
- tst-getpid1-internal \
- tst-misalign-clone-internal
+ tst-getpid1-internal
tests-internal += $(tests-clone-internal)
tests-static += $(tests-clone-internal)
diff --git a/sysdeps/unix/sysv/linux/clone-internal.c b/sysdeps/unix/sysv/linux/clone-internal.c
index a861177..e125c91 100644
--- a/sysdeps/unix/sysv/linux/clone-internal.c
+++ b/sysdeps/unix/sysv/linux/clone-internal.c
@@ -44,27 +44,15 @@ _Static_assert (sizeof (struct clone_args) == CLONE_ARGS_SIZE_VER2,
"sizeof (struct clone_args) != CLONE_ARGS_SIZE_VER2");
int
-__clone_internal (struct clone_args *cl_args,
- int (*func) (void *arg), void *arg)
+__clone_internal_fallback (struct clone_args *cl_args,
+ int (*func) (void *arg), void *arg)
{
- int ret;
-#ifdef HAVE_CLONE3_WRAPPER
- /* Try clone3 first. */
- int saved_errno = errno;
- ret = __clone3 (cl_args, sizeof (*cl_args), func, arg);
- if (ret != -1 || errno != ENOSYS)
- return ret;
-
- /* NB: Restore errno since errno may be checked against non-zero
- return value. */
- __set_errno (saved_errno);
-#endif
-
/* Map clone3 arguments to clone arguments. NB: No need to check
invalid clone3 specific bits in flags nor exit_signal since this
is an internal function. */
int flags = cl_args->flags | cl_args->exit_signal;
void *stack = cast_to_pointer (cl_args->stack);
+ int ret;
#ifdef __ia64__
ret = __clone2 (func, stack, cl_args->stack_size,
@@ -88,4 +76,23 @@ __clone_internal (struct clone_args *cl_args,
return ret;
}
+
+int
+__clone_internal (struct clone_args *cl_args,
+ int (*func) (void *arg), void *arg)
+{
+#ifdef HAVE_CLONE3_WRAPPER
+ int saved_errno = errno;
+ int ret = __clone3 (cl_args, sizeof (*cl_args), func, arg);
+ if (ret != -1 || errno != ENOSYS)
+ return ret;
+
+ /* NB: Restore errno since errno may be checked against non-zero
+ return value. */
+ __set_errno (saved_errno);
+#endif
+
+ return __clone_internal_fallback (cl_args, func, arg);
+}
+
libc_hidden_def (__clone_internal)
diff --git a/sysdeps/unix/sysv/linux/clone3.h b/sysdeps/unix/sysv/linux/clone3.h
index e4d642e..451b156 100644
--- a/sysdeps/unix/sysv/linux/clone3.h
+++ b/sysdeps/unix/sysv/linux/clone3.h
@@ -23,6 +23,13 @@
#include <stddef.h>
#include <bits/types.h>
+
+/* Flags for the clone3 syscall. */
+#define CLONE_CLEAR_SIGHAND 0x100000000ULL /* Clear any signal handler and
+ reset to SIG_DFL. */
+#define CLONE_INTO_CGROUP 0x200000000ULL /* Clone into a specific cgroup given
+ the right permissions. */
+
/* The unsigned 64-bit and 8-byte aligned integer type. */
typedef __U64_TYPE __aligned_uint64_t __attribute__ ((__aligned__ (8)));
diff --git a/sysdeps/unix/sysv/linux/spawni.c b/sysdeps/unix/sysv/linux/spawni.c
index a1a14a5..bc321d4 100644
--- a/sysdeps/unix/sysv/linux/spawni.c
+++ b/sysdeps/unix/sysv/linux/spawni.c
@@ -66,6 +66,7 @@ struct posix_spawn_args
ptrdiff_t argc;
char *const *envp;
int xflags;
+ bool use_clone3;
int err;
};
@@ -104,12 +105,11 @@ __spawni_child (void *arguments)
const posix_spawnattr_t *restrict attr = args->attr;
const posix_spawn_file_actions_t *file_actions = args->fa;
- /* 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
- possibly be more optimized (by tracking which signal potentially have a
- signal handler), it might requires system specific solutions (since the
- sigset_t data type can be very different on different architectures). */
+ /* The child must ensure that no signal handler is enabled because it
+ shares memory with parent, so all signal dispositions must be either
+ SIG_DFL or SIG_IGN. If clone3/CLONE_CLEAR_SIGHAND is used, there is
+ only the need to set the defined signals POSIX_SPAWN_SETSIGDEF to
+ SIG_DFL; otherwise, the code iterates over all signals. */
struct sigaction sa;
memset (&sa, '\0', sizeof (sa));
@@ -122,7 +122,7 @@ __spawni_child (void *arguments)
{
sa.sa_handler = SIG_DFL;
}
- else if (__sigismember (&hset, sig))
+ else if (!args->use_clone3 && __sigismember (&hset, sig))
{
if (is_internal_signal (sig))
sa.sa_handler = SIG_IGN;
@@ -382,12 +382,25 @@ __spawnix (pid_t * pid, const char *file,
for instance). */
struct clone_args clone_args =
{
- .flags = CLONE_VM | CLONE_VFORK,
+ /* Unsupported flags like CLONE_CLEAR_SIGHAND will be cleared up by
+ __clone_internal_fallback. */
+ .flags = CLONE_CLEAR_SIGHAND | CLONE_VM | CLONE_VFORK,
.exit_signal = SIGCHLD,
.stack = (uintptr_t) stack,
.stack_size = stack_size,
};
- new_pid = __clone_internal (&clone_args, __spawni_child, &args);
+#ifdef HAVE_CLONE3_WRAPPER
+ args.use_clone3 = true;
+ new_pid = __clone3 (&clone_args, sizeof (clone_args), __spawni_child,
+ &args);
+ /* clone3 was added in 5.3 and CLONE_CLEAR_SIGHAND in 5.5. */
+ if (new_pid == -1 && (errno == ENOSYS || errno == EINVAL))
+#endif
+ {
+ args.use_clone3 = false;
+ new_pid = __clone_internal_fallback (&clone_args, __spawni_child,
+ &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