summaryrefslogtreecommitdiffstats
path: root/src/corelib/io
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/io')
-rw-r--r--src/corelib/io/io.pri1
-rw-r--r--src/corelib/io/qprocess.cpp13
-rw-r--r--src/corelib/io/qprocess_p.h18
-rw-r--r--src/corelib/io/qprocess_unix.cpp495
4 files changed, 138 insertions, 389 deletions
diff --git a/src/corelib/io/io.pri b/src/corelib/io/io.pri
index 184ceb34be..78349fbc49 100644
--- a/src/corelib/io/io.pri
+++ b/src/corelib/io/io.pri
@@ -140,6 +140,7 @@ win32 {
io/forkfd_qt.cpp
HEADERS += \
../3rdparty/forkfd/forkfd.h
+ INCLUDEPATH += ../3rdparty/forkfd
!nacl:mac: {
SOURCES += io/qsettings_mac.cpp
diff --git a/src/corelib/io/qprocess.cpp b/src/corelib/io/qprocess.cpp
index a234050777..976d8503f3 100644
--- a/src/corelib/io/qprocess.cpp
+++ b/src/corelib/io/qprocess.cpp
@@ -89,6 +89,8 @@ QT_END_NAMESPACE
#ifdef Q_OS_WIN
#include <qwineventnotifier.h>
+#else
+#include <private/qcore_unix_p.h>
#endif
#ifndef QT_NO_PROCESS
@@ -810,8 +812,7 @@ QProcessPrivate::QProcessPrivate()
deathNotifier = 0;
childStartedPipe[0] = INVALID_Q_PIPE;
childStartedPipe[1] = INVALID_Q_PIPE;
- deathPipe[0] = INVALID_Q_PIPE;
- deathPipe[1] = INVALID_Q_PIPE;
+ forkfd = -1;
exitCode = 0;
crashed = false;
dying = false;
@@ -821,9 +822,6 @@ QProcessPrivate::QProcessPrivate()
notifier = 0;
processFinishedNotifier = 0;
#endif // Q_OS_WIN
-#ifdef Q_OS_UNIX
- serial = 0;
-#endif
}
/*!
@@ -890,9 +888,10 @@ void QProcessPrivate::cleanup()
closeChannel(&stderrChannel);
closeChannel(&stdinChannel);
destroyPipe(childStartedPipe);
- destroyPipe(deathPipe);
#ifdef Q_OS_UNIX
- serial = 0;
+ if (forkfd != -1)
+ qt_safe_close(forkfd);
+ forkfd = -1;
#endif
}
diff --git a/src/corelib/io/qprocess_p.h b/src/corelib/io/qprocess_p.h
index 8c5987aa05..3f86960c74 100644
--- a/src/corelib/io/qprocess_p.h
+++ b/src/corelib/io/qprocess_p.h
@@ -62,6 +62,9 @@ typedef HANDLE Q_PIPE;
#else
typedef int Q_PIPE;
#define INVALID_Q_PIPE -1
+# ifdef Q_OS_QNX
+# define QPROCESS_USE_SPAWN
+# endif
#endif
#ifndef QT_NO_PROCESS
@@ -331,12 +334,13 @@ public:
QProcessEnvironment environment;
Q_PIPE childStartedPipe[2];
- Q_PIPE deathPipe[2];
void destroyPipe(Q_PIPE pipe[2]);
QSocketNotifier *startupSocketNotifier;
QSocketNotifier *deathNotifier;
+ int forkfd;
+
#ifdef Q_OS_WIN
// the wonderful windows notifier
QTimer *notifier;
@@ -345,10 +349,10 @@ public:
void start(QIODevice::OpenMode mode);
void startProcess();
-#if defined(Q_OS_UNIX) && !defined(Q_OS_QNX)
+#if defined(Q_OS_UNIX) && !defined(QPROCESS_USE_SPAWN)
void execChild(const char *workingDirectory, char **path, char **argv, char **envp);
-#elif defined(Q_OS_QNX)
- pid_t spawnChild(const char *workingDirectory, char **argv, char **envp);
+#elif defined(QPROCESS_USE_SPAWN)
+ pid_t spawnChild(pid_t *ppid, const char *workingDirectory, char **argv, char **envp);
#endif
bool processStarted();
void terminateProcess();
@@ -369,9 +373,6 @@ public:
int exitCode;
QProcess::ExitStatus exitStatus;
bool crashed;
-#ifdef Q_OS_UNIX
- int serial;
-#endif
bool waitForStarted(int msecs = 30000);
bool waitForReadyRead(int msecs = 30000);
@@ -389,9 +390,6 @@ public:
QList<QSocketNotifier *> defaultNotifiers() const;
#endif // Q_OS_BLACKBERRY
-#ifdef Q_OS_UNIX
- static void initializeProcessManager();
-#endif
};
QT_END_NAMESPACE
diff --git a/src/corelib/io/qprocess_unix.cpp b/src/corelib/io/qprocess_unix.cpp
index cfee5f1d46..d626607dfa 100644
--- a/src/corelib/io/qprocess_unix.cpp
+++ b/src/corelib/io/qprocess_unix.cpp
@@ -95,15 +95,14 @@ QT_END_NAMESPACE
#include <qthread.h>
#include <qelapsedtimer.h>
+#ifdef Q_OS_QNX
+# include <sys/neutrino.h>
+#endif
+
#include <errno.h>
#include <stdlib.h>
#include <string.h>
-#ifdef Q_OS_QNX
-#include "qvarlengtharray.h"
-
-#include <spawn.h>
-#include <sys/neutrino.h>
-#endif
+#include <forkfd.h>
QT_BEGIN_NAMESPACE
@@ -111,38 +110,6 @@ QT_BEGIN_NAMESPACE
// so we will use 512
static const int errorBufferMax = 512;
-static int qt_qprocess_deadChild_pipe[2];
-static struct sigaction qt_sa_old_sigchld_handler;
-static void qt_sa_sigchld_sigaction(int signum, siginfo_t *info, void *context)
-{
- // *Never* use the info or contect variables in this function
- // (except for passing them to the next signal in the chain).
- // We cannot be sure if another library or if the application
- // installed a signal handler for SIGCHLD without SA_SIGINFO
- // and fails to pass the arguments to us. If they do that,
- // these arguments contain garbage and we'd most likely crash.
-
- qt_safe_write(qt_qprocess_deadChild_pipe[1], "", 1);
-#if defined (QPROCESS_DEBUG)
- fprintf(stderr, "*** SIGCHLD\n");
-#endif
-
- // load as volatile
- volatile struct sigaction *vsa = &qt_sa_old_sigchld_handler;
-
- if (qt_sa_old_sigchld_handler.sa_flags & SA_SIGINFO) {
- void (*oldAction)(int, siginfo_t *, void *) = vsa->sa_sigaction;
-
- if (oldAction)
- oldAction(signum, info, context);
- } else {
- void (*oldAction)(int) = vsa->sa_handler;
-
- if (oldAction && oldAction != SIG_IGN)
- oldAction(signum);
- }
-}
-
static inline void add_fd(int &nfds, int fd, fd_set *fdset)
{
FD_SET(fd, fdset);
@@ -150,199 +117,6 @@ static inline void add_fd(int &nfds, int fd, fd_set *fdset)
nfds = fd;
}
-struct QProcessInfo {
- QProcess *process;
- int deathPipe;
- int exitResult;
- pid_t pid;
- int serialNumber;
-};
-
-class QProcessManager : public QThread
-{
- Q_OBJECT
-public:
- QProcessManager();
- ~QProcessManager();
-
- void run() Q_DECL_OVERRIDE;
- void catchDeadChildren();
- void add(pid_t pid, QProcess *process);
- void remove(QProcess *process);
- void lock();
- void unlock();
-
-private:
- QMutex mutex;
- QHash<int, QProcessInfo *> children;
-};
-
-
-static QProcessManager *processManagerInstance = 0;
-
-static QProcessManager *processManager()
-{
- // The constructor of QProcessManager should be called only once
- // so we cannot use Q_GLOBAL_STATIC directly for QProcessManager
- static QBasicMutex processManagerGlobalMutex;
- QMutexLocker locker(&processManagerGlobalMutex);
-
- if (!processManagerInstance)
- new QProcessManager;
-
- Q_ASSERT(processManagerInstance);
- return processManagerInstance;
-}
-
-QProcessManager::QProcessManager()
-{
-#if defined (QPROCESS_DEBUG)
- qDebug() << "QProcessManager::QProcessManager()";
-#endif
- // initialize the dead child pipe and make it non-blocking. in the
- // extremely unlikely event that the pipe fills up, we do not under any
- // circumstances want to block.
- qt_safe_pipe(qt_qprocess_deadChild_pipe, O_NONBLOCK);
-
- // set up the SIGCHLD handler, which writes a single byte to the dead
- // child pipe every time a child dies.
-
- struct sigaction action;
- // use the old handler as template, i.e., preserve the signal mask
- // otherwise the original signal handler might be interrupted although it
- // was marked to never be interrupted
- ::sigaction(SIGCHLD, NULL, &action);
- action.sa_sigaction = qt_sa_sigchld_sigaction;
- // set the SA_SIGINFO flag such that we can use the three argument handler
- // function
- action.sa_flags = SA_NOCLDSTOP | SA_SIGINFO;
- ::sigaction(SIGCHLD, &action, &qt_sa_old_sigchld_handler);
-
- processManagerInstance = this;
-}
-
-QProcessManager::~QProcessManager()
-{
- // notify the thread that we're shutting down.
- qt_safe_write(qt_qprocess_deadChild_pipe[1], "@", 1);
- qt_safe_close(qt_qprocess_deadChild_pipe[1]);
- wait();
-
- // on certain unixes, closing the reading end of the pipe will cause
- // select in run() to block forever, rather than return with EBADF.
- qt_safe_close(qt_qprocess_deadChild_pipe[0]);
-
- qt_qprocess_deadChild_pipe[0] = -1;
- qt_qprocess_deadChild_pipe[1] = -1;
-
- qDeleteAll(children.values());
- children.clear();
-
- struct sigaction currentAction;
- ::sigaction(SIGCHLD, 0, &currentAction);
- if (currentAction.sa_sigaction == qt_sa_sigchld_sigaction) {
- ::sigaction(SIGCHLD, &qt_sa_old_sigchld_handler, 0);
- }
-
- processManagerInstance = 0;
-}
-
-void QProcessManager::run()
-{
- forever {
- fd_set readset;
- FD_ZERO(&readset);
- FD_SET(qt_qprocess_deadChild_pipe[0], &readset);
-
-#if defined (QPROCESS_DEBUG)
- qDebug() << "QProcessManager::run() waiting for children to die";
-#endif
-
- // block forever, or until activity is detected on the dead child
- // pipe. the only other peers are the SIGCHLD signal handler, and the
- // QProcessManager destructor.
- int nselect = select(qt_qprocess_deadChild_pipe[0] + 1, &readset, 0, 0, 0);
- if (nselect < 0) {
- if (errno == EINTR)
- continue;
- break;
- }
-
- // empty only one byte from the pipe, even though several SIGCHLD
- // signals may have been delivered in the meantime, to avoid race
- // conditions.
- char c;
- if (qt_safe_read(qt_qprocess_deadChild_pipe[0], &c, 1) < 0 || c == '@')
- break;
-
- // catch any and all children that we can.
- catchDeadChildren();
- }
-}
-
-void QProcessManager::catchDeadChildren()
-{
- QMutexLocker locker(&mutex);
-
- // try to catch all children whose pid we have registered, and whose
- // deathPipe is still valid (i.e, we have not already notified it).
- QHash<int, QProcessInfo *>::Iterator it = children.begin();
- while (it != children.end()) {
- // notify all children that they may have died. they need to run
- // waitpid() in their own thread.
- QProcessInfo *info = it.value();
- qt_safe_write(info->deathPipe, "", 1);
-
-#if defined (QPROCESS_DEBUG)
- qDebug() << "QProcessManager::run() sending death notice to" << info->process;
-#endif
- ++it;
- }
-}
-
-static QBasicAtomicInt idCounter = Q_BASIC_ATOMIC_INITIALIZER(1);
-
-void QProcessManager::add(pid_t pid, QProcess *process)
-{
-#if defined (QPROCESS_DEBUG)
- qDebug() << "QProcessManager::add() adding pid" << pid << "process" << process;
-#endif
-
- // insert a new info structure for this process
- QProcessInfo *info = new QProcessInfo;
- info->process = process;
- info->deathPipe = process->d_func()->deathPipe[1];
- info->exitResult = 0;
- info->pid = pid;
-
- int serial = idCounter.fetchAndAddRelaxed(1);
- process->d_func()->serial = serial;
- children.insert(serial, info);
-}
-
-void QProcessManager::remove(QProcess *process)
-{
- QMutexLocker locker(&mutex);
-
- int serial = process->d_func()->serial;
- QProcessInfo *info = children.take(serial);
-#if defined (QPROCESS_DEBUG)
- if (info)
- qDebug() << "QProcessManager::remove() removing pid" << info->pid << "process" << info->process;
-#endif
- delete info;
-}
-
-void QProcessManager::lock()
-{
- mutex.lock();
-}
-
-void QProcessManager::unlock()
-{
- mutex.unlock();
-}
-
static int qt_create_pipe(int *pipe)
{
if (pipe[0] != -1)
@@ -562,14 +336,11 @@ void QProcessPrivate::startProcess()
qDebug("QProcessPrivate::startProcess()");
#endif
- processManager()->start();
-
// Initialize pipes
if (!openChannel(stdinChannel) ||
!openChannel(stdoutChannel) ||
!openChannel(stderrChannel) ||
- qt_create_pipe(childStartedPipe) != 0 ||
- qt_create_pipe(deathPipe) != 0) {
+ qt_create_pipe(childStartedPipe) != 0) {
processError = QProcess::FailedToStart;
q->setErrorString(qt_error_string(errno));
emit q->error(processError);
@@ -582,11 +353,6 @@ void QProcessPrivate::startProcess()
QSocketNotifier::Read, q);
QObject::connect(startupSocketNotifier, SIGNAL(activated(int)),
q, SLOT(_q_startupNotification()));
-
- deathNotifier = new QSocketNotifier(deathPipe[0],
- QSocketNotifier::Read, q);
- QObject::connect(deathNotifier, SIGNAL(activated(int)),
- q, SLOT(_q_processDied()));
}
// Start the process (platform dependent)
@@ -669,14 +435,17 @@ void QProcessPrivate::startProcess()
}
// Start the process manager, and fork off the child process.
- processManager()->lock();
-#if defined(Q_OS_QNX)
- pid_t childPid = spawnChild(workingDirPtr, argv, envp);
+#if defined(QPROCESS_USE_SPAWN)
+ pid_t childPid;
+ forkfd = spawnChild(&childPid, workingDirPtr, argv, envp);
+ Q_ASSUME(forkfd != FFD_CHILD_PROCESS);
#else
- pid_t childPid = fork();
- int lastForkErrno = errno;
+ pid_t childPid;
+ forkfd = ::forkfd(FFD_CLOEXEC, &childPid);
#endif
- if (childPid != 0) {
+ int lastForkErrno = errno;
+ if (forkfd != FFD_CHILD_PROCESS) {
+ // Parent process.
// Clean up duplicated memory.
free(dupProgramName);
for (int i = 1; i <= arguments.count(); ++i)
@@ -690,23 +459,15 @@ void QProcessPrivate::startProcess()
delete [] path;
}
- // This is not a valid check under QNX, because the semantics are
- // different. While under other platforms where fork() may succeed and exec() can still fail,
- // causing the childPid to hold a valid value (and thus evaluating the
- // following if to false), and then signaling the error via
- // childStartedPipe, under QNX on the other hand, spawn() return value will be assigned
- // to childPid (which will be -1 in case of failure). This will force
- // QProcess to cleanup, instead of signaling the error via
- // childStartedPipe. Since it will invalidade the pipes, functions like
- // QProcess::waitForStarted() will fail, for childStartedPipe will be
- // '-1' and mess with the select() calls.
-#if !defined(Q_OS_QNX)
- if (childPid < 0) {
+ // On QNX, if spawnChild failed, childPid will be -1 but forkfd is still 0.
+ // This is intentional because we only want to handle failure to fork()
+ // here, which is a rare occurrence. Handling of the failure to start is
+ // done elsewhere.
+ if (forkfd == -1) {
// Cleanup, report error and return
#if defined (QPROCESS_DEBUG)
qDebug("fork failed: %s", qPrintable(qt_error_string(lastForkErrno)));
#endif
- processManager()->unlock();
q->setProcessState(QProcess::NotRunning);
processError = QProcess::FailedToStart;
q->setErrorString(QProcess::tr("Resource error (fork failure): %1").arg(qt_error_string(lastForkErrno)));
@@ -716,21 +477,17 @@ void QProcessPrivate::startProcess()
}
// Start the child.
- if (childPid == 0) {
+#if !defined(QPROCESS_USE_SPAWN)
+ if (forkfd == FFD_CHILD_PROCESS) {
execChild(workingDirPtr, path, argv, envp);
::_exit(-1);
}
#endif
- // Register the child. In the mean time, we can get a SIGCHLD, so we need
- // to keep the lock held to avoid a race to catch the child.
- processManager()->add(childPid, q);
pid = Q_PID(childPid);
- processManager()->unlock();
// parent
// close the ends we don't use and make all pipes non-blocking
- ::fcntl(deathPipe[0], F_SETFL, ::fcntl(deathPipe[0], F_GETFL) | O_NONBLOCK);
qt_safe_close(childStartedPipe[1]);
childStartedPipe[1] = -1;
@@ -756,110 +513,117 @@ void QProcessPrivate::startProcess()
}
if (stderrChannel.pipe[0] != -1)
::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
+
+ if (threadData->eventDispatcher) {
+ deathNotifier = new QSocketNotifier(forkfd, QSocketNotifier::Read, q);
+ QObject::connect(deathNotifier, SIGNAL(activated(int)),
+ q, SLOT(_q_processDied()));
+ }
}
-#if defined(Q_OS_QNX)
-static pid_t doSpawn(int fd_count, int fd_map[], char **argv, char **envp,
- const char *workingDir, bool spawn_detached)
+#if defined(QPROCESS_USE_SPAWN)
+static int doSpawn(pid_t *ppid, const posix_spawn_file_actions_t *file_actions,
+ char **argv, char **envp, const char *workingDir, bool spawn_detached)
{
- // A multi threaded QNX Process can't fork so we call spawn() instead.
-
- struct inheritance inherit;
- memset(&inherit, 0, sizeof(inherit));
- inherit.flags |= SPAWN_SETSID;
- inherit.flags |= SPAWN_CHECK_SCRIPT;
- if (spawn_detached)
- inherit.flags |= SPAWN_NOZOMBIE;
- inherit.flags |= SPAWN_SETSIGDEF;
- sigaddset(&inherit.sigdefault, SIGPIPE); // reset the signal that we ignored
+ // A multi threaded QNX Process can't fork so we call spawnfd() instead.
+ posix_spawnattr_t attr;
+ posix_spawnattr_init(&attr);
+# ifdef Q_OS_QNX
+ posix_spawnattr_setxflags(&attr, POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETPGROUP
+ | (spawn_detached * POSIX_SPAWN_NOZOMBIE));
+# else
+ posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETPGROUP);
+# endif
+ posix_spawnattr_setpgroup(&attr, 0);
+
+ sigset_t sigdefault;
+ sigemptyset(&sigdefault);
+ sigaddset(&sigdefault, SIGPIPE); // reset the signal that we ignored
+ posix_spawnattr_setsigdefault(&attr, &sigdefault);
// enter the working directory
const char *oldWorkingDir = 0;
char buff[PATH_MAX + 1];
if (workingDir) {
+# ifdef Q_OS_QNX
//we need to freeze everyone in order to avoid race conditions with //chdir().
if (ThreadCtl(_NTO_TCTL_THREADS_HOLD, 0) == -1)
qWarning("ThreadCtl(): cannot hold threads: %s", qPrintable(qt_error_string(errno)));
+# endif
oldWorkingDir = QT_GETCWD(buff, PATH_MAX + 1);
if (QT_CHDIR(workingDir) == -1)
qWarning("ThreadCtl(): failed to chdir to %s", workingDir);
}
- pid_t childPid;
- EINTR_LOOP(childPid, ::spawn(argv[0], fd_count, fd_map, &inherit, argv, envp));
- if (childPid == -1) {
- inherit.flags |= SPAWN_SEARCH_PATH;
- EINTR_LOOP(childPid, ::spawn(argv[0], fd_count, fd_map, &inherit, argv, envp));
+ int fd;
+ if (spawn_detached) {
+ fd = ::posix_spawn(ppid, argv[0], file_actions, &attr, argv, envp);
+ if (fd == -1) {
+ fd = ::posix_spawnp(ppid, argv[0], file_actions, &attr, argv, envp);
+ }
+ } else {
+ // use spawnfd
+ fd = ::spawnfd(FFD_CLOEXEC | FFD_NONBLOCK, ppid, argv[0], file_actions, &attr, argv, envp);
+ if (fd == -1) {
+ fd = ::spawnfd(FFD_CLOEXEC | FFD_NONBLOCK | FFD_SPAWN_SEARCH_PATH, ppid, argv[0], file_actions,
+ &attr, argv, envp);
+ }
}
if (oldWorkingDir) {
if (QT_CHDIR(oldWorkingDir) == -1)
qWarning("ThreadCtl(): failed to chdir to %s", oldWorkingDir);
+# ifdef Q_OS_QNX
if (ThreadCtl(_NTO_TCTL_THREADS_CONT, 0) == -1)
qFatal("ThreadCtl(): cannot resume threads: %s", qPrintable(qt_error_string(errno)));
+# endif
}
- return childPid;
+ posix_spawnattr_destroy(&attr);
+ return fd;
}
-pid_t QProcessPrivate::spawnChild(const char *workingDir, char **argv, char **envp)
+pid_t QProcessPrivate::spawnChild(pid_t *ppid, const char *workingDir, char **argv, char **envp)
{
- // we need to manually fill in fd_map
- // to inherit the file descriptors from
- // the parent
- const int fd_count = sysconf(_SC_OPEN_MAX);
- QVarLengthArray<int, 1024> fd_map(fd_count);
-
- for (int i = 3; i < fd_count; ++i) {
- // here we rely that fcntl returns -1 and
- // sets errno to EBADF
- const int flags = ::fcntl(i, F_GETFD);
-
- fd_map[i] = ((flags >= 0) && !(flags & FD_CLOEXEC))
- ? i : SPAWN_FDCLOSED;
+ // posix_spawn causes all file descriptors with FD_CLOEXEC to be closed automatically;
+ // we only need to add the actions for our own pipes
+ posix_spawn_file_actions_t file_actions;
+ posix_spawn_file_actions_init(&file_actions);
+
+ if (processChannelMode == QProcess::MergedChannels) {
+ // managed stderr == stdout
+ posix_spawn_file_actions_adddup2(&file_actions, stdoutChannel.pipe[1], STDERR_FILENO);
+ } else if (processChannelMode != QProcess::ForwardedChannels && processChannelMode != QProcess::ForwardedErrorChannel) {
+ // managed stderr
+ posix_spawn_file_actions_adddup2(&file_actions, stderrChannel.pipe[1], STDERR_FILENO);
+ posix_spawn_file_actions_addclose(&file_actions, stderrChannel.pipe[1]);
+ }
+
+ if (processChannelMode != QProcess::ForwardedChannels && processChannelMode != QProcess::ForwardedOutputChannel) {
+ // managed stdout
+ posix_spawn_file_actions_adddup2(&file_actions, stdoutChannel.pipe[1], STDOUT_FILENO);
+ posix_spawn_file_actions_addclose(&file_actions, stdoutChannel.pipe[1]);
}
- if (inputChannelMode == QProcess::ManagedInputChannel)
- fd_map[0] = stdinChannel.pipe[0];
- else
- fd_map[0] = QT_FILENO(stdin);
-
- switch (processChannelMode) {
- case QProcess::ForwardedChannels:
- fd_map[1] = QT_FILENO(stdout);
- fd_map[2] = QT_FILENO(stderr);
- break;
- case QProcess::ForwardedOutputChannel:
- fd_map[1] = QT_FILENO(stdout);
- fd_map[2] = stderrChannel.pipe[1];
- break;
- case QProcess::ForwardedErrorChannel:
- fd_map[1] = stdoutChannel.pipe[1];
- fd_map[2] = QT_FILENO(stderr);
- break;
- case QProcess::MergedChannels:
- fd_map[1] = stdoutChannel.pipe[1];
- fd_map[2] = stdoutChannel.pipe[1];
- break;
- case QProcess::SeparateChannels:
- fd_map[1] = stdoutChannel.pipe[1];
- fd_map[2] = stderrChannel.pipe[1];
- break;
+ if (inputChannelMode == QProcess::ManagedInputChannel) {
+ posix_spawn_file_actions_adddup2(&file_actions, stdinChannel.pipe[0], STDIN_FILENO);
+ posix_spawn_file_actions_addclose(&file_actions, stdinChannel.pipe[0]);
}
- pid_t childPid = doSpawn(fd_count, fd_map.data(), argv, envp, workingDir, false);
+ int retval = doSpawn(ppid, &file_actions, argv, envp, workingDir, false);
- if (childPid == -1) {
+ if (retval == -1) {
QString error = qt_error_string(errno);
qt_safe_write(childStartedPipe[1], error.data(), error.length() * sizeof(QChar));
qt_safe_close(childStartedPipe[1]);
childStartedPipe[1] = -1;
}
- return childPid;
+ posix_spawn_file_actions_destroy(&file_actions);
+ return retval;
}
#else
@@ -1092,8 +856,8 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
- int nfds = deathPipe[0];
- FD_SET(deathPipe[0], &fdread);
+ int nfds = forkfd;
+ FD_SET(forkfd, &fdread);
if (processState == QProcess::Starting)
add_fd(nfds, childStartedPipe[0], &fdread);
@@ -1143,7 +907,7 @@ bool QProcessPrivate::waitForReadyRead(int msecs)
if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
_q_canWrite();
- if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
+ if (forkfd == -1 || FD_ISSET(forkfd, &fdread)) {
if (_q_processDied())
return false;
}
@@ -1172,8 +936,8 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
- int nfds = deathPipe[0];
- FD_SET(deathPipe[0], &fdread);
+ int nfds = forkfd;
+ FD_SET(forkfd, &fdread);
if (processState == QProcess::Starting)
add_fd(nfds, childStartedPipe[0], &fdread);
@@ -1217,7 +981,7 @@ bool QProcessPrivate::waitForBytesWritten(int msecs)
if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
_q_canReadStandardError();
- if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
+ if (forkfd == -1 || FD_ISSET(forkfd, &fdread)) {
if (_q_processDied())
return false;
}
@@ -1256,8 +1020,8 @@ bool QProcessPrivate::waitForFinished(int msecs)
if (stderrChannel.pipe[0] != -1)
add_fd(nfds, stderrChannel.pipe[0], &fdread);
- if (processState == QProcess::Running)
- add_fd(nfds, deathPipe[0], &fdread);
+ if (processState == QProcess::Running && forkfd != -1)
+ add_fd(nfds, forkfd, &fdread);
if (!stdinChannel.buffer.isEmpty() && stdinChannel.pipe[1] != -1)
add_fd(nfds, stdinChannel.pipe[1], &fdwrite);
@@ -1290,7 +1054,7 @@ bool QProcessPrivate::waitForFinished(int msecs)
if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
_q_canReadStandardError();
- if (deathPipe[0] == -1 || FD_ISSET(deathPipe[0], &fdread)) {
+ if (forkfd == -1 || FD_ISSET(forkfd, &fdread)) {
if (_q_processDied())
return true;
}
@@ -1308,46 +1072,41 @@ bool QProcessPrivate::waitForWrite(int msecs)
void QProcessPrivate::findExitCode()
{
- Q_Q(QProcess);
- processManager()->remove(q);
}
bool QProcessPrivate::waitForDeadChild()
{
- Q_Q(QProcess);
+ if (forkfd == -1)
+ return true; // child has already exited
- // read a byte from the death pipe
- char c;
- qt_safe_read(deathPipe[0], &c, 1);
+ // read the process information from our fd
+ siginfo_t info;
+ qint64 ret = qt_safe_read(forkfd, &info, sizeof info);
+ Q_ASSERT(ret == sizeof info);
+ Q_UNUSED(ret);
+
+ Q_ASSERT(info.si_pid == pid_t(pid));
+
+ exitCode = info.si_status;
+ crashed = info.si_code != CLD_EXITED;
+
+ qt_safe_close(forkfd);
+ forkfd = -1; // Child is dead, don't try to kill it anymore
- // check if our process is dead
- int exitStatus;
- if (qt_safe_waitpid(pid_t(pid), &exitStatus, WNOHANG) > 0) {
- processManager()->remove(q);
- crashed = !WIFEXITED(exitStatus);
- exitCode = WEXITSTATUS(exitStatus);
-#if defined QPROCESS_DEBUG
- qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode"
- << exitCode << ", crashed?" << crashed;
-#endif
- return true;
- }
#if defined QPROCESS_DEBUG
- qDebug() << "QProcessPrivate::waitForDeadChild() not dead!";
+ qDebug() << "QProcessPrivate::waitForDeadChild() dead with exitCode"
+ << exitCode << ", crashed?" << crashed;
#endif
- return false;
+ return true;
}
void QProcessPrivate::_q_notified()
{
}
-#if defined(Q_OS_QNX)
+#if defined(QPROCESS_USE_SPAWN)
bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
{
- const int fd_count = 3;
- int fd_map[fd_count] = { QT_FILENO(stdin), QT_FILENO(stdout), QT_FILENO(stderr) };
-
QList<QByteArray> enc_args;
enc_args.append(QFile::encodeName(program));
for (int i = 0; i < arguments.size(); ++i)
@@ -1369,19 +1128,18 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
workingDirPtr = encodedWorkingDirectory.constData();
}
- pid_t childPid = doSpawn(fd_count, fd_map, raw_argv.data(), envp, workingDirPtr, true);
- if (pid && childPid != -1)
+ pid_t childPid;
+ int retval = doSpawn(&childPid, NULL, raw_argv.data(), envp, workingDirPtr, true);
+ if (pid && retval != -1)
*pid = childPid;
- return childPid != -1;
+ return retval != -1;
}
#else
bool QProcessPrivate::startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory, qint64 *pid)
{
- processManager()->start();
-
QByteArray encodedWorkingDirectory = QFile::encodeName(workingDirectory);
// To catch the startup of the child
@@ -1496,13 +1254,6 @@ bool QProcessPrivate::startDetached(const QString &program, const QStringList &a
}
#endif
-void QProcessPrivate::initializeProcessManager()
-{
- (void) processManager();
-}
-
QT_END_NAMESPACE
-#include "qprocess_unix.moc"
-
#endif // QT_NO_PROCESS