Changeset 210


Ignore:
Timestamp:
Oct 7, 2009, 12:09:56 AM (16 years ago)
Author:
Dmitry A. Kuminov
Message:

corelib: QProcess: Implemented QProcess->QProcess redirection.

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

Legend:

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

    r203 r210  
    515515    destroyPipe(childStartedPipe);
    516516    destroyPipe(deathPipe);
     517#else
     518    pipeData[InPipe].bytesLeft = 0;
     519    pipeData[OutPipe].bytesLeft = pipeData[ErrPipe].bytesLeft = 0;
     520    pipeData[InPipe].newBytes = 0;
     521    pipeData[OutPipe].newBytes = pipeData[ErrPipe].newBytes = 0;
    517522#endif
    518523#ifdef Q_OS_UNIX
  • TabularUnified trunk/src/corelib/io/qprocess_os2.cpp

    r203 r210  
    271271    APIRET arc = NO_ERROR;
    272272    QProcessPrivate *d = process->d_func();
    273     if (d->stdinChannel.pipe.server != HPIPE(~0)) {
     273    if (d->stdinChannel.type == QProcessPrivate::Channel::Normal &&
     274        d->stdinChannel.pipe.server != HPIPE(~0)) {
    274275        arc = DosSetNPipeSem(d->stdinChannel.pipe.server, (HSEM)instance->eventSem,
    275276                             toPipeKey(procKey, QProcessPrivate::InPipe));
    276277    }
    277     if (arc == NO_ERROR && d->stdoutChannel.pipe.server != HPIPE(~0)) {
     278    if (arc == NO_ERROR &&
     279        d->stdoutChannel.type == QProcessPrivate::Channel::Normal &&
     280        d->stdoutChannel.pipe.server != HPIPE(~0)) {
    278281        arc = DosSetNPipeSem(d->stdoutChannel.pipe.server, (HSEM)instance->eventSem,
    279282                             toPipeKey(procKey, QProcessPrivate::OutPipe));
    280283    }
    281     if (arc == NO_ERROR && d->stderrChannel.pipe.server != HPIPE(~0)) {
     284    if (arc == NO_ERROR &&
     285        d->stderrChannel.type == QProcessPrivate::Channel::Normal &&
     286        d->stderrChannel.pipe.server != HPIPE(~0)) {
    282287        arc = DosSetNPipeSem(d->stderrChannel.pipe.server, (HSEM)instance->eventSem,
    283288                             toPipeKey(procKey, QProcessPrivate::ErrPipe));
     
    552557}
    553558
    554 bool QProcessPrivate::createPipe(PipeType type, Channel::Pipe &pipe)
     559bool QProcessPrivate::createPipe(PipeType type, Channel::Pipe &pipe,
     560                                 const char *name /*= 0*/)
    555561{
    556562    APIRET rc;
    557563    char pathBuf[CCHMAXPATH];
     564
     565    pipe.server = HPIPE(~0);
     566    pipe.client = HFILE(~0);
    558567
    559568    // we need the process identifier to guarantee pipe name unicity
     
    564573    case InPipe:
    565574        // create our end of the pipe
    566         sprintf(pathBuf, "\\pipe\\Qt4\\%08lX\\QProcess\\%p\\Stdin",
    567                 ppib->pib_ulpid, this->q_func());
     575        sprintf(pathBuf, "\\pipe\\Qt4\\%08lX\\QProcess\\%p\\%s",
     576                ppib->pib_ulpid, this->q_func(), name ? name : "Stdin");
    568577        rc = DosCreateNPipe(pathBuf, &pipe.server,
    569                             NP_ACCESS_OUTBOUND, NP_NOWAIT | NP_TYPE_BYTE | 1,
     578                            NP_ACCESS_OUTBOUND | NP_NOINHERIT,
     579                            NP_NOWAIT | NP_TYPE_BYTE | 1,
    570580                            PIPE_SIZE_STDIN, 0, 0);
    571581        if (rc == NO_ERROR) {
    572582            DosConnectNPipe(pipe.server);
     583            // ensure the other end blocks (vital for process->process redirections)
     584            DosSetNPHState(pipe.server, NP_WAIT);
    573585            // open the client end of the pipe
    574586            ULONG action = 0;
     
    582594        // create our end of the pipe
    583595        sprintf(pathBuf, "\\pipe\\Qt4\\%08lX\\QProcess\\%p\\%s",
    584                 ppib->pib_ulpid, this->q_func(), type == OutPipe ? "Stdout" : "Stderr");
     596                ppib->pib_ulpid, this->q_func(),
     597                name ? name : type == OutPipe ? "Stdout" : "Stderr");
    585598        rc = DosCreateNPipe(pathBuf, &pipe.server,
    586                             NP_ACCESS_INBOUND, NP_NOWAIT | NP_TYPE_BYTE | 1,
     599                            NP_ACCESS_INBOUND | NP_NOINHERIT,
     600                            NP_NOWAIT | NP_TYPE_BYTE | 1,
    587601                            0, type == OutPipe ? PIPE_SIZE_STDOUT : PIPE_SIZE_STDERR, 0);
    588602        if (rc == NO_ERROR) {
    589603            DosConnectNPipe(pipe.server);
     604            // ensure the other end blocks (vital for process->process redirections)
     605            DosSetNPHState(pipe.server, NP_WAIT);
    590606            // open the client end of the pipe
    591607            ULONG action = 0;
     
    597613    }
    598614
    599     if (rc != NO_ERROR)
    600         qWarning("QProcessPrivate::createPipe: DosCreateNPipe or DosOpen "
    601                  "returned %lu for PipeType(%d)", rc, type);
     615    if (rc != NO_ERROR) {
     616        qWarning("QProcessPrivate::createPipe: %s(%s) returned %lu",
     617                 pipe.server == HPIPE(~0) ? "DosCreateNPipe" : "DosOpen",
     618                 pathBuf, rc);
     619    }
    602620
    603621    return rc == NO_ERROR;
     
    689707        Q_ASSERT_X(channel.process, "QProcess::start", "Internal error");
    690708
    691         Channel *source;
    692         Channel *sink;
     709        // the first process started is the server, the second one is the client.
     710        // the server stores handles to both ends in its channel.pipe member;
     711        // the other part will pickup the handle of the client end from there.
    693712
    694713        if (channel.type == Channel::PipeSource) {
    695714            // we are the source
    696             source = &channel;
    697             sink = &channel.process->stdinChannel;
    698 
    699             Q_ASSERT(source == &stdoutChannel);
    700             Q_ASSERT(sink->process == this && sink->type == Channel::PipeSink);
     715            Q_ASSERT(&channel == &stdoutChannel);
     716            Q_ASSERT(channel.process->stdinChannel.process == this &&
     717                     channel.process->stdinChannel.type == Channel::PipeSink);
     718            if (channel.process->stdinChannel.pipe.server != HPIPE(~0)) {
     719                // the other process has already started and became the server
     720            } else {
     721                // note: InPipe, since the type is relative to the other side
     722                createPipe(InPipe, channel.pipe, "Source");
     723            }
    701724        } else {
    702             // we are the sink;
    703             source = &channel.process->stdoutChannel;
    704             sink = &channel;
    705 
    706             Q_ASSERT(sink == &stdinChannel);
    707             Q_ASSERT(source->process == this && source->type == Channel::PipeSource);
    708         }
    709 
    710         if (source->pipe.server != HPIPE(~0)) {
    711             // already created, do nothing
    712             Q_ASSERT(source->pipe.client == HFILE(~0));
    713             Q_ASSERT(sink->pipe.server == HPIPE(~0) && sink->pipe.client != HFILE(~0));
    714             return true;
    715         } else {
    716             Q_ASSERT(source->pipe.server == HPIPE(~0) && source->pipe.client == HFILE(~0));
    717             Q_ASSERT(sink->pipe.server == HPIPE(~0) && sink->pipe.client == HFILE(~0));
    718 
    719             Channel::Pipe pipe;
    720             createPipe(OutPipe, pipe);
    721             sink->pipe.client = pipe.client;
    722             source->pipe.server = pipe.server;
    723 
    724             return true;
    725         }
     725            // we are the sink (and the server)
     726            Q_ASSERT(channel.type == Channel::PipeSink);
     727            Q_ASSERT(&channel == &stdinChannel);
     728            Q_ASSERT(channel.process->stdoutChannel.process == this &&
     729                     channel.process->stdoutChannel.type == Channel::PipeSource);
     730            if (channel.process->stdoutChannel.pipe.server != HPIPE(~0)) {
     731                // the other process has already started and became the server
     732            } else {
     733                // note: OutPipe, since the type is relative to the other side
     734                createPipe(OutPipe, channel.pipe, "Sink");
     735            }
     736        }
     737
     738        return true;
    726739    }
    727740}
     
    877890        // save & copy the stdin handle
    878891        if ((arc = DosDupHandle(realStdin, &tmpStdin)) == NO_ERROR) {
    879             arc = DosDupHandle(stdinChannel.pipe.client, &realStdin);
     892            HFILE handle = stdinChannel.pipe.client;
     893            if (stdinChannel.type == Channel::PipeSink) {
     894                // process -> process redirection
     895                if (stdinChannel.pipe.server != HPIPE(~0)) {
     896                    // we are the server
     897                    handle = (HFILE)stdinChannel.pipe.server;
     898                } else {
     899                    // we are the client, use the server's variable
     900                    handle = stdinChannel.process->stdoutChannel.pipe.client;
     901                }
     902                Q_ASSERT(handle != HFILE(~0));
     903            }
     904            arc = DosDupHandle(handle, &realStdin);
    880905        }
    881906        if (arc != NO_ERROR) {
     
    890915            // save & copy the stdout handle
    891916            if ((arc = DosDupHandle(realStdout, &tmpStdout)) == NO_ERROR) {
    892                 arc = DosDupHandle(stdoutChannel.pipe.client, &realStdout);
     917                HFILE handle = stdoutChannel.pipe.client;
     918                if (stdoutChannel.type == Channel::PipeSource) {
     919                    // process -> process redirection
     920                    if (stdoutChannel.pipe.server != HPIPE(~0)) {
     921                        // we are the server
     922                        handle = (HFILE)stdoutChannel.pipe.server;
     923                    } else {
     924                        // we are the client, use the server's variable
     925                        handle = stdoutChannel.process->stdinChannel.pipe.client;
     926                    }
     927                    Q_ASSERT(handle != HFILE(~0));
     928                }
     929                arc = DosDupHandle(handle, &realStdout);
    893930            }
    894931            if (arc != NO_ERROR) {
     
    904941                // merge stdout and stderr if asked to
    905942                if (processChannelMode == QProcess::MergedChannels) {
    906                     arc = DosDupHandle(stdoutChannel.pipe.client, &realStderr);
     943                    arc = DosDupHandle(realStdout, &realStderr);
    907944                } else {
    908945                    arc = DosDupHandle(stderrChannel.pipe.client, &realStderr);
     
    959996    this->pid = Q_PID(pid);
    960997
    961     // close the client ends (they are no more necessary)
    962     if (stdinChannel.pipe.client != HFILE(~0)) {
    963         DosClose(stdinChannel.pipe.client);
    964         stdinChannel.pipe.client = HFILE(~0);
    965     }
    966     if (stdoutChannel.pipe.client != HFILE(~0)) {
    967         DosClose(stdoutChannel.pipe.client);
    968         stdoutChannel.pipe.client = HFILE(~0);
     998    // close the client ends inherited by the started process (it's necessary to
     999    // make sure that the started process owns the only handle to the client end
     1000    // and when it closes this handle the other party will notice it and e.g.
     1001    // stop waiting for new data).
     1002
     1003    if (stdinChannel.type == Channel::PipeSink) {
     1004        // process -> process redirection
     1005        if (stdinChannel.pipe.server != HPIPE(~0)) {
     1006            // we are the server, leave the handle for the other party
     1007        } else {
     1008            // we are the client, close the handle
     1009            DosClose(stdinChannel.process->stdoutChannel.pipe.client);
     1010            stdinChannel.process->stdoutChannel.pipe.client = HFILE(~0);
     1011        }
     1012    } else {
     1013        if (stdinChannel.pipe.client != HFILE(~0)) {
     1014            DosClose(stdinChannel.pipe.client);
     1015            stdinChannel.pipe.client = HFILE(~0);
     1016        }
     1017    }
     1018    if (stdoutChannel.type == Channel::PipeSource) {
     1019        // process -> process redirection
     1020        if (stdoutChannel.pipe.server != HPIPE(~0)) {
     1021            // we are the server, leave the handle for the other party
     1022        } else {
     1023            // we are the client, close the handle
     1024            DosClose(stdoutChannel.process->stdinChannel.pipe.client);
     1025            stdoutChannel.process->stdinChannel.pipe.client = HFILE(~0);
     1026        }
     1027    } else {
     1028        if (stdoutChannel.pipe.client != HFILE(~0)) {
     1029            DosClose(stdoutChannel.pipe.client);
     1030            stdoutChannel.pipe.client = HFILE(~0);
     1031        }
    9691032    }
    9701033    if (stderrChannel.pipe.client != HFILE(~0)) {
  • TabularUnified trunk/src/corelib/io/qprocess_p.h

    r203 r210  
    185185#if defined(Q_OS_OS2)
    186186    enum PipeType { InPipe = 0, OutPipe = 1, ErrPipe = 2 };
    187     bool createPipe(PipeType type, Channel::Pipe &pipe);
     187    bool createPipe(PipeType type, Channel::Pipe &pipe, const char *name = 0);
    188188    void destroyPipe(Channel::Pipe &pipe);
    189189#else
Note: See TracChangeset for help on using the changeset viewer.