diff options
Diffstat (limited to 'src/3rdparty/forkfd')
-rw-r--r-- | src/3rdparty/forkfd/forkfd.c | 56 | ||||
-rw-r--r-- | src/3rdparty/forkfd/forkfd.h | 16 | ||||
-rw-r--r-- | src/3rdparty/forkfd/forkfd_freebsd.c | 22 | ||||
-rw-r--r-- | src/3rdparty/forkfd/forkfd_linux.c | 30 |
4 files changed, 95 insertions, 29 deletions
diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index 31189fa2cd..50784deaa5 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 Intel Corporation. +** Copyright (C) 2020 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 @@ -29,6 +29,11 @@ #include "forkfd.h" +/* Macros fine-tuning the build: */ +//#define FORKFD_NO_FORKFD 1 /* disable the forkfd() function */ +//#define FORKFD_NO_SPAWNFD 1 /* disable the spawnfd() function */ +//#define FORKFD_DISABLE_FORK_FALLBACK 1 /* disable falling back to fork() from system_forkfd() */ + #include <sys/types.h> #if defined(__OpenBSD__) || defined(__NetBSD__) # include <sys/param.h> @@ -94,7 +99,17 @@ 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); +static int system_forkfd_wait(int ffd, struct forkfd_info *info, int ffdwoptions, struct rusage *rusage); + +static int disable_fork_fallback(void) +{ +#ifdef FORKFD_DISABLE_FORK_FALLBACK + /* if there's no system forkfd, we have to use the fallback */ + return system_has_forkfd(); +#else + return false; +#endif +} #define CHILDREN_IN_SMALL_ARRAY 16 #define CHILDREN_IN_BIG_ARRAY 256 @@ -225,6 +240,16 @@ static void convertStatusToForkfdInfo(int status, struct forkfd_info *info) } } +static int convertForkfdWaitFlagsToWaitFlags(int ffdoptions) +{ + int woptions = WEXITED; + if (ffdoptions & FFDW_NOWAIT) + woptions |= WNOWAIT; + if (ffdoptions & FFDW_NOHANG) + woptions |= WNOHANG; + return woptions; +} + static int tryReaping(pid_t pid, struct pipe_payload *payload) { /* reap the child */ @@ -586,12 +611,18 @@ static int create_pipe(int filedes[], int flags) * descriptor. You probably want to set this flag, since forkfd() does not work * if the original parent process dies. * - * @li @C FFD_USE_FORK Tell forkfd() to actually call fork() instead of a + * @li @c FFD_USE_FORK Tell forkfd() to actually call fork() instead of a * different system implementation that may be available. On systems where a * different implementation is available, its behavior may differ from that of * fork(), such as not calling the functions registered with pthread_atfork(). * If that's necessary, pass this flag. * + * @li @c FFD_VFORK_SEMANTICS Tell forkfd() to use semantics similar to + * vfork(), if that's available. For example, on Linux with pidfd support + * available, this will add the CLONE_VFORK option. On most other systems, + * including Linux without pidfd support, this option does nothing, as using + * the actual vfork() system call would cause a race condition. + * * The file descriptor returned by forkfd() supports the following operations: * * @li read(2) When the child process exits, then the buffer supplied to @@ -619,9 +650,12 @@ int forkfd(int flags, pid_t *ppid) int efd; #endif + if (disable_fork_fallback()) + flags &= ~FFD_USE_FORK; + if ((flags & FFD_USE_FORK) == 0) { fd = system_forkfd(flags, ppid, &ret); - if (ret) + if (ret || disable_fork_fallback()) return fd; } @@ -800,14 +834,17 @@ out: } #endif // _POSIX_SPAWN && !FORKFD_NO_SPAWNFD - -int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) +int forkfd_wait4(int ffd, struct forkfd_info *info, int options, struct rusage *rusage) { struct pipe_payload payload; int ret; - if (system_has_forkfd()) - return system_forkfd_wait(ffd, info, rusage); + if (system_has_forkfd()) { + /* if this is one of our pipes, not a procdesc/pidfd, we'll get an EBADF */ + ret = system_forkfd_wait(ffd, info, options, rusage); + if (disable_fork_fallback() || ret != -1 || errno != EBADF) + return ret; + } ret = read(ffd, &payload, sizeof(payload)); if (ret == -1) @@ -846,10 +883,11 @@ int system_forkfd(int flags, pid_t *ppid, int *system) return -1; } -int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) +int system_forkfd_wait(int ffd, struct forkfd_info *info, int options, struct rusage *rusage) { (void)ffd; (void)info; + (void)options; (void)rusage; return -1; } diff --git a/src/3rdparty/forkfd/forkfd.h b/src/3rdparty/forkfd/forkfd.h index fe70371719..a864b59861 100644 --- a/src/3rdparty/forkfd/forkfd.h +++ b/src/3rdparty/forkfd/forkfd.h @@ -38,19 +38,27 @@ extern "C" { #endif -#define FFD_CLOEXEC 1 -#define FFD_NONBLOCK 2 -#define FFD_USE_FORK 4 +#define FFD_CLOEXEC 1 +#define FFD_NONBLOCK 2 +#define FFD_USE_FORK 4 +#define FFD_VFORK_SEMANTICS 8 #define FFD_CHILD_PROCESS (-2) +#define FFDW_NOHANG 1 /* WNOHANG */ +#define FFDW_NOWAIT 2 /* WNOWAIT */ + struct forkfd_info { int32_t code; int32_t status; }; int forkfd(int flags, pid_t *ppid); -int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage); +int forkfd_wait4(int ffd, struct forkfd_info *info, int options, struct rusage *rusage); +static inline int forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) +{ + return forkfd_wait4(ffd, info, 0, rusage); +} int forkfd_close(int ffd); #if _POSIX_SPAWN > 0 diff --git a/src/3rdparty/forkfd/forkfd_freebsd.c b/src/3rdparty/forkfd/forkfd_freebsd.c index 77ce3fcfad..c4ca796ccd 100644 --- a/src/3rdparty/forkfd/forkfd_freebsd.c +++ b/src/3rdparty/forkfd/forkfd_freebsd.c @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 Intel Corporation. +** Copyright (C) 2020 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 @@ -29,6 +29,10 @@ #include "forkfd_atomic.h" +// in forkfd.c +static int convertForkfdWaitFlagsToWaitFlags(int ffdoptions); +static void convertStatusToForkfdInfo(int status, struct forkfd_info *info); + #if __FreeBSD__ >= 10 /* On FreeBSD 10, PROCDESC was enabled by default. On v11, it's not an option * anymore and can't be disabled. */ @@ -81,19 +85,23 @@ int system_forkfd(int flags, pid_t *ppid, int *system) return ret; } -int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) +int system_forkfd_wait(int ffd, struct forkfd_info *info, int ffdoptions, struct rusage *rusage) { pid_t pid; int status; - int options = WEXITED; + int options = convertForkfdWaitFlagsToWaitFlags(ffdoptions); 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; + + if ((options & WNOHANG) == 0) { + /* check if the file descriptor is non-blocking */ + 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); diff --git a/src/3rdparty/forkfd/forkfd_linux.c b/src/3rdparty/forkfd/forkfd_linux.c index 27ab09f748..c4f723343f 100644 --- a/src/3rdparty/forkfd/forkfd_linux.c +++ b/src/3rdparty/forkfd/forkfd_linux.c @@ -1,6 +1,6 @@ /**************************************************************************** ** -** Copyright (C) 2019 Intel Corporation. +** Copyright (C) 2020 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 @@ -51,6 +51,10 @@ # define P_PIDFD 3 #endif +// in forkfd.c +static int convertForkfdWaitFlagsToWaitFlags(int ffdoptions); +static void convertStatusToForkfdInfo(int status, struct forkfd_info *info); + static ffd_atomic_int system_forkfd_state = FFD_ATOMIC_INIT(0); static int sys_waitid(int which, int pid_or_pidfd, siginfo_t *infop, int options, @@ -143,7 +147,10 @@ int system_forkfd(int flags, pid_t *ppid, int *system) } *system = 1; - pid = sys_clone(CLONE_PIDFD, &pidfd); + unsigned long cloneflags = CLONE_PIDFD; + if (flags & FFD_VFORK_SEMANTICS) + cloneflags |= CLONE_VFORK; + pid = sys_clone(cloneflags, &pidfd); if (ppid) *ppid = pid; @@ -162,15 +169,20 @@ int system_forkfd(int flags, pid_t *ppid, int *system) return pidfd; } -int system_forkfd_wait(int ffd, struct forkfd_info *info, struct rusage *rusage) +int system_forkfd_wait(int ffd, struct forkfd_info *info, int ffdoptions, struct rusage *rusage) { siginfo_t si; - int options = WEXITED | __WALL; - int ret = fcntl(ffd, F_GETFL); - if (ret == -1) - return ret; - if (ret & O_NONBLOCK) - options |= WNOHANG; + int ret; + int options = __WALL | convertForkfdWaitFlagsToWaitFlags(ffdoptions); + + if ((options & WNOHANG) == 0) { + /* check if the file descriptor is non-blocking */ + ret = fcntl(ffd, F_GETFL); + if (ret == -1) + return ret; + if (ret & O_NONBLOCK) + options |= WNOHANG; + } ret = sys_waitid(P_PIDFD, ffd, &si, options, rusage); if (ret == -1 && errno == ECHILD) { |