summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2014-05-28 19:13:06 -0700
committerThiago Macieira <thiago.macieira@intel.com>2015-01-23 19:13:12 +0100
commitf3459a43af8098d286ff272cc8da5e0c755d0700 (patch)
treea9f35b05439bff0dbe56c95fb99bbb4e921fee28 /src
parent9931fa9df4cb96a4006a3390db64f87e3b5bc1a0 (diff)
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>
Diffstat (limited to 'src')
-rw-r--r--src/3rdparty/forkfd/forkfd.c63
-rw-r--r--src/3rdparty/forkfd/forkfd.h13
2 files changed, 76 insertions, 0 deletions
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 <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