Index: /trunk/src/corelib/io/qprocess.cpp
===================================================================
--- /trunk/src/corelib/io/qprocess.cpp	(revision 189)
+++ /trunk/src/corelib/io/qprocess.cpp	(revision 190)
@@ -437,4 +437,7 @@
     serial = 0;
 #endif
+#ifdef Q_OS_OS2
+    init();
+#endif
 }
 
@@ -443,4 +446,7 @@
 QProcessPrivate::~QProcessPrivate()
 {
+#ifdef Q_OS_OS2
+    uninit();
+#endif
     if (stdinChannel.process)
         stdinChannel.process->stdoutChannel.clear();
@@ -744,5 +750,5 @@
     processError = QProcess::FailedToStart;
     emit q->error(processError);
-#ifdef Q_OS_UNIX
+#if defined(Q_OS_UNIX) || defined(Q_OS_OS2)
     // make sure the process manager removes this entry
     waitForDeadChild();
@@ -801,5 +807,5 @@
         waitForFinished();
     }
-#ifdef Q_OS_UNIX
+#if defined(Q_OS_UNIX) || defined(Q_OS_OS2)
     // make sure the process manager removes this entry
     d->findExitCode();
Index: /trunk/src/corelib/io/qprocess_os2.cpp
===================================================================
--- /trunk/src/corelib/io/qprocess_os2.cpp	(revision 189)
+++ /trunk/src/corelib/io/qprocess_os2.cpp	(revision 190)
@@ -51,4 +51,6 @@
 #include <ctype.h>
 
