summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/forkfd/forkfd_linux.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/forkfd/forkfd_linux.c')
-rw-r--r--src/3rdparty/forkfd/forkfd_linux.c60
1 files changed, 48 insertions, 12 deletions
diff --git a/src/3rdparty/forkfd/forkfd_linux.c b/src/3rdparty/forkfd/forkfd_linux.c
index 4b3be7036b..4dacc1919d 100644
--- a/src/3rdparty/forkfd/forkfd_linux.c
+++ b/src/3rdparty/forkfd/forkfd_linux.c
@@ -51,6 +51,8 @@
# define P_PIDFD 3
#endif
+#define SYSTEM_FORKFD_CAN_VFORK
+
// in forkfd.c
static int convertForkfdWaitFlagsToWaitFlags(int ffdoptions);
static void convertStatusToForkfdInfo(int status, struct forkfd_info *info);
@@ -82,7 +84,8 @@ static int sys_clone(unsigned long cloneflags, int *ptid)
return syscall(__NR_clone, cloneflags, child_stack, stack_size, ptid, newtls, ctid);
#elif defined(__arc__) || defined(__arm__) || defined(__aarch64__) || defined(__mips__) || \
defined(__nds32__) || defined(__hppa__) || defined(__powerpc__) || defined(__i386__) || \
- defined(__x86_64__) || defined(__xtensa__) || defined(__alpha__) || defined(__riscv)
+ defined(__x86_64__) || defined(__xtensa__) || defined(__alpha__) || defined(__riscv) || \
+ defined(__loongarch__)
/* ctid and newtls are inverted on CONFIG_CLONE_BACKWARDS architectures,
* but since both values are 0, there's no harm. */
return syscall(__NR_clone, cloneflags, child_stack, ptid, ctid, newtls);
@@ -131,16 +134,55 @@ int system_has_forkfd()
return ffd_atomic_load(&system_forkfd_state, FFD_ATOMIC_RELAXED) > 0;
}
-int system_forkfd(int flags, pid_t *ppid, int *system)
+static int system_forkfd_availability(void)
{
- pid_t pid;
- int pidfd;
-
int state = ffd_atomic_load(&system_forkfd_state, FFD_ATOMIC_RELAXED);
if (state == 0) {
state = detect_clone_pidfd_support();
ffd_atomic_store(&system_forkfd_state, state, FFD_ATOMIC_RELAXED);
}
+ return state;
+}
+
+static int system_forkfd_pidfd_set_flags(int pidfd, int flags)
+{
+ if ((flags & FFD_CLOEXEC) == 0) {
+ /* pidfd defaults to O_CLOEXEC */
+ fcntl(pidfd, F_SETFD, 0);
+ }
+ if (flags & FFD_NONBLOCK)
+ fcntl(pidfd, F_SETFL, fcntl(pidfd, F_GETFL) | O_NONBLOCK);
+ return pidfd;
+}
+
+int system_vforkfd(int flags, pid_t *ppid, int (*childFn)(void *), void *token, int *system)
+{
+ __attribute__((aligned(64))) char childStack[SIGSTKSZ];
+ pid_t pid;
+ int pidfd;
+ unsigned long cloneflags = CLONE_PIDFD | CLONE_VFORK | CLONE_VM | SIGCHLD;
+
+ int state = system_forkfd_availability();
+ if (state < 0) {
+ *system = 0;
+ return state;
+ }
+ *system = 1;
+
+ pid = clone(childFn, childStack + sizeof(childStack), cloneflags, token, &pidfd, NULL, NULL);
+ if (pid < 0)
+ return pid;
+ if (ppid)
+ *ppid = pid;
+ return system_forkfd_pidfd_set_flags(pidfd, flags);
+}
+
+int system_forkfd(int flags, pid_t *ppid, int *system)
+{
+ pid_t pid;
+ int pidfd;
+
+ int state = system_forkfd_availability();
if (state < 0) {
*system = 0;
return state;
@@ -160,13 +202,7 @@ int system_forkfd(int flags, pid_t *ppid, int *system)
}
/* parent process */
- if ((flags & FFD_CLOEXEC) == 0) {
- /* pidfd defaults to O_CLOEXEC */
- fcntl(pidfd, F_SETFD, 0);
- }
- if (flags & FFD_NONBLOCK)
- fcntl(pidfd, F_SETFL, fcntl(pidfd, F_GETFL) | O_NONBLOCK);
- return pidfd;
+ return system_forkfd_pidfd_set_flags(pidfd, flags);
}
int system_forkfd_wait(int ffd, struct forkfd_info *info, int ffdoptions, struct rusage *rusage)