summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/forkfd
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/forkfd')
-rw-r--r--src/3rdparty/forkfd/forkfd.c56
-rw-r--r--src/3rdparty/forkfd/forkfd.h16
-rw-r--r--src/3rdparty/forkfd/forkfd_freebsd.c22
-rw-r--r--src/3rdparty/forkfd/forkfd_linux.c30
4 files changed, 95 insertions, 29 deletions
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c
index 31189fa2cd..50784deaa5 100644
--- a/src/3rdparty/forkfd/forkfd.c
+++ b/src/3rdparty/forkfd/forkfd.c
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 Intel Corporation.
+** Copyright (C) 2020 Intel Corporation.
** Copyright (C) 2015 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
@@ -29,6 +29,11 @@
#include "forkfd.h"
+/* Macros fine-tuning the build: */
+//#define FORKFD_NO_FORKFD 1 /* disable the forkfd() function */
+//#define FORKFD_NO_SPAWNFD 1 /* disable the spawnfd() function */
+//#define FORKFD_DISABLE_FORK_FALLBACK 1 /* disable falling back to fork() from system_forkfd() */
+
#include <sys/types.h>
#if defined(__OpenBSD__) || defined(__NetBSD__)
# include <sys/param.h>
@@ -94,7 +99,17 @@
static int system_has_forkfd(void);
static int system_forkfd(int flags, pid_t *ppid, int *system);
-static int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage);
+static int system_forkfd_wait(int ffd, struct forkfd_info *info, int ffdwoptions, struct rusage *rusage);
+
+static int disable_fork_fallback(void)
+{
+#ifdef FORKFD_DISABLE_FORK_FALLBACK
+ /* if there's no system forkfd, we have to use the fallback */
+ return system_has_forkfd();
+#else
+ return false;
+#endif
+}
#define CHILDREN_IN_SMALL_ARRAY 16
#define CHILDREN_IN_BIG_ARRAY 256
@@ -225,6 +240,16 @@ static void convertStatusToForkfdInfo(int status, struct forkfd_info *info)
}
}
+static int convertForkfdWaitFlagsToWaitFlags(int ffdoptions)
+{
+ int woptions = WEXITED;
+ if (ffdoptions & FFDW_NOWAIT)
+ woptions |= WNOWAIT;
+ if (ffdoptions & FFDW_NOHANG)
+ woptions |= WNOHANG;
+ return woptions;
+}
+
static int tryReaping(pid_t pid, struct pipe_payload *payload)
{
/* reap the child */
@@ -586,12 +611,18 @@ static int create_pipe(int filedes[], int flags)
* descriptor. You probably want to set this flag, since forkfd() does not work
* if the original parent process dies.
*
- * @li @C FFD_USE_FORK Tell forkfd() to actually call fork() instead of a
+ * @li @c FFD_USE_FORK Tell forkfd() to actually call fork() instead of a
* different system implementation that may be available. On systems where a
* different implementation is available, its behavior may differ from that of
* fork(), such as not calling the functions registered with pthread_atfork().
* If that's necessary, pass this flag.
*
+ * @li @c FFD_VFORK_SEMANTICS Tell forkfd() to use semantics similar to
+ * vfork(), if that's available. For example, on Linux with pidfd support
+ * available, this will add the CLONE_VFORK option. On most other systems,
+ * including Linux without pidfd support, this option does nothing, as using
+ * the actual vfork() system call would cause a race condition.
+ *
* The file descriptor returned by forkfd() supports the following operations:
*
* @li read(2) When the child process exits, then the buffer supplied to
@@ -619,9 +650,12 @@ int forkfd(int flags, pid_t *ppid)
int efd;
#endif
+ if (disable_fork_fallback())
+ flags &= ~FFD_USE_FORK;
+
if ((flags & FFD_USE_FORK) == 0) {
fd = system_forkfd(flags, ppid, &ret);
- if (ret)
+ if (ret || disable_fork_fallback())
return fd;
}
@@ -800,14 +834,17 @@ out:
}
#endif // _POSIX_SPAWN && !FORKFD_NO_SPAWNFD
-
-int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
+int forkfd_wait4(int ffd, struct forkfd_info *info, int options, struct rusage *rusage)
{
struct pipe_payload payload;
int ret;
- if (system_has_forkfd())
- return system_forkfd_wait(ffd, info, rusage);
+ if (system_has_forkfd()) {
+ /* if this is one of our pipes, not a procdesc/pidfd, we'll get an EBADF */
+ ret = system_forkfd_wait(ffd, info, options, rusage);
+ if (disable_fork_fallback() || ret != -1 || errno != EBADF)
+ return ret;
+ }
ret = read(ffd, &payload, sizeof(payload));
if (ret == -1)
@@ -846,10 +883,11 @@ int system_forkfd(int flags, pid_t *ppid, int *system)
return -1;
}
-int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
+int system_forkfd_wait(int ffd, struct forkfd_info *info, int options, struct rusage *rusage)
{
(void)ffd;
(void)info;
+ (void)options;
(void)rusage;
return -1;
}
diff --git a/src/3rdparty/forkfd/forkfd.h b/src/3rdparty/forkfd/forkfd.h
index fe70371719..a864b59861 100644
--- a/src/3rdparty/forkfd/forkfd.h
+++ b/src/3rdparty/forkfd/forkfd.h
@@ -38,19 +38,27 @@
extern "C" {
#endif
-#define FFD_CLOEXEC 1
-#define FFD_NONBLOCK 2
-#define FFD_USE_FORK 4
+#define FFD_CLOEXEC 1
+#define FFD_NONBLOCK 2
+#define FFD_USE_FORK 4
+#define FFD_VFORK_SEMANTICS 8
#define FFD_CHILD_PROCESS (-2)
+#define FFDW_NOHANG 1 /* WNOHANG */
+#define FFDW_NOWAIT 2 /* WNOWAIT */
+
struct forkfd_info {
int32_t code;
int32_t status;
};
int forkfd(int flags, pid_t *ppid);
-int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage);
+int forkfd_wait4(int ffd, struct forkfd_info *info, int options, struct rusage *rusage);
+static inline int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
+{
+ return forkfd_wait4(ffd, info, 0, rusage);
+}
int forkfd_close(int ffd);
#if _POSIX_SPAWN > 0
diff --git a/src/3rdparty/forkfd/forkfd_freebsd.c b/src/3rdparty/forkfd/forkfd_freebsd.c
index 77ce3fcfad..c4ca796ccd 100644
--- a/src/3rdparty/forkfd/forkfd_freebsd.c
+++ b/src/3rdparty/forkfd/forkfd_freebsd.c
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 Intel Corporation.
+** Copyright (C) 2020 Intel Corporation.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
@@ -29,6 +29,10 @@
#include "forkfd_atomic.h"
+// in forkfd.c
+static int convertForkfdWaitFlagsToWaitFlags(int ffdoptions);
+static void convertStatusToForkfdInfo(int status, struct forkfd_info *info);
+
#if __FreeBSD__ >= 10
/* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option
* anymore and can't be disabled. */
@@ -81,19 +85,23 @@ int system_forkfd(int flags, pid_t *ppid, int *system)
return ret;
}
-int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
+int system_forkfd_wait(int ffd, struct forkfd_info *info, int ffdoptions, struct rusage *rusage)
{
pid_t pid;
int status;
- int options = WEXITED;
+ int options = convertForkfdWaitFlagsToWaitFlags(ffdoptions);
int ret = pdgetpid(ffd, &pid);
if (ret == -1)
return ret;
- ret = fcntl(ffd, F_GETFL);
- if (ret == -1)
- return ret;
- options |= (ret & O_NONBLOCK) ? WNOHANG : 0;
+
+ if ((options & WNOHANG) == 0) {
+ /* check if the file descriptor is non-blocking */
+ ret = fcntl(ffd, F_GETFL);
+ if (ret == -1)
+ return ret;
+ options |= (ret & O_NONBLOCK) ? WNOHANG : 0;
+ }
ret = wait4(pid, &status, options, rusage);
if (ret != -1 && info)
convertStatusToForkfdInfo(status, info);
diff --git a/src/3rdparty/forkfd/forkfd_linux.c b/src/3rdparty/forkfd/forkfd_linux.c
index 27ab09f748..c4f723343f 100644
--- a/src/3rdparty/forkfd/forkfd_linux.c
+++ b/src/3rdparty/forkfd/forkfd_linux.c
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2019 Intel Corporation.
+** Copyright (C) 2020 Intel Corporation.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
@@ -51,6 +51,10 @@
# define P_PIDFD 3
#endif
+// in forkfd.c
+static int convertForkfdWaitFlagsToWaitFlags(int ffdoptions);
+static void convertStatusToForkfdInfo(int status, struct forkfd_info *info);
+
static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(0);
static int sys_waitid(int which, int pid_or_pidfd, siginfo_t *infop, int options,
@@ -143,7 +147,10 @@ int system_forkfd(int flags, pid_t *ppid, int *system)
}
*system = 1;
- pid = sys_clone(CLONE_PIDFD, &pidfd);
+ unsigned long cloneflags = CLONE_PIDFD;
+ if (flags & FFD_VFORK_SEMANTICS)
+ cloneflags |= CLONE_VFORK;
+ pid = sys_clone(cloneflags, &pidfd);
if (ppid)
*ppid = pid;
@@ -162,15 +169,20 @@ int system_forkfd(int flags, pid_t *ppid, int *system)
return pidfd;
}
-int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
+int system_forkfd_wait(int ffd, struct forkfd_info *info, int ffdoptions, struct rusage *rusage)
{
siginfo_t si;
- int options = WEXITED | __WALL;
- int ret = fcntl(ffd, F_GETFL);
- if (ret == -1)
- return ret;
- if (ret & O_NONBLOCK)
- options |= WNOHANG;
+ int ret;
+ int options = __WALL | convertForkfdWaitFlagsToWaitFlags(ffdoptions);
+
+ if ((options & WNOHANG) == 0) {
+ /* check if the file descriptor is non-blocking */
+ ret = fcntl(ffd, F_GETFL);
+ if (ret == -1)
+ return ret;
+ if (ret & O_NONBLOCK)
+ options |= WNOHANG;
+ }
ret = sys_waitid(P_PIDFD, ffd, &si, options, rusage);
if (ret == -1 && errno == ECHILD) {