diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/io/qwindowspipereader.cpp | 162 | ||||
-rw-r--r-- | src/corelib/io/qwindowspipereader_p.h | 12 |
2 files changed, 83 insertions, 91 deletions
diff --git a/src/corelib/io/qwindowspipereader.cpp b/src/corelib/io/qwindowspipereader.cpp index 2938a7501b..7979ee77df 100644 --- a/src/corelib/io/qwindowspipereader.cpp +++ b/src/corelib/io/qwindowspipereader.cpp @@ -40,11 +40,11 @@ ****************************************************************************/ #include "qwindowspipereader_p.h" +#include "qwinoverlappedionotifier_p.h" #include <qdebug.h> #include <qelapsedtimer.h> #include <qeventloop.h> #include <qtimer.h> -#include <qwineventnotifier.h> QT_BEGIN_NAMESPACE @@ -53,21 +53,23 @@ QWindowsPipeReader::QWindowsPipeReader(QObject *parent) handle(INVALID_HANDLE_VALUE), readBufferMaxSize(0), actualReadBufferSize(0), + readSequenceStarted(false), emitReadyReadTimer(new QTimer(this)), - pipeBroken(false) + pipeBroken(false), + readyReadEmitted(false) { emitReadyReadTimer->setSingleShot(true); connect(emitReadyReadTimer, SIGNAL(timeout()), SIGNAL(readyRead())); - - ZeroMemory(&overlapped, sizeof(overlapped)); - overlapped.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - dataReadNotifier = new QWinEventNotifier(overlapped.hEvent, this); - connect(dataReadNotifier, SIGNAL(activated(HANDLE)), SLOT(readEventSignalled())); + dataReadNotifier = new QWinOverlappedIoNotifier(this); + connect(dataReadNotifier, &QWinOverlappedIoNotifier::notified, this, &QWindowsPipeReader::notified); } QWindowsPipeReader::~QWindowsPipeReader() { - CloseHandle(overlapped.hEvent); + if (readSequenceStarted) { + CancelIoEx(handle, &overlapped); + dataReadNotifier->waitForNotified(-1); + } } /*! @@ -78,8 +80,13 @@ void QWindowsPipeReader::setHandle(HANDLE hPipeReadEnd) readBuffer.clear(); actualReadBufferSize = 0; handle = hPipeReadEnd; + ZeroMemory(&overlapped, sizeof(overlapped)); pipeBroken = false; - dataReadNotifier->setEnabled(true); + readyReadEmitted = false; + if (hPipeReadEnd != INVALID_HANDLE_VALUE) { + dataReadNotifier->setHandle(hPipeReadEnd); + dataReadNotifier->setEnabled(true); + } } /*! @@ -92,7 +99,6 @@ void QWindowsPipeReader::stop() dataReadNotifier->setEnabled(false); readSequenceStarted = false; handle = INVALID_HANDLE_VALUE; - ResetEvent(overlapped.hEvent); } /*! @@ -149,19 +155,18 @@ bool QWindowsPipeReader::canReadLine() const /*! \internal Will be called whenever the read operation completes. - Returns true, if readyRead() has been emitted. */ -bool QWindowsPipeReader::readEventSignalled() +void QWindowsPipeReader::notified(DWORD numberOfBytesRead, DWORD errorCode) { - if (!completeAsyncRead()) { + if (!completeAsyncRead(numberOfBytesRead, errorCode)) { pipeBroken = true; emit pipeClosed(); - return false; + return; } startAsyncRead(); emitReadyReadTimer->stop(); + readyReadEmitted = true; emit readyRead(); - return true; } /*! @@ -170,56 +175,49 @@ bool QWindowsPipeReader::readEventSignalled() */ void QWindowsPipeReader::startAsyncRead() { - do { - DWORD bytesToRead = checkPipeState(); - if (pipeBroken) - return; + DWORD bytesToRead = qMax(checkPipeState(), minReadBufferSize); + if (pipeBroken) + return; + if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { + bytesToRead = readBufferMaxSize - readBuffer.size(); if (bytesToRead == 0) { - // There are no bytes in the pipe but we need to - // start the overlapped read with some buffer size. - bytesToRead = initialReadBufferSize; - } - - if (readBufferMaxSize && bytesToRead > (readBufferMaxSize - readBuffer.size())) { - bytesToRead = readBufferMaxSize - readBuffer.size(); - if (bytesToRead == 0) { - // Buffer is full. User must read data from the buffer - // before we can read more from the pipe. - return; - } + // Buffer is full. User must read data from the buffer + // before we can read more from the pipe. + return; } + } - char *ptr = readBuffer.reserve(bytesToRead); + char *ptr = readBuffer.reserve(bytesToRead); - readSequenceStarted = true; - if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) { - completeAsyncRead(); - } else { - switch (GetLastError()) { - case ERROR_IO_PENDING: - // This is not an error. We're getting notified, when data arrives. - return; - case ERROR_MORE_DATA: - // This is not an error. The synchronous read succeeded. - // We're connected to a message mode pipe and the message - // didn't fit into the pipe's system buffer. - completeAsyncRead(); - break; - case ERROR_PIPE_NOT_CONNECTED: - { - // It may happen, that the other side closes the connection directly - // after writing data. Then we must set the appropriate socket state. - pipeBroken = true; - emit pipeClosed(); - return; - } - default: - emit winError(GetLastError(), QLatin1String("QWindowsPipeReader::startAsyncRead")); - return; + readSequenceStarted = true; + if (ReadFile(handle, ptr, bytesToRead, NULL, &overlapped)) { + // We get notified by the QWinOverlappedIoNotifier - even in the synchronous case. + return; + } else { + switch (GetLastError()) { + case ERROR_IO_PENDING: + // This is not an error. We're getting notified, when data arrives. + return; + case ERROR_MORE_DATA: + // This is not an error. The synchronous read succeeded. + // We're connected to a message mode pipe and the message + // didn't fit into the pipe's system buffer. + // We're getting notified by the QWinOverlappedIoNotifier. + break; + case ERROR_PIPE_NOT_CONNECTED: + { + // It may happen, that the other side closes the connection directly + // after writing data. Then we must set the appropriate socket state. + pipeBroken = true; + emit pipeClosed(); + return; } + default: + emit winError(GetLastError(), QLatin1String("QWindowsPipeReader::startAsyncRead")); + return; } - } while (!readSequenceStarted); + } } /*! @@ -227,26 +225,24 @@ void QWindowsPipeReader::startAsyncRead() Sets the correct size of the read buffer after a read operation. Returns false, if an error occurred or the connection dropped. */ -bool QWindowsPipeReader::completeAsyncRead() +bool QWindowsPipeReader::completeAsyncRead(DWORD bytesRead, DWORD errorCode) { - ResetEvent(overlapped.hEvent); readSequenceStarted = false; - DWORD bytesRead; - if (!GetOverlappedResult(handle, &overlapped, &bytesRead, TRUE)) { - switch (GetLastError()) { - case ERROR_MORE_DATA: - // This is not an error. We're connected to a message mode - // pipe and the message didn't fit into the pipe's system - // buffer. We will read the remaining data in the next call. - break; - case ERROR_BROKEN_PIPE: - case ERROR_PIPE_NOT_CONNECTED: - return false; - default: - emit winError(GetLastError(), QLatin1String("QWindowsPipeReader::completeAsyncRead")); - return false; - } + switch (errorCode) { + case ERROR_SUCCESS: + break; + case ERROR_MORE_DATA: + // This is not an error. We're connected to a message mode + // pipe and the message didn't fit into the pipe's system + // buffer. We will read the remaining data in the next call. + break; + case ERROR_BROKEN_PIPE: + case ERROR_PIPE_NOT_CONNECTED: + return false; + default: + emit winError(errorCode, QLatin1String("QWindowsPipeReader::completeAsyncRead")); + return false; } actualReadBufferSize += bytesRead; @@ -281,17 +277,11 @@ DWORD QWindowsPipeReader::checkPipeState() */ bool QWindowsPipeReader::waitForReadyRead(int msecs) { - Q_ASSERT(readSequenceStarted); - DWORD result = WaitForSingleObject(overlapped.hEvent, msecs == -1 ? INFINITE : msecs); - switch (result) { - case WAIT_OBJECT_0: - return readEventSignalled(); - case WAIT_TIMEOUT: - return false; - } - - qWarning("QWindowsPipeReader::waitForReadyRead WaitForSingleObject failed with error code %d.", int(GetLastError())); - return false; + if (!readSequenceStarted) + return false; + readyReadEmitted = false; + dataReadNotifier->waitForNotified(msecs); + return readyReadEmitted; } /*! diff --git a/src/corelib/io/qwindowspipereader_p.h b/src/corelib/io/qwindowspipereader_p.h index 132c3540c0..2d979c337b 100644 --- a/src/corelib/io/qwindowspipereader_p.h +++ b/src/corelib/io/qwindowspipereader_p.h @@ -66,7 +66,7 @@ QT_BEGIN_NAMESPACE QT_MODULE(Core) -class QWinEventNotifier; +class QWinOverlappedIoNotifier; class Q_CORE_EXPORT QWindowsPipeReader : public QObject { @@ -89,7 +89,7 @@ public: bool waitForPipeClosed(int msecs); void startAsyncRead(); - bool completeAsyncRead(); + bool isReadOperationActive() const { return readSequenceStarted; } Q_SIGNALS: void winError(ulong, const QString &); @@ -97,22 +97,24 @@ Q_SIGNALS: void pipeClosed(); private Q_SLOTS: - bool readEventSignalled(); + void notified(DWORD numberOfBytesRead, DWORD errorCode); private: + bool completeAsyncRead(DWORD bytesRead, DWORD errorCode); DWORD checkPipeState(); private: HANDLE handle; OVERLAPPED overlapped; - QWinEventNotifier *dataReadNotifier; + QWinOverlappedIoNotifier *dataReadNotifier; qint64 readBufferMaxSize; QRingBuffer readBuffer; int actualReadBufferSize; bool readSequenceStarted; QTimer *emitReadyReadTimer; bool pipeBroken; - static const qint64 initialReadBufferSize = 4096; + bool readyReadEmitted; + static const DWORD minReadBufferSize = 4096; }; QT_END_NAMESPACE |