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 <thiago.macieira@intel.com>
This commit is contained in:
parent
9931fa9df4
commit
f3459a43af
63
src/3rdparty/forkfd/forkfd.c
vendored
63
src/3rdparty/forkfd/forkfd.c
vendored
@ -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
|
||||
|
13
src/3rdparty/forkfd/forkfd.h
vendored
13
src/3rdparty/forkfd/forkfd.h
vendored
@ -39,6 +39,11 @@
|
||||
#define FORKFD_H
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h> // to get the POSIX flags
|
||||
|
||||
#ifdef _POSIX_SPAWN
|
||||
# include <spawn.h>
|
||||
#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
|
||||
|
Loading…
x
Reference in New Issue
Block a user