From f3459a43af8098d286ff272cc8da5e0c755d0700 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Wed, 28 May 2014 19:13:06 -0700 Subject: Add spawnfd for use where fork / forkfd can't be used In certain environments, using fork() is not recommended due to the need for an MMU. This commit adds support for those environments, by using posix_spawn. Limitations of this environment are: - we cannot reliably detect failure to exec (e.g. non-existing executable) - we cannot do setsid(); we do setpgrp(0, 0) instead - we cannot thread-safely chdir() to the requested dir Because of the former limitation, the QProcess unit tests that rely on failure-to-start error conditions are either skipped or marked as expected failures. There's a non-reliable solution that is implemented in a another commit. This change also makes it easier to transition the QNX builds to using fork(), which is supported from QNX Neutrino 6.6 and onwards. Change-Id: I5cb46abf2ef8783941525d35cc991f00d2bf2d58 Reviewed-by: Thiago Macieira --- src/3rdparty/forkfd/forkfd.c | 63 ++++++++++++++++++++++++++++++++++++++++++++ src/3rdparty/forkfd/forkfd.h | 13 +++++++++ 2 files changed, 76 insertions(+) (limited to 'src/3rdparty') diff --git a/src/3rdparty/forkfd/forkfd.c b/src/3rdparty/forkfd/forkfd.c index 2ad06fe1a5..1b3e162a7e 100644 --- a/src/3rdparty/forkfd/forkfd.c +++ b/src/3rdparty/forkfd/forkfd.c @@ -590,3 +590,66 @@ err_free: freeInfo(header, info); return -1; } + +#ifdef _POSIX_SPAWN +int spawnfd(int flags, pid_t *ppid, const char *path, const posix_spawn_file_actions_t *file_actions, + posix_spawnattr_t *attrp, char *const argv[], char *const envp[]) +{ + Header *header; + ProcessInfo *info; + siginfo_t si; + pid_t pid; + int death_pipe[2]; + int ret = -1; + /* we can only do work if we have a way to start the child in stopped mode; + * otherwise, we have a major race condition. */ + + (void) pthread_once(&forkfd_initialization, forkfd_initialize); + + info = allocateInfo(&header); + if (info == NULL) { + errno = ENOMEM; + goto out; + } + + /* create the pipe before we spawn */ + if (create_pipe(death_pipe, flags) == -1) + goto err_free; /* failed to create the pipes, pass errno */ + + /* start the process */ + if (flags & FFD_SPAWN_SEARCH_PATH) { + /* use posix_spawnp */ + if (posix_spawnp(&pid, path, file_actions, attrp, argv, envp) != 0) + goto err_close; + } else { + if (posix_spawn(&pid, path, file_actions, attrp, argv, envp) != 0) + goto err_close; + } + + if (ppid) + *ppid = pid; + + /* Store the child's PID in the info structure. + */ + info->deathPipe = death_pipe[1]; + ffd_atomic_store(&info->pid, pid, FFD_ATOMIC_RELEASE); + + /* check if the child has already exited */ + if (tryReaping(pid, &si)) + notifyAndFreeInfo(header, info, &si); + + ret = death_pipe[0]; + return ret; + +err_close: + EINTR_LOOP(ret, close(death_pipe[0])); + EINTR_LOOP(ret, close(death_pipe[1])); + +err_free: + /* free the info pointer */ + freeInfo(header, info); + +out: + return -1; +} +#endif // _POSIX_SPAWN diff --git a/src/3rdparty/forkfd/forkfd.h b/src/3rdparty/forkfd/forkfd.h index 01b8882623..c987f8a7a9 100644 --- a/src/3rdparty/forkfd/forkfd.h +++ b/src/3rdparty/forkfd/forkfd.h @@ -39,6 +39,11 @@ #define FORKFD_H #include +#include // to get the POSIX flags + +#ifdef _POSIX_SPAWN +# include +#endif #ifdef __cplusplus extern "C" { @@ -51,6 +56,14 @@ extern "C" { int forkfd(int flags, pid_t *ppid); +#ifdef _POSIX_SPAWN +/* only for spawnfd: */ +# define FFD_SPAWN_SEARCH_PATH O_RDWR + +int spawnfd(int flags, pid_t *ppid, const char *path, const posix_spawn_file_actions_t *file_actions, + posix_spawnattr_t *attrp, char *const argv[], char *const envp[]); +#endif + #ifdef __cplusplus } #endif -- cgit v1.2.3