Changeset 188


Ignore:
Timestamp:
Nov 21, 2008, 4:36:19 AM (17 years ago)
Author:
dmik
Message:

Kernel: QPrcess: Another attempt to fix unexpected pipe handle reusal (ticket:51).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kernel/qprocess_pm.cpp

    r186 r188  
    143143    QProcessPrivate( QProcess *proc )
    144144    {
    145         stdinBufRead = 0;
     145        stdinBufRead = 0;
    146146        pipeStdin = HP_NULL;
    147147        pid = PID_NULL;
    148         exitValuesCalculated = FALSE;
    149 
    150         lookup = new QTimer( proc );
    151         qApp->connect( lookup, SIGNAL(timeout()), proc, SLOT(timeout()) );
     148        exitValuesCalculated = FALSE;
     149
     150        lookup = new QTimer( proc );
     151        qApp->connect( lookup, SIGNAL(timeout()), proc, SLOT(timeout()) );
    152152    }
    153153
    154154    ~QProcessPrivate()
    155155    {
    156         reset();
     156        reset();
    157157    }
    158158
    159159    void reset()
    160160    {
    161         while ( !stdinBuf.isEmpty() ) {
    162             delete stdinBuf.dequeue();
    163         }
    164         stdinBufRead = 0;
    165         closeHandles();
     161        while ( !stdinBuf.isEmpty() ) {
     162            delete stdinBuf.dequeue();
     163        }
     164        stdinBufRead = 0;
     165        closeHandles();
    166166        stdout.buf.clear();
    167167        stderr.buf.clear();
    168         pid = PID_NULL;
    169         exitValuesCalculated = FALSE;
     168        pid = PID_NULL;
     169        exitValuesCalculated = FALSE;
    170170    }
    171171
     
    237237    bool addProcess( QProcess *proc );
    238238    void removeProcess( QProcessPrivate *d,
    239                         QProcessPrivate::Pipe *pipe = NULL );
     239                        QProcessPrivate::Pipe *pipe = NULL,
     240                        bool inMsgHandler = false);
    240241
    241242    void monitor();
     
    405406
    406407void QProcessMonitor::removeProcess( QProcessPrivate *d,
    407                                      QProcessPrivate::Pipe *pipe /* = NULL */)
     408                                     QProcessPrivate::Pipe *pipe /* = NULL */,
     409                                     bool inMsgHandler /* = false */)
    408410{
    409411#if defined(QT_QPROCESS_DEBUG)
     
    424426        return;
    425427    }
    426    
     428
     429    if ( !inMsgHandler ) {
     430        // process all messages in the message queue related to QProcessMonitor.
     431        // A failure to do so may lead to a situation when another QProcess
     432        // started before these messages are processed but after our ends of
     433        // pipes are closed (for example, by QProcessPrivate::reset()) gets the
     434        // same pipe handles from the system. Since pipe handles are also used
     435        // as keys, the delayed messages will then refer to the new QProcess
     436        // object they were not intended for. The fix is to remove "our"
     437        // messages from the queue now, before closing pipes (which will usually
     438        // be done right after this method).
     439   
     440        QMSG qmsg;
     441        while (WinPeekMsg (0, &qmsg, hwnd(), WM_U_PIPE_RDATA, WM_U_PIPE_CLOSE,
     442                           PM_REMOVE)) {
     443            qDebug( "msg=%08x", qmsg.msg );
     444            if ( qmsg.msg == WM_U_PIPE_CLOSE ) {
     445                QProcess *proc = (QProcess *) PVOIDFROMMP( qmsg.mp1 );
     446                USHORT key = SHORT1FROMMP( qmsg.mp2 );
     447                if ( proc == pipeKeys.find( key ) && proc->d == d ) {
     448                    // skip the close message for ourselves as we will do all
     449                    // the necessary stuff
     450                    continue;
     451                }
     452            }
     453            WinDispatchMsg( 0, &qmsg );
     454        }
     455    }
     456
    427457    if ( pipe ) {
    428458        removePipe( pipe );
     
    559589            if ( proc == pipeKeys.find( key ) ) {
    560590#if defined(QT_QPROCESS_DEBUG)
    561             qDebug( "QProcessMonitor::WM_U_PIPE_RDATA: proc=%p (%s/%s) d=%p "
    562                     "key=%04hX",
    563                     proc, proc->name(), proc->className(), proc->d, key );
     591                qDebug( "QProcessMonitor::WM_U_PIPE_RDATA: proc=%p (%s/%s) d=%p "
     592                        "key=%04hX",
     593                        proc, proc->name(), proc->className(), proc->d, key );
    564594#endif
    565595                QProcessPrivate *d = proc->d;
     
    596626                    Q_ASSERT( pipe->closed );
    597627                    // remove the single pipe from watching
    598                     removeProcess( d, pipe );
     628                    removeProcess( d, pipe, TRUE /* inMsgHandler */ );
    599629                    // close the pipe since no more necessary
    600630                    // (pipe is not watched anymore, no need to lock access)
     
    686716        // the client's end of pipe has been closed, so close our end as well
    687717        if ( processMonitor && pipe->key != KEY_NULL ) {
    688             // WM_U_PIPE_CLOSE has been posted but not yet processed: do
    689             // nothing in this case and let it do the close job. This is vital
    690             // since if we close the pipe now then it's possible that another
    691             // QProcess instance created in the meantime will get a pipe with
    692             // the same handle from the system (and therefore with the same key)
    693             // so our pending WM_U_PIPE_CLOSE message will attempt to close an
    694             // invalid (foreign) pipe
    695         }
    696         else
     718            // WM_U_PIPE_CLOSE has been posted but not yet processed
     719            // (the following call make sure it will be processed)
     720            processMonitor->removeProcess( this, pipe );
     721        }
     722        else
    697723            closePipe( pipe );
    698724    }
     
    770796
    771797    if ( _arguments.isEmpty() )
    772         return FALSE;
     798        return FALSE;
    773799
    774800#if defined(QT_QPROCESS_USE_DOSEXECPGM)
     
    14791505    QProcess *that = (QProcess *) this;
    14801506
     1507    /// @todo the below comment is not relevant any more since removeProcess()
     1508    //  will dispatch all related messages including WM_U_PIPE_RDATA. Therefore,
     1509    //  this code should not be needed anymore.
     1510#if 0
    14811511    // There might be data to read, but WM_U_PIPE_RDATA messages won't be
    14821512    // converted to signals after removeProcess() is called below. Therefore,
     
    14871517    if ( d->readPipe( &d->stderr ) )
    14881518        emit that->readyReadStderr();
     1519#endif
    14891520   
    14901521    // compute the exit values
Note: See TracChangeset for help on using the changeset viewer.