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>
This commit is contained in:
parent
8784ab7ba8
commit
1b9274573e
178
src/3rdparty/forkfd/forkfd.c
vendored
178
src/3rdparty/forkfd/forkfd.c
vendored
@ -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
|
||||
|
101
src/3rdparty/forkfd/forkfd_freebsd.c
vendored
Normal file
101
src/3rdparty/forkfd/forkfd_freebsd.c
vendored
Normal file
@ -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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user