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
|
# define HAVE_PIPE2 1
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
#if defined(__FreeBSD__) && __FreeBSD__ >= 9
|
|
||||||
# include <sys/procdesc.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if _POSIX_VERSION-0 >= 200809L || _XOPEN_VERSION-0 >= 500
|
#if _POSIX_VERSION-0 >= 200809L || _XOPEN_VERSION-0 >= 500
|
||||||
# define HAVE_WAITID 1
|
# define HAVE_WAITID 1
|
||||||
@ -95,6 +92,10 @@
|
|||||||
|
|
||||||
#include "forkfd_atomic.h"
|
#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_SMALL_ARRAY 16
|
||||||
#define CHILDREN_IN_BIG_ARRAY 256
|
#define CHILDREN_IN_BIG_ARRAY 256
|
||||||
#define sizeofarray(array) (sizeof(array)/sizeof(array[0]))
|
#define sizeofarray(array) (sizeof(array)/sizeof(array[0]))
|
||||||
@ -446,6 +447,37 @@ static void ignore_sigpipe()
|
|||||||
#endif
|
#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()
|
static void forkfd_initialize()
|
||||||
{
|
{
|
||||||
#if defined(HAVE_BROKEN_WAITID)
|
#if defined(HAVE_BROKEN_WAITID)
|
||||||
@ -487,44 +519,15 @@ static void forkfd_initialize()
|
|||||||
ignore_sigpipe();
|
ignore_sigpipe();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __GNUC__
|
#ifdef __GNUC__
|
||||||
|
(void) cleanup; /* suppress unused static function warning */
|
||||||
|
#else
|
||||||
atexit(cleanup);
|
atexit(cleanup);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ffd_atomic_store(&forkfd_status, 1, FFD_ATOMIC_RELAXED);
|
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)
|
static int create_pipe(int filedes[], int flags)
|
||||||
{
|
{
|
||||||
int ret = -1;
|
int ret = -1;
|
||||||
@ -563,55 +566,6 @@ static int create_pipe(int filedes[], int flags)
|
|||||||
return ret;
|
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
|
#ifndef FORKFD_NO_FORKFD
|
||||||
/**
|
/**
|
||||||
* @brief forkfd returns a file descriptor representing a child process
|
* @brief forkfd returns a file descriptor representing a child process
|
||||||
@ -659,11 +613,9 @@ int forkfd(int flags, pid_t *ppid)
|
|||||||
int efd;
|
int efd;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (system_has_forkfd) {
|
fd = system_forkfd(flags, ppid, &ret);
|
||||||
ret = system_forkfd(flags, ppid);
|
if (ret)
|
||||||
if (system_has_forkfd)
|
return fd;
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
(void) pthread_once(&forkfd_initialization, forkfd_initialize);
|
(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;
|
/* we can only do work if we have a way to start the child in stopped mode;
|
||||||
* otherwise, we have a major race condition. */
|
* otherwise, we have a major race condition. */
|
||||||
|
|
||||||
assert(!system_has_forkfd);
|
assert(!system_has_forkfd());
|
||||||
|
|
||||||
(void) pthread_once(&forkfd_initialization, forkfd_initialize);
|
(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;
|
struct pipe_payload payload;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (system_has_forkfd) {
|
if (system_has_forkfd())
|
||||||
#if defined(__FreeBSD__) && __FreeBSD__ >= 9
|
return system_forkfd_wait(ffd, info, rusage);
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = read(ffd, &payload, sizeof(payload));
|
ret = read(ffd, &payload, sizeof(payload));
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
@ -884,3 +819,28 @@ int forkfd_close(int ffd)
|
|||||||
{
|
{
|
||||||
return close(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