summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/forkfd
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2019-08-10 08:13:14 -0700
committerThiago Macieira <thiago.macieira@intel.com>2019-08-20 16:57:02 -0700
commit1b9274573e204ed24ef41eb0dc273bb7aa0be6f2 (patch)
treeb6fc1304f62c40ece8b796a09e71f59ae2480fa9 /src/3rdparty/forkfd
parent8784ab7ba8718c7254a774e3a487950cb77cd5ec (diff)
forkfd: move the FreeBSD system implementation to a separate file
Simplifies the code a bit and will be helpful when I add the Linux equivalent. Change-Id: Iec9c051acd73484c8d94fffd15b99879dc269db9 Reviewed-by: Lars Knoll <lars.knoll@qt.io>
Diffstat (limited to 'src/3rdparty/forkfd')
-rw-r--r--src/3rdparty/forkfd/forkfd.c178
-rw-r--r--src/3rdparty/forkfd/forkfd_freebsd.c101
2 files changed, 170 insertions, 109 deletions
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c
index 17a9b23581..e4f3bd85de 100644
--- a/src/3rdparty/forkfd/forkfd.c
+++ b/src/3rdparty/forkfd/forkfd.c
@@ -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
@@ -95,6 +92,10 @@
#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
#define sizeofarray(array) (sizeof(array)/sizeof(array[0]))
@@ -446,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)
@@ -487,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;
@@ -563,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
@@ -659,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);
@@ -788,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);
@@ -846,25 +798,8 @@ 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)
@@ -884,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_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;
+}