Changeset 197 for trunk/src/corelib


Ignore:
Timestamp:
Oct 3, 2009, 2:34:36 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

corelib: Reimplemented QProcess to use native pipes for redirection.

Location:
trunk/src/corelib/io
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/corelib/io/qprocess.cpp

    r190 r197  
    421421    notifier = 0;
    422422    pipeWriter = 0;
     423
    423424    childStartedPipe[0] = INVALID_Q_PIPE;
    424425    childStartedPipe[1] = INVALID_Q_PIPE;
    425426    deathPipe[0] = INVALID_Q_PIPE;
    426427    deathPipe[1] = INVALID_Q_PIPE;
     428
    427429    exitCode = 0;
    428430    crashed = false;
     
    510512    destroyPipe(stderrChannel.pipe);
    511513    destroyPipe(stdinChannel.pipe);
     514
    512515    destroyPipe(childStartedPipe);
    513516    destroyPipe(deathPipe);
     517
    514518#ifdef Q_OS_UNIX
    515519    serial = 0;
  • trunk/src/corelib/io/qprocess_os2.cpp

    r195 r197  
    9797#include <qfile.h>
    9898#include <qfileinfo.h>
    99 #include <qlist.h>
    100 #include <qmap.h>
     99#include <qhash.h>
    101100#include <qmutex.h>
    102 #include <qsemaphore.h>
    103 #include <qsocketnotifier.h>
    104101#include <qdir.h>
    105102
    106 #include <errno.h>
    107 #include <sys/filio.h>
    108 #include <sys/socket.h> // socketpair
     103#
     104#
     105#
    109106
    110107QT_BEGIN_NAMESPACE
    111108
    112 static void qt_create_pipe(int *pipe)
    113 {
    114     if (pipe[0] != -1)
    115         ::close(pipe[0]);
    116     if (pipe[1] != -1)
    117         ::close(pipe[1]);
    118     // Note: with kLIBC 0.6.3 and earlier (GCC 3.3.5 CSD3), fds created with
    119     // pipe() cannot be used in select(), so use socketpair() instead
    120     if (::socketpair(AF_OS2, SOCK_STREAM, 0, pipe) != 0) {
    121         qWarning("QProcessPrivate::createPipe: ::socketpair() failed with '%s'",
    122                  qPrintable(qt_error_string(errno)));
    123     }
    124     ::fcntl(pipe[0], F_SETFD, FD_CLOEXEC);
    125     ::fcntl(pipe[1], F_SETFD, FD_CLOEXEC);
    126 }
    127 
     109enum
     110{
     111    PIPE_SIZE_STDIN = 65520, // max
     112    PIPE_SIZE_STDOUT = 65520, // max
     113    PIPE_SIZE_STDERR = 4096,
     114};
    128115
    129116class QProcessManager : public QThread
    130117{
    131118public:
     119
     120
    132121
    133122    static void addRef();
    134123    static void release();
    135124
    136     static void addProcess(QProcess *process);
    137     static void removeProcess(QProcess *process);
     125    static USHORT addProcess(QProcess *process);
     126    static void removeProcess(USHORT procKey);
     127
     128    static QMutex *mutex() { return &mtx; }
    138129
    139130private:
     
    151142    HEV eventSem;
    152143    QAtomicInt eventSemGuard;
    153 
    154     typedef QList<QProcess *> ProcessList;
     144    QAtomicInt deathFlag;
     145
     146    typedef QHash<USHORT, QProcess *> ProcessList;
    155147    ProcessList processes;
     148
    156149
    157150    void (*sa_old_sigchld_handler)(int);
     
    159152    static void sa_sigchld_handler(int signum);
    160153
     154
     155
     156
     157
     158
     159
     160
     161
     162
    161163    static QProcessManager *instance;
    162     static QMutex mutex;
     164    static QMutex mx;
    163165};
    164166
    165167// static
    166168QProcessManager *QProcessManager::instance = 0;
    167 QMutex QProcessManager::mutex;
     169QMutex QProcessManager::mx;
    168170
    169171// static
     
    184186        return;
    185187
    186     APIRET rc = DosPostEventSem(instance->eventSem);
    187     Q_ASSERT(rc == NO_ERROR);
     188    // set deathEvent to 1 and post the semaphore if not already done so
     189    if (instance->deathFlag.testAndSetRelaxed(0, 1)) {
     190        APIRET rc = DosPostEventSem(instance->eventSem);
     191        Q_ASSERT(rc == NO_ERROR || rc == ERROR_ALREADY_POSTED);
     192    }
    188193
    189194    instance->eventSemGuard.testAndSetRelease(2, 1);
     
    197202void QProcessManager::addRef()
    198203{
    199     QMutexLocker locker(&mutex);
     204    QMutexLocker locker();
    200205
    201206    if (instance == 0) {
     
    209214void QProcessManager::release()
    210215{
    211     QMutexLocker locker(&mutex);
     216    QMutexLocker locker();
    212217
    213218    Q_ASSERT(instance);
     
    234239
    235240// static
    236 void QProcessManager::addProcess(QProcess *process)
    237 {
    238 #if defined (QPROCESS_DEBUG)
    239     qDebug() << "QProcessManager::addProcess()";
    240 #endif
    241 
    242     QMutexLocker locker(&mutex);
     241 QProcessManager::addProcess(QProcess *process)
     242{
     243#if defined (QPROCESS_DEBUG)
     244    qDebug(;
     245#endif
     246
     247    QMutexLocker locker();
    243248    Q_ASSERT(instance);
    244249
     
    249254    }
    250255
    251     instance->processes.append(process);
     256    USHORT procKey = instance->lastProcKey + 1;
     257    if (procKey > MaxProcKey) {
     258        // limit reached, find an unused number
     259        procKey = 0;
     260        while (++procKey <= MaxProcKey &&
     261               instance->processes.contains(procKey));
     262        Q_ASSERT(procKey <= MaxProcKey);
     263        if (procKey > MaxProcKey) {
     264            // oops, no more free keys!
     265            process->setErrorString(QString("Internal error: Too many processes"));
     266            return InvalidProcKey;
     267        }
     268    } else {
     269        instance->lastProcKey = procKey;
     270    }
     271
     272    // attach the semahpore to the pipes of the process
     273    APIRET arc = NO_ERROR;
     274    QProcessPrivate *d = process->d_func();
     275    if (d->stdinChannel.pipe.server != HPIPE(~0)) {
     276        arc = DosSetNPipeSem(d->stdinChannel.pipe.server, (HSEM)instance->eventSem,
     277                             toPipeKey(procKey, QProcessPrivate::InPipe));
     278    }
     279    if (arc == NO_ERROR && d->stdoutChannel.pipe.server != HPIPE(~0)) {
     280        arc = DosSetNPipeSem(d->stdoutChannel.pipe.server, (HSEM)instance->eventSem,
     281                             toPipeKey(procKey, QProcessPrivate::OutPipe));
     282    }
     283    if (arc == NO_ERROR && d->stderrChannel.pipe.server != HPIPE(~0)) {
     284        arc = DosSetNPipeSem(d->stderrChannel.pipe.server, (HSEM)instance->eventSem,
     285                             toPipeKey(procKey, QProcessPrivate::ErrPipe));
     286    }
     287    if (arc != NO_ERROR) {
     288        process->setErrorString(QProcess::tr("Internal error: DOS error %1")
     289                                .arg(arc));
     290        if (procKey == instance->lastProcKey)
     291            --instance->lastProcKey;
     292        return InvalidProcKey;
     293    }
     294
     295    instance->processes[procKey] = process;
     296
     297    return procKey;
    252298}
    253299
    254300// static
    255 void QProcessManager::removeProcess(QProcess *process)
    256 {
    257 #if defined (QPROCESS_DEBUG)
    258     qDebug() << "QProcessManager::removeProcess()";
    259 #endif
    260 
    261     QMutexLocker locker(&mutex);
     301void QProcessManager::removeProcess(USHORT procKey)
     302{
     303    QMutexLocker locker(mutex());
    262304    Q_ASSERT(instance);
    263305
    264     instance->processes.removeAll(process);
     306    Q_ASSERT(instance->processes.contains(procKey));
     307    QProcess *process = instance->processes[procKey];
     308
     309#if defined (QPROCESS_DEBUG)
     310    qDebug("QProcessManager::removeProcess(%p)", process);
     311#endif
     312
     313    // to guarantee that the given procKey may be reused, we must close all
     314    // pipes in order to ensure that we won't get late NPSS_CLOSE for the
     315    // removed process that may be already associated with a different process
     316    QProcessPrivate *d = process->d_func();
     317    d->destroyPipe(d->stdinChannel.pipe);
     318    d->destroyPipe(d->stdoutChannel.pipe);
     319    d->destroyPipe(d->stderrChannel.pipe);
     320
     321    instance->processes.remove(procKey);
     322
     323    // small optimization: released the highest key
     324    if (procKey == instance->lastProcKey)
     325        --instance->lastProcKey;
    265326}
    266327
     
    272333#endif
    273334
    274     APIRET rc = DosCreateEventSem(NULL, &eventSem, DCE_AUTORESET | DCE_POSTONE, FALSE);
     335    APIRET rc = DosCreateEventSem(NULL, &eventSem,
     336                                  DC_SEM_SHARED | DCE_AUTORESET | DCE_POSTONE,
     337                                  FALSE);
    275338    Q_ASSERT(rc == NO_ERROR);
     339
     340
    276341}
    277342
     
    327392    // and all complex work is done here asynchronously.
    328393
    329     QMutexLocker locker(&mutex);
     394    QMutexLocker locker();
    330395    APIRET arc;
     396
     397
     398
    331399
    332400    do {
     
    334402        qDosNI(arc = DosWaitEventSem(eventSem, SEM_INDEFINITE_WAIT));
    335403        locker.relock();
     404
    336405        if (finish)
    337406            break;
    338407
    339 #if defined (QPROCESS_DEBUG)
    340         qDebug() << "QProcessManager::run() signaled";
    341 #endif
    342         foreach (QProcess *proc, processes) {
     408        if (instance->deathFlag.testAndSetRelaxed(1, 0)) {
     409#if defined (QPROCESS_DEBUG)
     410            qDebug() << "QProcessManager::run(): child death signaled";
     411#endif
     412            foreach (QProcess *proc, processes) {
     413                QProcessPrivate::WaitMode mode = (QProcessPrivate::WaitMode)
     414                    proc->d_func()->waitMode.fetchAndStoreRelaxed(QProcessPrivate::SigChild);
     415                switch (mode) {
     416                case QProcessPrivate::Semaphore:
     417                    DosPostEventSem(proc->d_func()->waitSem);
     418                    break;
     419                case QProcessPrivate::Async:
     420                case QProcessPrivate::SigChild:
     421                    QMetaObject::invokeMethod(proc, "_q_processDied", Qt::QueuedConnection);
     422                    break;
     423                }
     424            }
     425        }
     426
     427#if defined (QPROCESS_DEBUG)
     428        qDebug() << "QProcessManager::run(): checking pipes";
     429#endif
     430
     431        // make sure the state array is big enough. The best size for sz pipes
     432        // is sz * 2 (to be able to store both NPSS_RDATA/NPSS_WSPACE and
     433        // NPSS_CLOSE for every pipe) + one for NPSS_EOI
     434        int bestSize = processes.size() * 3 * 2 + 1;
     435        if (pipeStates.size() < bestSize)
     436            pipeStates.resize(bestSize);
     437
     438        arc = DosQueryNPipeSemState((HSEM)eventSem, pipeStates.data(),
     439                                    pipeStates.size() * sizeof(PIPESEMSTATE));
     440        if (arc != NO_ERROR) {
     441            qWarning("QProcessManager::run: DosQueryNPipeSemState returned %lu", arc);
     442            continue;
     443        }
     444
     445        // In the returned information array, CLOSE and READ records for the
     446        // same pipe key may be mixed. We need CLOSE messages to be posted after
     447        // READ messages, so we do two passes.
     448
     449        int pass = 0;
     450        for (int i = 0; pass < 2; ++i) {
     451            BYTE status = pipeStates[i].fStatus;
     452            if (status == NPSS_EOI) {
     453                ++ pass;
     454                i = -1;
     455                continue;
     456            }
     457            if (pass == 0 && status != NPSS_RDATA && status != NPSS_WSPACE)
     458                continue;
     459            if (pass == 1 && status != NPSS_CLOSE)
     460                continue;
     461#if defined(QPROCESS_DEBUG)
     462            qDebug(" %d/%d: fStatus %u fFlag f%02X usKey %04hX usAvail %hu",
     463                   pass, i, (uint) pipeStates[i].fStatus,
     464                   (uint) pipeStates[i].fFlag, pipeStates[i].usKey,
     465                   pipeStates[i].usAvail);
     466#endif
     467            int procKey = toProcKey(pipeStates[i].usKey);
     468            QProcessPrivate::PipeType type = toPipeType(pipeStates[i].usKey);
     469
     470            QProcess *proc = processes[procKey];
     471            Q_ASSERT(proc);
     472#if defined(QPROCESS_DEBUG)
     473            qDebug("  process %p", proc);
     474#endif
     475            QProcessPrivate *d = proc->d_func();
     476
     477            if (status == NPSS_CLOSE) {
     478                // nothing to do but notify the object; it should close the
     479                // pipe if it sees that it has been notified but there is no
     480                // data to read, or if it fails to write to a (closed) pipe
     481            } else {
     482                d->pipeData[type].bytes = pipeStates[i].usAvail;
     483            }
     484
     485            if (d->pipeData[type].isNew) {
     486                // the object didn't process the previous notification yet;
     487                // there is no point to send a new one
     488                continue;
     489            }
     490
     491            d->pipeData[type].isNew = true;
     492
     493            // signal the process object
    343494            QProcessPrivate::WaitMode mode = (QProcessPrivate::WaitMode)
    344                 proc->d_func()->waitMode.fetchAndStoreAcquire(QProcessPrivate::SigChild);
     495                proc->d_func()->waitMode.fetchAndStore(QProcessPrivate::SigChild);
    345496            switch (mode) {
    346             case QProcessPrivate::Select:
    347                 ::so_cancel(proc->d_func()->maxSelectFd);
    348                 break;
    349497            case QProcessPrivate::Semaphore:
    350498                DosPostEventSem(proc->d_func()->waitSem);
     
    352500            case QProcessPrivate::Async:
    353501            case QProcessPrivate::SigChild:
    354                 QMetaObject::invokeMethod(proc, "_q_processDied", Qt::QueuedConnection);
     502                const char *method;
     503                switch(type) {
     504                case QProcessPrivate::InPipe:
     505                    Q_ASSERT(status == NPSS_CLOSE || status == NPSS_WSPACE);
     506                    method = "_q_canWrite";
     507                    break;
     508                case QProcessPrivate::OutPipe:
     509                    Q_ASSERT(status == NPSS_CLOSE || status == NPSS_RDATA);
     510                    method = "_q_canReadStandardOutput";
     511                    break;
     512                case QProcessPrivate::ErrPipe:
     513                    Q_ASSERT(status == NPSS_CLOSE || status == NPSS_RDATA);
     514                    method = "_q_canReadStandardError";
     515                    break;
     516                }
     517                QMetaObject::invokeMethod(proc, method, Qt::QueuedConnection);
    355518                break;
    356519            }
     
    367530{
    368531    waitMode = Async;
    369     maxSelectFd = -1;
    370532    waitSem = NULLHANDLE;
     533
     534
     535
     536
     537
     538
    371539    QProcessManager::addRef();
    372540}
     
    375543{
    376544    QProcessManager::release();
     545
    377546    if (waitSem != NULLHANDLE)
    378547        DosCloseEventSem(waitSem);
     
    387556}
    388557
    389 void QProcessPrivate::destroyPipe(int *pipe)
    390 {
    391     if (pipe[1] != -1) {
    392         ::close(pipe[1]);
    393         pipe[1] = -1;
    394     }
    395     if (pipe[0] != -1) {
    396         ::close(pipe[0]);
    397         pipe[0] = -1;
     558bool QProcessPrivate::createPipe(PipeType type, Channel::Pipe &pipe)
     559{
     560    APIRET rc;
     561    char pathBuf[CCHMAXPATH];
     562
     563    // we need the process identifier to guarantee pipe name unicity
     564    PPIB ppib = NULL;
     565    DosGetInfoBlocks(NULL, &ppib);
     566
     567    switch (type) {
     568    case InPipe:
     569        // create our end of the pipe
     570        sprintf(pathBuf, "\\pipe\\Qt4\\%08lX\\QProcess\\%p\\Stdin",
     571                ppib->pib_ulpid, this->q_func());
     572        rc = DosCreateNPipe(pathBuf, &pipe.server,
     573                            NP_ACCESS_OUTBOUND, NP_NOWAIT | NP_TYPE_BYTE | 1,
     574                            PIPE_SIZE_STDIN, 0, 0);
     575        if (rc == NO_ERROR) {
     576            DosConnectNPipe(pipe.server);
     577            // open the client end of the pipe
     578            ULONG action = 0;
     579            rc = DosOpen(pathBuf, &pipe.client, &action, 0, FILE_NORMAL, FILE_OPEN,
     580                         OPEN_ACCESS_READONLY | OPEN_SHARE_DENYREADWRITE |
     581                         OPEN_FLAGS_NOINHERIT, (PEAOP2)NULL);
     582        }
     583        break;
     584    case OutPipe:
     585    case ErrPipe:
     586        // create our end of the pipe
     587        sprintf(pathBuf, "\\pipe\\Qt4\\%08lX\\QProcess\\%p\\%s",
     588                ppib->pib_ulpid, this->q_func(), type == OutPipe ? "Stdout" : "Stderr");
     589        rc = DosCreateNPipe(pathBuf, &pipe.server,
     590                            NP_ACCESS_INBOUND, NP_NOWAIT | NP_TYPE_BYTE | 1,
     591                            0, type == OutPipe ? PIPE_SIZE_STDOUT : PIPE_SIZE_STDERR, 0);
     592        if (rc == NO_ERROR) {
     593            DosConnectNPipe(pipe.server);
     594            // open the client end of the pipe
     595            ULONG action = 0;
     596            rc = DosOpen(pathBuf, &pipe.client, &action, 0, FILE_NORMAL, FILE_OPEN,
     597                         OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE |
     598                         OPEN_FLAGS_NOINHERIT, (PEAOP2)NULL);
     599        }
     600        break;
     601    }
     602
     603    if (rc != NO_ERROR)
     604        qWarning("QProcessPrivate::createPipe: DosCreateNPipe or DosOpen "
     605                 "returned %lu for PipeType(%d)", rc, type);
     606
     607    return rc == NO_ERROR;
     608}
     609
     610void QProcessPrivate::destroyPipe(Channel::Pipe &pipe)
     611{
     612    if (pipe.client != ~HFILE(~0)) {
     613        DosClose(pipe.client);
     614        pipe.client = HFILE(~0);
     615    }
     616    if (pipe.server != HPIPE(~0)) {
     617        DosDisConnectNPipe(pipe.server);
     618        DosClose(pipe.server);
     619        pipe.server = HPIPE(~0);
    398620    }
    399621}
     
    408630    Q_Q(QProcess);
    409631
     632
     633
     634
    410635    if (&channel == &stderrChannel && processChannelMode == QProcess::MergedChannels) {
    411         channel.pipe[0] = -1;
    412         channel.pipe[1] = -1;
    413636        return true;
    414637    }
     
    416639    if (channel.type == Channel::Normal) {
    417640        // we're piping this channel to our own process
    418         qt_create_pipe(channel.pipe);
    419 
    420         // create the socket notifiers
    421         if (threadData->eventDispatcher) {
    422             if (&channel == &stdinChannel) {
    423                 channel.notifier = new QSocketNotifier(channel.pipe[1],
    424                                                        QSocketNotifier::Write, q);
    425                 channel.notifier->setEnabled(false);
    426                 QObject::connect(channel.notifier, SIGNAL(activated(int)),
    427                                  q, SLOT(_q_canWrite()));
    428             } else {
    429                 channel.notifier = new QSocketNotifier(channel.pipe[0],
    430                                                        QSocketNotifier::Read, q);
    431                 const char *receiver;
    432                 if (&channel == &stdoutChannel)
    433                     receiver = SLOT(_q_canReadStandardOutput());
    434                 else
    435                     receiver = SLOT(_q_canReadStandardError());
    436                 QObject::connect(channel.notifier, SIGNAL(activated(int)),
    437                                  q, receiver);
    438             }
    439         }
    440 
    441         return true;
     641        PipeType type;
     642        if (&channel == &stdinChannel)
     643            type = InPipe;
     644        else if (&channel == &stdoutChannel)
     645            type = OutPipe;
     646        else if (&channel == &stderrChannel)
     647            type = ErrPipe;
     648        else
     649            Q_ASSERT(false);
     650        return createPipe(type, channel.pipe);
    442651    } else if (channel.type == Channel::Redirect) {
    443652        // we're redirecting the channel to/from a file
    444653        QByteArray fname = QFile::encodeName(channel.file);
    445654
     655
    446656        if (&channel == &stdinChannel) {
    447657            // try to open in read-only mode
    448             channel.pipe[1] = -1;
    449             if ( (channel.pipe[0] = ::open(fname, O_RDONLY)) != -1)
    450                 return true;    // success
     658            ULONG action = 0;
     659            rc = DosOpen(fname, &channel.pipe.client, &action, 0, FILE_NORMAL, FILE_OPEN,
     660                         OPEN_ACCESS_READONLY | OPEN_FLAGS_NOINHERIT, (PEAOP2)NULL);
     661
     662            if (rc == NO_ERROR)
     663                return true; // success
    451664
    452665            q->setErrorString(QProcess::tr("Could not open input redirection for reading"));
    453666        } else {
    454             int mode = O_WRONLY | O_CREAT;
     667            int mode = ;
    455668            if (channel.append)
    456                 mode |= O_APPEND;
     669                mode |= ;
    457670            else
    458                 mode |= O_TRUNC;
    459 
    460             channel.pipe[0] = -1;
    461             if ( (channel.pipe[1] = ::open(fname, mode, 0666)) != -1)
     671                mode |= FILE_TRUNCATE;
     672            ULONG action = 0;
     673            rc = DosOpen(fname, &channel.pipe.client, &action, 0, FILE_NORMAL, mode,
     674                         OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYWRITE |
     675                         OPEN_FLAGS_NOINHERIT, (PEAOP2)NULL);
     676
     677            if (rc == NO_ERROR && channel.append) {
     678                ULONG actual = 0;
     679                rc = DosSetFilePtr(channel.pipe.client, 0, FILE_END, &actual);
     680            }
     681            if (rc == NO_ERROR)
    462682                return true; // success
    463683
     
    492712        }
    493713
    494         if (source->pipe[1] != INVALID_Q_PIPE || sink->pipe[0] != INVALID_Q_PIPE) {
     714        if (source->pipe) {
    495715            // already created, do nothing
     716
     717
    496718            return true;
    497719        } else {
    498             Q_ASSERT(source->pipe[0] == INVALID_Q_PIPE && source->pipe[1] == INVALID_Q_PIPE);
    499             Q_ASSERT(sink->pipe[0] == INVALID_Q_PIPE && sink->pipe[1] == INVALID_Q_PIPE);
    500 
    501             Q_PIPE pipe[2] = { -1, -1 };
    502             qt_create_pipe(pipe);
    503             sink->pipe[0] = pipe[0];
    504             source->pipe[1] = pipe[1];
     720            Q_ASSERT(source->pipe);
     721            Q_ASSERT(sink->pipe);
     722
     723            ;
     724            pipe);
     725            sink->pipe;
     726            source->pipe;
    505727
    506728            return true;
     
    635857        return;
    636858
    637     QProcessManager::addProcess(q);
     859    procKey = QProcessManager::addProcess(q);
     860
     861    if (procKey == QProcessManager::InvalidProcKey) {
     862        // setErrorString() is called inside addProcess()
     863        Q_ASSERT(!q->errorString().isEmpty());
     864        processError = QProcess::FailedToStart;
     865        emit q->error(processError);
     866        cleanup();
     867        return;
     868    }
    638869
    639870    // Start the process (platform dependent)
     871
    640872    q->setProcessState(QProcess::Starting);
    641873
    642     // save & copy the stdin socket
    643     int stdin_copy = ::dup(fileno(stdin));
    644     ::dup2(stdinChannel.pipe[0], fileno(stdin));
    645 
    646     // save & copy the stdout and stderr if asked to
    647     int stdout_copy = -1, stderr_copy = -1;
    648     if (processChannelMode != QProcess::ForwardedChannels) {
    649         stdout_copy = ::dup(fileno(stdout));
    650         ::dup2(stdoutChannel.pipe[1], fileno(stdout));
    651 
    652         // merge stdout and stderr if asked to
    653         stderr_copy = ::dup(fileno(stderr));
    654         if (processChannelMode == QProcess::MergedChannels) {
    655             ::dup2(fileno(stdout), fileno(stderr));
    656         } else {
     874    APIRET arc;
     875
     876    QString error;
     877    HFILE tmpStdin = HFILE(~0), tmpStdout = HFILE(~0), tmpStderr = HFILE(~0);
     878    HFILE realStdin = HF_STDIN, realStdout = HF_STDOUT, realStderr = HF_STDERR;
     879
     880    do {
     881        // save & copy the stdin handle
     882        if ((arc = DosDupHandle(realStdin, &tmpStdin)) == NO_ERROR) {
     883            arc = DosDupHandle(stdinChannel.pipe.client, &realStdin);
     884        }
     885        if (arc != NO_ERROR) {
     886#if defined (QPROCESS_DEBUG)
     887            qDebug("QProcessPrivate::startProcess: DosDupHandle for STDIN "
     888                   "returned %lu", arc);
     889#endif
     890            break;
     891        }
     892        // save & copy the stdout and stderr handles if asked to
     893        if (processChannelMode != QProcess::ForwardedChannels) {
     894            // save & copy the stdout handle
     895            if ((arc = DosDupHandle(realStdout, &tmpStdout)) == NO_ERROR) {
     896                arc = DosDupHandle(stdoutChannel.pipe.client, &realStdout);
     897            }
     898            if (arc != NO_ERROR) {
     899#if defined (QPROCESS_DEBUG)
     900                qDebug("QProcessPrivate::startProcess: DosDupHandle for STDOUT "
     901                       "returned %lu", arc);
     902#endif
     903                break;
     904            }
     905            // qDebug() uses STDERR so only redirect if !QPROCESS_DEBUG
    657906#if !defined (QPROCESS_DEBUG)
    658             // don't redirect it as qDebug() uses it
    659             ::dup2(stderrChannel.pipe[1], fileno(stderr));
    660 #endif
    661         }
    662     }
    663 
    664     int pid = qt_startProcess(program, arguments, workingDirectory,
     907            if ((arc = DosDupHandle(realStderr, &tmpStderr)) == NO_ERROR) {
     908                // merge stdout and stderr if asked to
     909                if (processChannelMode == QProcess::MergedChannels) {
     910                    arc = DosDupHandle(stdoutChannel.pipe.client, &realStderr);
     911                } else {
     912                    arc = DosDupHandle(stderrChannel.pipe.client, &realStderr);
     913                }
     914            }
     915            if (arc != NO_ERROR)
     916                break;
     917#endif
     918        }
     919
     920    } while (false);
     921
     922    int pid = -1;
     923    if (arc == NO_ERROR)
     924        pid = qt_startProcess(program, arguments, workingDirectory,
    665925                              &environment);
    666926
    667     // restore stdin/stdout/stderr
    668     if (stdin_copy != -1) {
    669         ::dup2(stdin_copy, fileno(stdin));
    670         ::close(stdin_copy);
    671     }
    672     if (stdout_copy != -1) {
    673         ::dup2(stdout_copy, fileno(stdout));
    674         ::close(stdout_copy);
    675     }
    676     if (stderr_copy != -1) {
    677         ::dup2(stderr_copy, fileno(stderr));
    678         ::close(stderr_copy);
    679     }
    680 
    681     if (pid == -1) {
     927    //
     928    if () {
     929        );
     930        );
     931    }
     932    if () {
     933        );
     934        );
     935    }
     936    if () {
     937        );
     938        );
     939    }
     940
     941    if (pid == -1) {
    682942        // Cleanup, report error and return
    683 #if defined (QPROCESS_DEBUG)
    684         qDebug("spawnvpe failed: %s", qPrintable(qt_error_string(errno)));
    685 #endif
    686943        q->setProcessState(QProcess::NotRunning);
    687944        processError = QProcess::FailedToStart;
    688         q->setErrorString(QProcess::tr("Process failed to start: %1")
    689                                        .arg(qPrintable(qt_error_string(errno))));
     945        if (arc != NO_ERROR) {
     946            // handle duplication failed
     947            q->setErrorString(QProcess::tr("Process failed to start: %1")
     948                                           .arg(QString("DOS error %1").arg(arc)));
     949        } else {
     950#if defined (QPROCESS_DEBUG)
     951            qDebug("spawnvpe failed: %s", qPrintable(qt_error_string(errno)));
     952#endif
     953            q->setErrorString(QProcess::tr("Process failed to start: %1")
     954                                           .arg(qPrintable(qt_error_string(errno))));
     955        }
    690956        emit q->error(processError);
    691         QProcessManager::removeProcess(q);
     957        QProcessManager::removeProcess(procKey);
     958        procKey = QProcessManager::InvalidProcKey;
    692959        cleanup();
    693960        return;
     
    696963    this->pid = Q_PID(pid);
    697964
    698     unsigned long nonBlock = 1;
    699 
    700     // close the ends we don't use and make all pipes non-blocking
    701     if (stdinChannel.pipe[0] != -1) {
    702         ::close(stdinChannel.pipe[0]);
    703         stdinChannel.pipe[0] = -1;
    704     }
    705     if (stdinChannel.pipe[1] != -1)
    706         ::ioctl(stdinChannel.pipe[1], FIONBIO, &nonBlock);
    707 
    708     if (stdoutChannel.pipe[1] != -1) {
    709         ::close(stdoutChannel.pipe[1]);
    710         stdoutChannel.pipe[1] = -1;
    711     }
    712     if (stdoutChannel.pipe[0] != -1)
    713         ::ioctl(stdoutChannel.pipe[0], FIONBIO, &nonBlock);
    714 
    715     if (stderrChannel.pipe[1] != -1) {
    716         ::close(stderrChannel.pipe[1]);
    717         stderrChannel.pipe[1] = -1;
    718     }
    719     if (stderrChannel.pipe[0] != -1)
    720         ::ioctl(stderrChannel.pipe[0], FIONBIO, &nonBlock);
     965    // close the client ends (they are no more necessary)
     966    if (stdinChannel.pipe.client != HFILE(~0)) {
     967        DosClose(stdinChannel.pipe.client);
     968        stdinChannel.pipe.client = HFILE(~0);
     969    }
     970    if (stdoutChannel.pipe.client != HFILE(~0)) {
     971        DosClose(stdoutChannel.pipe.client);
     972        stdoutChannel.pipe.client = HFILE(~0);
     973    }
     974    if (stderrChannel.pipe.client != HFILE(~0)) {
     975        DosClose(stderrChannel.pipe.client);
     976        stderrChannel.pipe.client = HFILE(~0);
     977    }
    721978
    722979    // give the process a chance to start ...
     
    735992qint64 QProcessPrivate::bytesAvailableFromStdout() const
    736993{
    737     size_t nbytes = 0;
    738994    qint64 available = 0;
    739     if (::ioctl(stdoutChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0)
    740         available = (qint64) *((int *) &nbytes);
     995    {
     996        QMutexLocker lock(QProcessManager::mutex());
     997        available = pipeData[OutPipe].bytes;
     998        // accept new messages from QProcessManager
     999        const_cast<QProcessPrivate*>(this)->pipeData[OutPipe].isNew = false;
     1000    }
    7411001#if defined (QPROCESS_DEBUG)
    7421002    qDebug("QProcessPrivate::bytesAvailableFromStdout() == %lld", available);
     
    7471007qint64 QProcessPrivate::bytesAvailableFromStderr() const
    7481008{
    749     size_t nbytes = 0;
    7501009    qint64 available = 0;
    751     if (::ioctl(stderrChannel.pipe[0], FIONREAD, (char *) &nbytes) >= 0)
    752         available = (qint64) *((int *) &nbytes);
     1010    {
     1011        QMutexLocker lock(QProcessManager::mutex());
     1012        available = pipeData[ErrPipe].bytes;
     1013        // accept new messages from QProcessManager
     1014        const_cast<QProcessPrivate*>(this)->pipeData[ErrPipe].isNew = false;
     1015    }
    7531016#if defined (QPROCESS_DEBUG)
    7541017    qDebug("QProcessPrivate::bytesAvailableFromStderr() == %lld", available);
     
    7591022qint64 QProcessPrivate::readFromStdout(char *data, qint64 maxlen)
    7601023{
    761     qint64 bytesRead = ::read(stdoutChannel.pipe[0], data, maxlen);
     1024    ULONG actual = 0;
     1025    APIRET arc = DosRead(stdoutChannel.pipe.server, data, maxlen, &actual);
     1026
     1027    // decrement the counter to make sure bytesAvailableFromStdout() will return
     1028    // a correct number before QProcessManager::run() updates it
     1029    QMutexLocker lock(QProcessManager::mutex());
     1030    if (actual <= (ULONG) pipeData[OutPipe].bytes)
     1031        pipeData[OutPipe].bytes -= (USHORT) actual;
     1032    else
     1033        pipeData[OutPipe].bytes = 0;
     1034
     1035    qint64 bytesRead = arc == NO_ERROR ? (qint64)actual : -1;
     1036
    7621037#if defined QPROCESS_DEBUG
    7631038    qDebug("QProcessPrivate::readFromStdout(%p \"%s\", %lld) == %lld",
     
    7691044qint64 QProcessPrivate::readFromStderr(char *data, qint64 maxlen)
    7701045{
    771     qint64 bytesRead = ::read(stderrChannel.pipe[0], data, maxlen);
     1046    ULONG actual = 0;
     1047    APIRET arc = DosRead(stderrChannel.pipe.server, data, maxlen, &actual);
     1048
     1049    // decrement the counter to make sure bytesAvailableFromStderr() will return
     1050    // a correct number before QProcessManager::run() updates it
     1051    QMutexLocker lock(QProcessManager::mutex());
     1052    if (actual <= (ULONG) pipeData[ErrPipe].bytes)
     1053        pipeData[ErrPipe].bytes -= (USHORT) actual;
     1054    else
     1055        pipeData[ErrPipe].bytes = 0;
     1056
     1057    qint64 bytesRead = arc == NO_ERROR ? (qint64)actual : -1;
     1058
    7721059#if defined QPROCESS_DEBUG
    7731060    qDebug("QProcessPrivate::readFromStderr(%p \"%s\", %lld) == %lld",
     
    7791066qint64 QProcessPrivate::writeToStdin(const char *data, qint64 maxlen)
    7801067{
    781     qint64 written = ::write(stdinChannel.pipe[1], data, maxlen);
     1068    ULONG actual = 0;
     1069    APIRET arc = DosWrite(stdinChannel.pipe.server, data, maxlen, &actual);
     1070
     1071    qint64 written = arc == NO_ERROR ? (qint64)actual : -1;
     1072
     1073    // accept new messages from QProcessManager
     1074    QMutexLocker lock(QProcessManager::mutex());
     1075    const_cast<QProcessPrivate*>(this)->pipeData[InPipe].isNew = false;
     1076
    7821077#if defined QPROCESS_DEBUG
    7831078    qDebug("QProcessPrivate::writeToStdin(%p \"%s\", %lld) == %lld",
     
    8401135}
    8411136
    842 static int qt_select(int maxfd, fd_set *fdread, fd_set *fdwrite, int timeout)
    843 {
    844     struct timeval tv;
    845     tv.tv_sec = timeout / 1000;
    846     tv.tv_usec = (timeout % 1000) * 1000;
    847 
    848     int ret = select(maxfd, fdread, fdwrite, 0, timeout < 0 ? 0 : &tv);
    849     return ret;
    850 }
    851 
    8521137bool QProcessPrivate::waitForStarted(int msecs)
    8531138{
     
    8751160    stopWatch.start();
    8761161
     1162
     1163
     1164
    8771165    forever {
    878         fd_set fdread;
    879         fd_set fdwrite;
    880 
    881         FD_ZERO(&fdread);
    882         FD_ZERO(&fdwrite);
    883 
    884         int maxFd = 0;
    885         if (stdoutChannel.pipe[0] != -1) {
    886             FD_SET(stdoutChannel.pipe[0], &fdread);
    887             maxFd = qMax(maxFd, stdoutChannel.pipe[0]);
    888         }
    889         if (stderrChannel.pipe[0] != -1) {
    890             FD_SET(stderrChannel.pipe[0], &fdread);
    891             maxFd = qMax(maxFd, stderrChannel.pipe[0]);
    892         }
    893 
    894         if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) {
    895             FD_SET(stdinChannel.pipe[1], &fdwrite);
    896             maxFd = qMax(maxFd, stdinChannel.pipe[1]);
    897         }
    898 
    899         WaitMode mode;
    900         if (maxFd >= 0) {
    901             mode = Select;
    902             maxSelectFd = maxFd;
    903         } else {
    904             mode = Semaphore;
    905             ensureWaitSem();
    906         }
    907 
    9081166        bool timedOut = false, failed = false;
    909 
    910         if (waitMode.testAndSetRelease(Async, mode)) {
     1167        if (waitMode.testAndSetRelaxed(Async, Semaphore)) {
    9111168            int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
    912             if (maxFd >= 0) {
    913                 int ret = qt_select(maxFd + 1, &fdread, &fdwrite, timeout);
    914                 if (ret < 0 && errno != EINTR) {
    915                     Q_ASSERT(errno == EINTR);
     1169            qDosNI(arc = DosWaitEventSem(waitSem, (ULONG)timeout));
     1170            if (arc == ERROR_TIMEOUT) {
     1171                timedOut = true;
     1172            } else if (arc != NO_ERROR) {
     1173                Q_ASSERT(arc == NO_ERROR);
     1174                failed = true;
     1175            } else {
     1176                QMutexLocker lock(QProcessManager::mutex());
     1177
     1178                bool readyReadEmitted = false;
     1179                if (pipeData[OutPipe].bytes) {
     1180                    bool canRead = _q_canReadStandardOutput();
     1181                    if (processChannel == QProcess::StandardOutput && canRead)
     1182                        readyReadEmitted = true;
     1183                }
     1184                if (pipeData[ErrPipe].bytes) {
     1185                    bool canRead = _q_canReadStandardError();
     1186                    if (processChannel == QProcess::StandardError && canRead)
     1187                        readyReadEmitted = true;
     1188                }
     1189                if (readyReadEmitted) {
     1190                    waitMode.fetchAndStoreRelaxed(Async);
     1191                    return true;
     1192                }
     1193
     1194                if (pipeData[InPipe].bytes)
     1195                    _q_canWrite();
     1196
     1197                if (!pid)
    9161198                    failed = true;
    917                 } else if (ret == 0) {
    918                     timedOut = true;
    919                 } else if (ret >= 0) {
    920                     bool readyReadEmitted = false;
    921                     if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread)) {
    922                         bool canRead = _q_canReadStandardOutput();
    923                         if (processChannel == QProcess::StandardOutput && canRead)
    924                             readyReadEmitted = true;
    925                     }
    926                     if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread)) {
    927                         bool canRead = _q_canReadStandardError();
    928                         if (processChannel == QProcess::StandardError && canRead)
    929                             readyReadEmitted = true;
    930                     }
    931                     if (readyReadEmitted) {
    932                         waitMode.fetchAndStoreRelaxed(Async);
    933                         return true;
    934                     }
    935 
    936                     if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
    937                         _q_canWrite();
    938 
    939                     if (!pid)
    940                         failed = true;
    941                 }
    942             } else {
    943                 APIRET arc;
    944                 qDosNI(arc = DosWaitEventSem(waitSem, (ULONG)timeout));
    945                 if (arc == ERROR_TIMEOUT) {
    946                     timedOut = true;
    947                 } else if (arc != NO_ERROR) {
    948                     Q_ASSERT(arc == NO_ERROR);
    949                     failed = true;
    950                 }
    9511199            }
    9521200        } else {
     
    9801228    stopWatch.start();
    9811229
     1230
     1231
     1232
    9821233    while (!writeBuffer.isEmpty()) {
    983         fd_set fdread;
    984         fd_set fdwrite;
    985 
    986         FD_ZERO(&fdread);
    987         FD_ZERO(&fdwrite);
    988 
    989         int maxFd = 0;
    990         if (stdoutChannel.pipe[0] != -1) {
    991             FD_SET(stdoutChannel.pipe[0], &fdread);
    992             maxFd = qMax(maxFd, stdoutChannel.pipe[0]);
    993         }
    994         if (stderrChannel.pipe[0] != -1) {
    995             FD_SET(stderrChannel.pipe[0], &fdread);
    996             maxFd = qMax(maxFd, stderrChannel.pipe[0]);
    997         }
    998 
    999         if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) {
    1000             FD_SET(stdinChannel.pipe[1], &fdwrite);
    1001             maxFd = qMax(maxFd, stdinChannel.pipe[1]);
    1002         }
    1003 
    1004         WaitMode mode;
    1005         if (maxFd >= 0) {
    1006             mode = Select;
    1007             maxSelectFd = maxFd;
    1008         } else {
    1009             mode = Semaphore;
    1010             ensureWaitSem();
    1011         }
    1012 
    10131234        bool timedOut = false, failed = false;
    1014 
    1015         if (waitMode.testAndSetRelease(Async, mode)) {
     1235        if (waitMode.testAndSetRelaxed(Async, Semaphore)) {
    10161236            int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
    1017             if (maxFd >= 0) {
    1018                 int ret = qt_select(maxFd + 1, &fdread, &fdwrite, timeout);
    1019                 if (ret < 0 && errno != EINTR) {
    1020                     Q_ASSERT(errno == EINTR);
     1237            qDosNI(arc = DosWaitEventSem(waitSem, (ULONG)timeout));
     1238            if (arc == ERROR_TIMEOUT) {
     1239                timedOut = true;
     1240            } else if (arc != NO_ERROR) {
     1241                Q_ASSERT(arc == NO_ERROR);
     1242                failed = true;
     1243            } else {
     1244                QMutexLocker lock(QProcessManager::mutex());
     1245
     1246                if (pipeData[InPipe].bytes) {
     1247                    waitMode.fetchAndStoreRelaxed(Async);
     1248                    return _q_canWrite();
     1249                }
     1250
     1251                if (pipeData[OutPipe].bytes)
     1252                    _q_canReadStandardOutput();
     1253
     1254                if (pipeData[ErrPipe].bytes)
     1255                    _q_canReadStandardError();
     1256
     1257                if (!pid)
    10211258                    failed = true;
    1022                 } else if (ret == 0) {
    1023                     timedOut = true;
    1024                 } else if (ret >= 0) {
    1025                     if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
    1026                         return _q_canWrite();
    1027 
    1028                     if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
    1029                         _q_canReadStandardOutput();
    1030 
    1031                     if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
    1032                         _q_canReadStandardError();
    1033 
    1034                     if (!pid)
    1035                         failed = true;
    1036                 }
    1037             } else {
    1038                 APIRET arc;
    1039                 qDosNI(arc = DosWaitEventSem(waitSem, (ULONG)timeout));
    1040                 if (arc == ERROR_TIMEOUT) {
    1041                     timedOut = true;
    1042                 } else if (arc != NO_ERROR) {
    1043                     Q_ASSERT(arc == NO_ERROR);
    1044                     failed = true;
    1045                 }
    10461259            }
    10471260        } else {
     
    10761289    stopWatch.start();
    10771290
     1291
     1292
     1293
    10781294    forever {
    1079         fd_set fdread;
    1080         fd_set fdwrite;
    1081 
    1082         FD_ZERO(&fdread);
    1083         FD_ZERO(&fdwrite);
    1084 
    1085         int maxFd = -1;
    1086         if (stdoutChannel.pipe[0] != -1) {
    1087             FD_SET(stdoutChannel.pipe[0], &fdread);
    1088             maxFd = qMax(maxFd, stdoutChannel.pipe[0]);
    1089         }
    1090         if (stderrChannel.pipe[0] != -1) {
    1091             FD_SET(stderrChannel.pipe[0], &fdread);
    1092             maxFd = qMax(maxFd, stderrChannel.pipe[0]);
    1093         }
    1094 
    1095         if (!writeBuffer.isEmpty() && stdinChannel.pipe[1] != -1) {
    1096             FD_SET(stdinChannel.pipe[1], &fdwrite);
    1097             maxFd = qMax(maxFd, stdinChannel.pipe[1]);
    1098         }
    1099 
    1100         WaitMode mode;
    1101         if (maxFd >= 0) {
    1102             mode = Select;
    1103             maxSelectFd = maxFd;
    1104         } else {
    1105             mode = Semaphore;
    1106             ensureWaitSem();
    1107         }
    1108 
    11091295        bool timedOut = false, failed = false;
    1110 
    1111         if (waitMode.testAndSetRelease(Async, mode)) {
     1296        if (waitMode.testAndSetRelaxed(Async, Semaphore)) {
    11121297            int timeout = qt_timeout_value(msecs, stopWatch.elapsed());
    1113             if (maxFd >= 0) {
    1114                 int ret = qt_select(maxFd + 1, &fdread, &fdwrite, timeout);
    1115                 if (ret < 0 && errno != EINTR) {
    1116                     Q_ASSERT(errno == EINTR);
    1117                     failed = true;
    1118                 } else if (ret == 0) {
    1119                     timedOut = true;
    1120                 } else if (ret >= 0) {
    1121                     if (stdinChannel.pipe[1] != -1 && FD_ISSET(stdinChannel.pipe[1], &fdwrite))
    1122                         _q_canWrite();
    1123 
    1124                     if (stdoutChannel.pipe[0] != -1 && FD_ISSET(stdoutChannel.pipe[0], &fdread))
    1125                         _q_canReadStandardOutput();
    1126 
    1127                     if (stderrChannel.pipe[0] != -1 && FD_ISSET(stderrChannel.pipe[0], &fdread))
    1128                         _q_canReadStandardError();
    1129 
    1130                     if (!pid) {
    1131                         waitMode.fetchAndStoreRelaxed(Async);
    1132                         return true;
    1133                     }
    1134                 }
     1298            qDosNI(arc = DosWaitEventSem(waitSem, (ULONG)timeout));
     1299            if (arc == ERROR_TIMEOUT) {
     1300                timedOut = true;
     1301            } else if (arc != NO_ERROR) {
     1302                Q_ASSERT(arc == NO_ERROR);
     1303                failed = true;
    11351304            } else {
    1136                 APIRET arc;
    1137                 qDosNI(arc = DosWaitEventSem(waitSem, (ULONG)timeout));
    1138                 if (arc == ERROR_TIMEOUT) {
    1139                     timedOut = true;
    1140                 } else if (arc != NO_ERROR) {
    1141                     Q_ASSERT(arc == NO_ERROR);
    1142                     failed = true;
     1305                QMutexLocker lock(QProcessManager::mutex());
     1306
     1307                if (pipeData[InPipe].bytes)
     1308                    _q_canWrite();
     1309
     1310                if (pipeData[OutPipe].bytes)
     1311                    _q_canReadStandardOutput();
     1312
     1313                if (pipeData[ErrPipe].bytes)
     1314                    _q_canReadStandardError();
     1315
     1316                if (!pid) {
     1317                    waitMode.fetchAndStoreRelaxed(Async);
     1318                    return true;
    11431319                }
    11441320            }
     
    11651341bool QProcessPrivate::waitForWrite(int msecs)
    11661342{
    1167     fd_set fdwrite;
    1168     FD_ZERO(&fdwrite);
    1169     FD_SET(stdinChannel.pipe[1], &fdwrite);
     1343    // ### this function isn't actually used in OS/2 and Unix code paths
     1344
     1345    APIRET arc;
     1346    ensureWaitSem();
    11701347
    11711348    bool ret = false;
    1172     maxSelectFd = stdinChannel.pipe[1];
    1173     if (waitMode.testAndSetRelease(Async, Select)) {
    1174         ret = qt_select(stdinChannel.pipe[1] + 1, 0, &fdwrite,
    1175                         msecs < 0 ? 0 : msecs) == 1;
     1349    if (waitMode.testAndSetRelaxed(Async, Semaphore)) {
     1350        qDosNI(arc = DosWaitEventSem(waitSem, (ULONG)msecs));
     1351        if (arc == NO_ERROR) {
     1352            QMutexLocker lock(QProcessManager::mutex());
     1353            ret = pipeData[InPipe].bytes;
     1354        }
    11761355    }
    11771356    waitMode.fetchAndStoreRelaxed(Async);
     
    11871366    // normally calls findExitCode() won't be walked)
    11881367
    1189     Q_Q(QProcess);
    1190     QProcessManager::removeProcess(q);
     1368    if (procKey != QProcessManager::InvalidProcKey) {
     1369        QProcessManager::removeProcess(procKey);
     1370        procKey = QProcessManager::InvalidProcKey;
     1371    }
    11911372}
    11921373
  • trunk/src/corelib/io/qprocess_p.h

    r192 r197  
    5959#include "private/qiodevice_p.h"
    6060
    61 #ifdef Q_OS_WIN
     61#if
    6262#include "QtCore/qt_windows.h"
    6363typedef HANDLE Q_PIPE;
    6464#define INVALID_Q_PIPE INVALID_HANDLE_VALUE
     65
     66
    6567#else
    6668typedef int Q_PIPE;
    6769#define INVALID_Q_PIPE -1
    68 #endif
    69 
    70 #ifdef Q_OS_OS2
    71 #include "QtCore/qt_os2.h"
    7270#endif
    7371
     
    9795        Channel() : process(0), notifier(0), type(Normal), closed(false), append(false)
    9896        {
     97
     98
     99
     100
    99101            pipe[0] = INVALID_Q_PIPE;
    100102            pipe[1] = INVALID_Q_PIPE;
     103
    101104        }
    102105
     
    128131        QProcessPrivate *process;
    129132        QSocketNotifier *notifier;
     133
     134
     135
     136
     137
     138
     139
    130140        Q_PIPE pipe[2];
     141
    131142
    132143        unsigned type : 2;
     
    172183    QRingBuffer writeBuffer;
    173184
     185
     186
     187
     188
     189
    174190    Q_PIPE childStartedPipe[2];
    175191    Q_PIPE deathPipe[2];
    176192    void destroyPipe(Q_PIPE pipe[2]);
     193
    177194
    178195    QSocketNotifier *startupSocketNotifier;
     
    215232#endif
    216233#ifdef Q_OS_OS2
    217     enum WaitMode { Async, Select, Semaphore, SigChild };
     234    enum WaitMode { Async, Semaphore, SigChild };
    218235    QAtomicInt waitMode;
    219     int maxSelectFd;
    220236    HEV waitSem;
     237
     238
     239
     240
     241
     242
    221243#endif
    222244
Note: See TracChangeset for help on using the changeset viewer.