summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/forkfd
diff options
context:
space:
mode:
Diffstat (limited to 'src/3rdparty/forkfd')
-rw-r--r--src/3rdparty/forkfd/forkfd.c186
-rw-r--r--src/3rdparty/forkfd/forkfd.h5
-rw-r--r--src/3rdparty/forkfd/forkfd_atomic.h39
-rw-r--r--src/3rdparty/forkfd/forkfd_c11.h64
-rw-r--r--src/3rdparty/forkfd/forkfd_freebsd.c101
5 files changed, 279 insertions, 116 deletions
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c
index 12537b6199..e4f3bd85de 100644
--- a/src/3rdparty/forkfd/forkfd.c
+++ b/src/3rdparty/forkfd/forkfd.c
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2019 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
@@ -59,9 +59,6 @@
# define HAVE_PIPE2 1
# endif
#endif
-#if defined(__FreeBSD__) && __FreeBSD__ >= 9
-# include <sys/procdesc.h>
-#endif
#if _POSIX_VERSION-0 >= 200809L || _XOPEN_VERSION-0 >= 500
# define HAVE_WAITID 1
@@ -93,9 +90,11 @@
# endif
#endif
-#ifndef FFD_ATOMIC_RELAXED
-# include "forkfd_gcc.h"
-#endif
+#include "forkfd_atomic.h"
+
+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);
#define CHILDREN_IN_SMALL_ARRAY 16
#define CHILDREN_IN_BIG_ARRAY 256
@@ -448,6 +447,37 @@ static void ignore_sigpipe()
#endif
}
+#if defined(__GNUC__) && (!defined(__FreeBSD__) || __FreeBSD__ < 10)
+__attribute((destructor, unused)) static void cleanup();
+#endif
+
+static void cleanup()
+{
+ BigArray *array;
+ /* This function is not thread-safe!
+ * It must only be called when the process is shutting down.
+ * At shutdown, we expect no one to be calling forkfd(), so we don't
+ * need to be thread-safe with what is done there.
+ *
+ * But SIGCHLD might be delivered to any thread, including this one.
+ * There's no way to prevent that. The correct solution would be to
+ * cooperatively delete. We don't do that.
+ */
+ if (ffd_atomic_load(&forkfd_status, FFD_ATOMIC_RELAXED) == 0)
+ return;
+
+ /* notify the handler that we're no longer in operation */
+ ffd_atomic_store(&forkfd_status, 0, FFD_ATOMIC_RELAXED);
+
+ /* free any arrays we might have */
+ array = ffd_atomic_load(&children.header.nextArray, FFD_ATOMIC_ACQUIRE);
+ while (array != NULL) {
+ BigArray *next = ffd_atomic_load(&array->header.nextArray, FFD_ATOMIC_ACQUIRE);
+ free(array);
+ array = next;
+ }
+}
+
static void forkfd_initialize()
{
#if defined(HAVE_BROKEN_WAITID)
@@ -489,44 +519,15 @@ static void forkfd_initialize()
ignore_sigpipe();
#endif
-#ifndef __GNUC__
+#ifdef __GNUC__
+ (void) cleanup; /* suppress unused static function warning */
+#else
atexit(cleanup);
#endif
ffd_atomic_store(&forkfd_status, 1, FFD_ATOMIC_RELAXED);
}
-#ifdef __GNUC__
-__attribute((destructor, unused)) static void cleanup();
-#endif
-
-static void cleanup()
-{
- BigArray *array;
- /* This function is not thread-safe!
- * It must only be called when the process is shutting down.
- * At shutdown, we expect no one to be calling forkfd(), so we don't
- * need to be thread-safe with what is done there.
- *
- * But SIGCHLD might be delivered to any thread, including this one.
- * There's no way to prevent that. The correct solution would be to
- * cooperatively delete. We don't do that.
- */
- if (ffd_atomic_load(&forkfd_status, FFD_ATOMIC_RELAXED) == 0)
- return;
-
- /* notify the handler that we're no longer in operation */
- ffd_atomic_store(&forkfd_status, 0, FFD_ATOMIC_RELAXED);
-
- /* free any arrays we might have */
- array = ffd_atomic_load(&children.header.nextArray, FFD_ATOMIC_ACQUIRE);
- while (array != NULL) {
- BigArray *next = ffd_atomic_load(&array->header.nextArray, FFD_ATOMIC_ACQUIRE);
- free(array);
- array = next;
- }
-}
-
static int create_pipe(int filedes[], int flags)
{
int ret = -1;
@@ -565,55 +566,6 @@ static int create_pipe(int filedes[], int flags)
return ret;
}
-#if defined(FORKFD_NO_SPAWNFD) && defined(__FreeBSD__) && __FreeBSD__ >= 9
-# if __FreeBSD__ == 9
-/* PROCDESC is an optional feature in the kernel and wasn't enabled
- * by default on FreeBSD 9. So we need to check for it at runtime. */
-static ffd_atomic_int system_has_forkfd = FFD_ATOMIC_INIT(1);
-# else
-/* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option
- * anymore and can't be disabled. */
-static const int system_has_forkfd = 1;
-# endif
-
-static int system_forkfd(int flags, pid_t *ppid)
-{
- int ret;
- pid_t pid;
- pid = pdfork(&ret, PD_DAEMON);
- if (__builtin_expect(pid == -1, 0)) {
-# if __FreeBSD__ == 9
- if (errno == ENOSYS) {
- /* PROCDESC wasn't compiled into the kernel: don't try it again. */
- ffd_atomic_store(&system_has_forkfd, 0, FFD_ATOMIC_RELAXED);
- }
-# endif
- return -1;
- }
- if (pid == 0) {
- /* child process */
- return FFD_CHILD_PROCESS;
- }
-
- /* parent process */
- if (flags & FFD_CLOEXEC)
- fcntl(ret, F_SETFD, FD_CLOEXEC);
- if (flags & FFD_NONBLOCK)
- fcntl(ret, F_SETFL, fcntl(ret, F_GETFL) | O_NONBLOCK);
- if (ppid)
- *ppid = pid;
- return ret;
-}
-#else
-static const int system_has_forkfd = 0;
-static int system_forkfd(int flags, pid_t *ppid)
-{
- (void)flags;
- (void)ppid;
- return -1;
-}
-#endif
-
#ifndef FORKFD_NO_FORKFD
/**
* @brief forkfd returns a file descriptor representing a child process
@@ -661,11 +613,9 @@ int forkfd(int flags, pid_t *ppid)
int efd;
#endif
- if (system_has_forkfd) {
- ret = system_forkfd(flags, ppid);
- if (system_has_forkfd)
- return ret;
- }
+ fd = system_forkfd(flags, ppid, &ret);
+ if (ret)
+ return fd;
(void) pthread_once(&forkfd_initialization, forkfd_initialize);
@@ -790,7 +740,7 @@ int spawnfd(int flags, pid_t *ppid, const char *path, const posix_spawn_file_act
/* we can only do work if we have a way to start the child in stopped mode;
* otherwise, we have a major race condition. */
- assert(!system_has_forkfd);
+ assert(!system_has_forkfd());
(void) pthread_once(&forkfd_initialization, forkfd_initialize);
@@ -843,30 +793,13 @@ out:
#endif // _POSIX_SPAWN && !FORKFD_NO_SPAWNFD
-int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage)
+int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
{
struct pipe_payload payload;
int ret;
- if (system_has_forkfd) {
-#if defined(__FreeBSD__) && __FreeBSD__ >= 9
- pid_t pid;
- int status;
- int options = WEXITED;
-
- 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;
- ret = wait4(pid, &status, options, rusage);
- if (ret != -1 && info)
- convertStatusToForkfdInfo(status, info);
- return ret == -1 ? -1 : 0;
-#endif
- }
+ if (system_has_forkfd())
+ return system_forkfd_wait(ffd, info, rusage);
ret = read(ffd, &payload, sizeof(payload));
if (ret == -1)
@@ -886,3 +819,28 @@ int forkfd_close(int ffd)
{
return close(ffd);
}
+
+#if defined(__FreeBSD__) && __FreeBSD__ >= 9
+# include "forkfd_freebsd.c"
+#else
+int system_has_forkfd()
+{
+ return 0;
+}
+
+int system_forkfd(int flags, pid_t *ppid, int *system)
+{
+ (void)flags;
+ (void)ppid;
+ *system = 0;
+ return -1;
+}
+
+int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
+{
+ (void)ffd;
+ (void)info;
+ (void)rusage;
+ return -1;
+}
+#endif
diff --git a/src/3rdparty/forkfd/forkfd.h b/src/3rdparty/forkfd/forkfd.h
index 958321c299..eb121de593 100644
--- a/src/3rdparty/forkfd/forkfd.h
+++ b/src/3rdparty/forkfd/forkfd.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 Intel Corporation.
+** Copyright (C) 2019 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
@@ -27,6 +27,7 @@
#include <fcntl.h>
#include <stdint.h>
+#include <sys/wait.h>
#include <unistd.h> // to get the POSIX flags
#if _POSIX_SPAWN > 0
@@ -48,7 +49,7 @@ struct forkfd_info {
};
int forkfd(int flags, pid_t *ppid);
-int forkfd_wait(int ffd, forkfd_info *info, struct rusage *rusage);
+int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage);
int forkfd_close(int ffd);
#if _POSIX_SPAWN > 0
diff --git a/src/3rdparty/forkfd/forkfd_atomic.h b/src/3rdparty/forkfd/forkfd_atomic.h
new file mode 100644
index 0000000000..394e30d26c
--- /dev/null
+++ b/src/3rdparty/forkfd/forkfd_atomic.h
@@ -0,0 +1,39 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#if !defined(FFD_ATOMIC_H) & !defined(FFD_ATOMIC_RELAXED)
+#define FFD_ATOMIC_H
+
+#if defined(__cplusplus) && __cplusplus >= 201103L
+# include "forkfd_c11.h"
+#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
+# include "forkfd_c11.h"
+#elif defined(__GNUC__)
+# include "forkfd_gcc.h"
+#endif
+
+#endif /* FFD_ATOMIC_h && FFD_ATOMIC_RELAXED */
+#ifndef FFD_ATOMIC_RELAXED
+# error "Could not determine atomics for this platform"
+#endif
diff --git a/src/3rdparty/forkfd/forkfd_c11.h b/src/3rdparty/forkfd/forkfd_c11.h
new file mode 100644
index 0000000000..f3dc2b5357
--- /dev/null
+++ b/src/3rdparty/forkfd/forkfd_c11.h
@@ -0,0 +1,64 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#ifndef FFD_ATOMIC_C11_H
+#define FFD_ATOMIC_C11_H
+
+/* atomics */
+/* Using the C11 <stdatomic.h> header or C++11's <atomic>
+ */
+
+#if defined(__cplusplus)
+# include <atomic>
+# define ffd_atomic_pointer(type) std::atomic<type*>
+# define FFD_ATOMIC_RELAXED std::memory_order_relaxed
+# define FFD_ATOMIC_ACQUIRE std::memory_order_acquire
+# define FFD_ATOMIC_RELEASE std::memory_order_release
+// acq_rel & cst not necessary
+typedef std::atomic_int ffd_atomic_int;
+#else
+# include <stdatomic.h>
+# define ffd_atomic_pointer(type) _Atomic(type*)
+# define FFD_ATOMIC_RELAXED memory_order_relaxed
+# define FFD_ATOMIC_ACQUIRE memory_order_acquire
+# define FFD_ATOMIC_RELEASE memory_order_release
+// acq_rel & cst not necessary
+
+typedef atomic_int ffd_atomic_int;
+#endif
+
+#define FFD_ATOMIC_INIT(val) ATOMIC_VAR_INIT(val)
+
+#define ffd_atomic_load(ptr, order) \
+ atomic_load_explicit(ptr, order)
+#define ffd_atomic_store(ptr, val, order) \
+ atomic_store_explicit(ptr, val, order)
+#define ffd_atomic_exchange(ptr,val,order) \
+ atomic_exchange_explicit(ptr, val, order)
+#define ffd_atomic_compare_exchange(ptr, expected, desired, order1, order2) \
+ atomic_compare_exchange_strong_explicit(ptr, expected, desired, order1, order2)
+#define ffd_atomic_add_fetch(ptr, val, order) \
+ (atomic_fetch_add_explicit(ptr, val, order) + (val))
+
+#endif
diff --git a/src/3rdparty/forkfd/forkfd_freebsd.c b/src/3rdparty/forkfd/forkfd_freebsd.c
new file mode 100644
index 0000000000..77ce3fcfad
--- /dev/null
+++ b/src/3rdparty/forkfd/forkfd_freebsd.c
@@ -0,0 +1,101 @@
+/****************************************************************************
+**
+** Copyright (C) 2019 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
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#include "forkfd.h"
+
+#include <sys/types.h>
+#include <sys/procdesc.h>
+
+#include "forkfd_atomic.h"
+
+#if __FreeBSD__ >= 10
+/* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option
+ * anymore and can't be disabled. */
+static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(1);
+#else
+static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(0);
+#endif
+
+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)
+{
+ int ret;
+ pid_t pid;
+
+ int state = ffd_atomic_load(&system_forkfd_state, FFD_ATOMIC_RELAXED);
+ *system = 0;
+ if (state < 0)
+ return -1;
+
+ pid = pdfork(&ret, PD_DAEMON);
+# if __FreeBSD__ == 9
+ if (state == 0 && pid != 0) {
+ /* Parent process: remember whether PROCDESC was compiled into the kernel */
+ state = (pid == -1 && errno == ENOSYS) ? -1 : 1;
+ ffd_atomic_store(&system_forkfd_state, state, FFD_ATOMIC_RELAXED);
+ }
+ if (state < 0)
+ return -1;
+# endif
+ *system = 1;
+ if (__builtin_expect(pid == -1, 0))
+ return -1;
+
+ if (pid == 0) {
+ /* child process */
+ return FFD_CHILD_PROCESS;
+ }
+
+ /* parent process */
+ if (flags & FFD_CLOEXEC)
+ fcntl(ret, F_SETFD, FD_CLOEXEC);
+ if (flags & FFD_NONBLOCK)
+ fcntl(ret, F_SETFL, fcntl(ret, F_GETFL) | O_NONBLOCK);
+ if (ppid)
+ *ppid = pid;
+ return ret;
+}
+
+int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage)
+{
+ pid_t pid;
+ int status;
+ int options = WEXITED;
+
+ 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;
+ ret = wait4(pid, &status, options, rusage);
+ if (ret != -1 && info)
+ convertStatusToForkfdInfo(status, info);
+ return ret == -1 ? -1 : 0;
+}