From 531e6a2091ad238f2635858fe78ea01b2dfb8b6d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 20 Jun 2025 04:31:08 +0900 Subject: [PATCH] raw-clone: move definition to .c file Then, we can decrease the number of headers to be indirectly included by including raw-clone.h. No functional change. --- src/basic/meson.build | 1 + src/basic/raw-clone.c | 84 +++++++++++++++++++++++++++++++++++++++++++ src/basic/raw-clone.h | 83 ++---------------------------------------- 3 files changed, 88 insertions(+), 80 deletions(-) create mode 100644 src/basic/raw-clone.c diff --git a/src/basic/meson.build b/src/basic/meson.build index b03df4a9a4c..d8591d49e2a 100644 --- a/src/basic/meson.build +++ b/src/basic/meson.build @@ -84,6 +84,7 @@ basic_sources = files( 'psi-util.c', 'random-util.c', 'ratelimit.c', + 'raw-clone.c', 'recurse-dir.c', 'replace-var.c', 'rlimit-util.c', diff --git a/src/basic/raw-clone.c b/src/basic/raw-clone.c new file mode 100644 index 00000000000..aa750acb6d9 --- /dev/null +++ b/src/basic/raw-clone.c @@ -0,0 +1,84 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/*** + Copyright © 2016 Michael Karcher +***/ + +#include +#include +#include +#include + +#include "process-util.h" +#include "raw-clone.h" + +/** + * raw_clone() - uses clone to create a new process with clone flags + * @flags: Flags to pass to the clone system call + * + * Uses the clone system call to create a new process with the cloning flags and termination signal passed in the flags + * parameter. Opposed to glibc's clone function, using this function does not set up a separate stack for the child, but + * relies on copy-on-write semantics on the one stack at a common virtual address, just as fork does. + * + * To obtain copy-on-write semantics, flags must not contain CLONE_VM, and thus CLONE_THREAD and CLONE_SIGHAND + * (which require CLONE_VM) are not usable. + * + * Additionally, as this function does not pass the ptid (pidfd in the case of CLONE_PIDFD), newtls and ctid + * parameters to the kernel, flags must not contain CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID, + * CLONE_SETTLS, or CLONE_PIDFD. + * + * WARNING: 💣 this call (just like glibc's own clone() wrapper) will not synchronize on glibc's malloc + * locks, which means they will be in an undefined state in the child if the parent is + * threaded. This means: the parent must either never use threads, or the child cannot use memory + * allocation itself. This is a major pitfall, hence be careful! 💣 + * + * Returns: 0 in the child process and the child process id in the parent. + */ +pid_t raw_clone(unsigned long flags) { + pid_t ret; + + assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID|CLONE_SETTLS|CLONE_PIDFD)) == 0); +#if defined(__s390x__) || defined(__s390__) || defined(__CRIS__) + /* On s390/s390x and cris the order of the first and second arguments + * of the raw clone() system call is reversed. */ + ret = (pid_t) syscall(__NR_clone, NULL, flags); +#elif defined(__sparc__) + { + /** + * sparc always returns the other process id in %o0, and + * a boolean flag whether this is the child or the parent in + * %o1. Inline assembly is needed to get the flag returned + * in %o1. + */ + int in_child, child_pid, error; + + asm volatile("mov %3, %%g1\n\t" + "mov %4, %%o0\n\t" + "mov 0 , %%o1\n\t" +#if defined(__arch64__) + "t 0x6d\n\t" +#else + "t 0x10\n\t" +#endif + "addx %%g0, 0, %2\n\t" + "mov %%o1, %0\n\t" + "mov %%o0, %1" : + "=r"(in_child), "=r"(child_pid), "=r"(error) : + "i"(__NR_clone), "r"(flags) : + "%o1", "%o0", "%g1", "cc" ); + + if (error) { + errno = child_pid; + ret = -1; + } else + ret = in_child ? 0 : child_pid; + } +#else + ret = (pid_t) syscall(__NR_clone, flags, NULL); +#endif + + if (ret == 0) + reset_cached_pid(); + + return ret; +} diff --git a/src/basic/raw-clone.h b/src/basic/raw-clone.h index 36202cc0ba4..af20cde73b9 100644 --- a/src/basic/raw-clone.h +++ b/src/basic/raw-clone.h @@ -1,85 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once -/*** - Copyright © 2016 Michael Karcher -***/ +#include /* IWYU pragma: export */ -#include -#include -#include +#include "forward.h" -#include "log.h" -#include "macro.h" -#include "process-util.h" - -/** - * raw_clone() - uses clone to create a new process with clone flags - * @flags: Flags to pass to the clone system call - * - * Uses the clone system call to create a new process with the cloning flags and termination signal passed in the flags - * parameter. Opposed to glibc's clone function, using this function does not set up a separate stack for the child, but - * relies on copy-on-write semantics on the one stack at a common virtual address, just as fork does. - * - * To obtain copy-on-write semantics, flags must not contain CLONE_VM, and thus CLONE_THREAD and CLONE_SIGHAND - * (which require CLONE_VM) are not usable. - * - * Additionally, as this function does not pass the ptid (pidfd in the case of CLONE_PIDFD), newtls and ctid - * parameters to the kernel, flags must not contain CLONE_PARENT_SETTID, CLONE_CHILD_SETTID, CLONE_CHILD_CLEARTID, - * CLONE_SETTLS, or CLONE_PIDFD. - * - * WARNING: 💣 this call (just like glibc's own clone() wrapper) will not synchronize on glibc's malloc - * locks, which means they will be in an undefined state in the child if the parent is - * threaded. This means: the parent must either never use threads, or the child cannot use memory - * allocation itself. This is a major pitfall, hence be careful! 💣 - * - * Returns: 0 in the child process and the child process id in the parent. - */ -static inline pid_t raw_clone(unsigned long flags) { - pid_t ret; - - assert((flags & (CLONE_VM|CLONE_PARENT_SETTID|CLONE_CHILD_SETTID|CLONE_CHILD_CLEARTID|CLONE_SETTLS|CLONE_PIDFD)) == 0); -#if defined(__s390x__) || defined(__s390__) || defined(__CRIS__) - /* On s390/s390x and cris the order of the first and second arguments - * of the raw clone() system call is reversed. */ - ret = (pid_t) syscall(__NR_clone, NULL, flags); -#elif defined(__sparc__) - { - /** - * sparc always returns the other process id in %o0, and - * a boolean flag whether this is the child or the parent in - * %o1. Inline assembly is needed to get the flag returned - * in %o1. - */ - int in_child, child_pid, error; - - asm volatile("mov %3, %%g1\n\t" - "mov %4, %%o0\n\t" - "mov 0 , %%o1\n\t" -#if defined(__arch64__) - "t 0x6d\n\t" -#else - "t 0x10\n\t" -#endif - "addx %%g0, 0, %2\n\t" - "mov %%o1, %0\n\t" - "mov %%o0, %1" : - "=r"(in_child), "=r"(child_pid), "=r"(error) : - "i"(__NR_clone), "r"(flags) : - "%o1", "%o0", "%g1", "cc" ); - - if (error) { - errno = child_pid; - ret = -1; - } else - ret = in_child ? 0 : child_pid; - } -#else - ret = (pid_t) syscall(__NR_clone, flags, NULL); -#endif - - if (ret == 0) - reset_cached_pid(); - - return ret; -} +pid_t raw_clone(unsigned long flags); -- 2.47.3