diff options
Diffstat (limited to 'src/3rdparty/forkfd')
-rw-r--r-- | src/3rdparty/forkfd/forkfd.c | 186 | ||||
-rw-r--r-- | src/3rdparty/forkfd/forkfd.h | 5 | ||||
-rw-r--r-- | src/3rdparty/forkfd/forkfd_atomic.h | 39 | ||||
-rw-r--r-- | src/3rdparty/forkfd/forkfd_c11.h | 64 | ||||
-rw-r--r-- | src/3rdparty/forkfd/forkfd_freebsd.c | 101 |
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; +} |