+#include <qthread.h>
+
 /*
     Returns a human readable representation of the first \a len
@@ -122,4 +124,237 @@
     ::fcntl(pipe[0], F_SETFD, FD_CLOEXEC);
     ::fcntl(pipe[1], F_SETFD, FD_CLOEXEC);
+}
+
+
+class QProcessManager : public QThread
+{
+public:
+
+    static void addRef();
+    static void release();
+
+    static void addProcess(QProcess *process);
+    static void removeProcess(QProcess *process);
+
+private:
+
+    QProcessManager();
+    ~QProcessManager();
+
+    void installSigHandler();
+    void uninstallSigHandler();
+    void run();
+
+    int refcnt;
+    bool finish;
+
+    HEV eventSem;
+    QAtomicInt eventSemGuard;
+
+    typedef QList<QProcess *> ProcessList;
+    ProcessList processes;
+
+    void (*sa_old_sigchld_handler)(int);
+
+    static void sa_sigchld_handler(int signum);
+
+    static QProcessManager *instance;
+    static QMutex mutex;
+};
+
+// static
+QProcessManager *QProcessManager::instance = 0;
+QMutex QProcessManager::mutex;
+
+// static
+void QProcessManager::sa_sigchld_handler(int signum)
+{
+#if defined (QPROCESS_DEBUG)
+    fprintf(stderr, "*** SIGCHLD\n");
+#endif
+
+    Q_ASSERT(instance);
+
+    // eventSemGuard is used as follows:
+    // 0 - QProcessManager is not operational
+    // 1 - QProcessManager is being run, eventSem is fine
+    // 2 - another signal handler is in action
+
+    if (!instance->eventSemGuard.testAndSetAcquire(1, 2))
+        return;
+
+    APIRET rc = DosPostEventSem(instance->eventSem);
+    Q_ASSERT(rc == NO_ERROR);
+
+    instance->eventSemGuard.testAndSetRelease(2, 1);
+
+    if (instance->sa_old_sigchld_handler &&
+        instance->sa_old_sigchld_handler != SIG_IGN)
+        instance->sa_old_sigchld_handler(signum);
+}
+
+// static
+void QProcessManager::addRef()
+{
+    QMutexLocker locker(&mutex);
+
+    if (instance == 0) {
+        instance = new QProcessManager();
+    }
+
+    ++instance->refcnt;
+}
+
+// static
+void QProcessManager::release()
+{
+    QMutexLocker locker(&mutex);
+
+    Q_ASSERT(instance);
+
+    if (--instance->refcnt == 0) {
+        // make sure we don't globally exist anymore before leaving the lock
+        QProcessManager *instance = QProcessManager::instance;
+        QProcessManager::instance = 0;
+        // disable the signal handler
+        while (!instance->eventSemGuard.testAndSetAcquire(1, 0))
+            DosSleep(0);
+        instance->uninstallSigHandler();
+        // stop the thread
+        instance->finish = true;
+        locker.unlock();
+        DosPostEventSem(instance->eventSem);
+        instance->wait();
+        delete instance;
+    }
+}
+
+// static
+void QProcessManager::addProcess(QProcess *process)
+{
+#if defined (QPROCESS_DEBUG)
+    qDebug() << "QProcessManager::addProcess()";
+#endif
+
+    QMutexLocker locker(&mutex);
+    Q_ASSERT(instance);
+
+    // lazily enable SIGCHLD handler and start the worker
+    if (instance->eventSemGuard.testAndSetAcquire(0, 1)) {
+        instance->installSigHandler();
+        instance->start();
+    }
+
+    instance->processes.append(process);
+}
+
+// static
+void QProcessManager::removeProcess(QProcess *process)
+{
+#if defined (QPROCESS_DEBUG)
+    qDebug() << "QProcessManager::removeProcess()";
+#endif
+
+    QMutexLocker locker(&mutex);
+    Q_ASSERT(instance);
+
+    instance->processes.removeAll(process);
+}
+
+QProcessManager::QProcessManager()
+    : refcnt(0), finish(false), eventSem(NULLHANDLE), sa_old_sigchld_handler(0)
+{
+#if defined (QPROCESS_DEBUG)
+    qDebug() << "QProcessManager::QProcessManager()";
+#endif
+
+    APIRET rc = DosCreateEventSem(NULL, &eventSem, DCE_AUTORESET | DCE_POSTONE, FALSE);
+    Q_ASSERT(rc == NO_ERROR);
+}
+
+QProcessManager::~QProcessManager()
+{
+#if defined (QPROCESS_DEBUG)
+    qDebug() << "QProcessManager::~QProcessManager()";
+#endif
+
+    Q_ASSERT(!refcnt);
+    Q_ASSERT(!processes.size());
+
+    DosCloseEventSem(eventSem);
+}
+
+void QProcessManager::installSigHandler()
+{
+    // set up the SIGCHLD handler, which calls _q_processDied on all
+    // known QProcessPrivate instances every time a child dies.
+    struct sigaction oldAction;
+    struct sigaction action;
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = sa_sigchld_handler;
+    action.sa_flags = SA_NOCLDSTOP;
+    ::sigaction(SIGCHLD, &action, &oldAction);
+    if (oldAction.sa_handler != sa_sigchld_handler)
+    sa_old_sigchld_handler = oldAction.sa_handler;
+}
+
+void QProcessManager::uninstallSigHandler()
+{
+    struct sigaction oldAction;
+    struct sigaction action;
+    memset(&action, 0, sizeof(action));
+    action.sa_handler = sa_old_sigchld_handler;
+    action.sa_flags = SA_NOCLDSTOP;
+    ::sigaction(SIGCHLD, &action, &oldAction);
+    if (oldAction.sa_handler != sa_sigchld_handler) {
+        ::sigaction(SIGCHLD, &oldAction, 0);
+    }
+}
+
+void QProcessManager::run()
+{
+#if defined (QPROCESS_DEBUG)
+    qDebug() << "QProcessManager::run() BEGIN";
+#endif
+
+    // Note: the rationale behind using a worker thread so far is that
+    // calling complex functions from a signal handler is not really a good
+    // idea unless there is a 100% guarantee that they are reentrant. So, the
+    // handler only posts a semaphore (I *hope* DosPostEventSem is reentrant)
+    // and all complex work is done here asynchronously.
+
+    QMutexLocker locker(&mutex);
+    APIRET arc;
+
+    do {
+        locker.unlock();
+        arc = DosWaitEventSem(eventSem, SEM_INDEFINITE_WAIT);
+        locker.relock();
+        if (finish)
+            break;
+
+#if defined (QPROCESS_DEBUG)
+    qDebug() << "QProcessManager::run() signaled";
+#endif
+        foreach (QProcess *proc, processes) {
+            QMetaObject::invokeMethod(proc, "_q_processDied", Qt::QueuedConnection);
+        }
+
+    } while (true);
+
+#if defined (QPROCESS_DEBUG)
+    qDebug() << "QProcessManager::run() END";
+#endif
+}
+
+
+void QProcessPrivate::init()
+{
+    QProcessManager::addRef();
+}
+
+void QProcessPrivate::uninit()
+{
+    QProcessManager::release();
 }
 
@@ -372,4 +607,6 @@
         return;
 
+    QProcessManager::addProcess(q);
+
     // Start the process (platform dependent)
     q->setProcessState(QProcess::Starting);
@@ -424,4 +661,5 @@
                                        .arg(qPrintable(qt_error_string(errno))));
         emit q->error(processError);
+        removeProcess(q);
         cleanup();
         return;
@@ -452,12 +690,7 @@
         ::fcntl(stderrChannel.pipe[0], F_SETFL, ::fcntl(stderrChannel.pipe[0], F_GETFL) | O_NONBLOCK);
 
-    q->setProcessState(QProcess::Running);
-    // User can call kill()/terminate() from the stateChanged() slot
-    // so check before proceeding
-    if (!pid)
-        return;
-
     // give the process a chance to start ...
     DosSleep(100);
+
     _q_startupNotification();
 }
@@ -465,5 +698,7 @@
 bool QProcessPrivate::processStarted()
 {
-    return processState == QProcess::Running;
+    // we don't actually wait for any notification from the child process
+    // assuming it has been started as long as spawnvpe() returns success
+    return processState == QProcess::Starting;
 }
 
@@ -589,5 +824,5 @@
     Q_Q(QProcess);
 
-    if (processStarted())
+    if (processState == QProcess::Running)
         return true;
 
@@ -820,4 +1055,12 @@
 void QProcessPrivate::findExitCode()
 {
+    // note: this method is unconditionally called from QProcess destructor
+    // to make sure the process manager removes the watcher even in such a rare
+    // case when the process is still running after killing it and waiting
+    // for termination (in which case the child termination code path that
+    // normally calls findExitCode() won't be walked)
+
+    Q_Q(QProcess);
+    QProcessManager::removeProcess(q);
 }
 
@@ -838,4 +1081,6 @@
 #if defined QPROCESS_DEBUG
     qDebug() << "QProcessPrivate::waitForDeadChild() not dead!";
+    if (waitResult == -1)
+        qDebug() << "QProcessPrivate::waitForDeadChild()" << strerror(errno);
 #endif
     return false;
Index: /trunk/src/corelib/io/qprocess_p.h
===================================================================
--- /trunk/src/corelib/io/qprocess_p.h	(revision 189)
+++ /trunk/src/corelib/io/qprocess_p.h	(revision 190)
@@ -195,4 +195,8 @@
     qint64 pipeWriterBytesToWrite() const;
 #endif
+#ifdef Q_OS_OS2
+    void init();
+    void uninit();
+#endif
 
     static bool startDetached(const QString &program, const QStringList &arguments, const QString &workingDirectory = QString(),
