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:
Thiago Macieira 2014-05-28 19:13:06 -07:00
parent 9931fa9df4
commit f3459a43af
2 changed files with 76 additions and 0 deletions

View File

@ -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

View File

@ -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