diff --git a/src/corelib/io/qwinoverlappedionotifier.cpp b/src/corelib/io/qwinoverlappedionotifier.cpp index 33583afb78..06746c0597 100644 --- a/src/corelib/io/qwinoverlappedionotifier.cpp +++ b/src/corelib/io/qwinoverlappedionotifier.cpp @@ -41,6 +41,7 @@ #include "qwinoverlappedionotifier_p.h" #include +#include #include #include #include @@ -292,6 +293,36 @@ void QWinOverlappedIoNotifier::setEnabled(bool enabled) d->iocp->unregisterNotifier(d); } +/*! + * Wait synchronously for any notified signal. + * + * The function returns a pointer to the OVERLAPPED object corresponding to the completed I/O + * operation. In case no I/O operation was completed during the \a msec timeout, this function + * returns a null pointer. + */ +OVERLAPPED *QWinOverlappedIoNotifier::waitForAnyNotified(int msecs) +{ + Q_D(QWinOverlappedIoNotifier); + if (!d->iocp->isRunning()) { + qWarning("Called QWinOverlappedIoNotifier::waitForAnyNotified on inactive notifier."); + return 0; + } + + if (msecs == 0) + d->iocp->drainQueue(); + + switch (WaitForSingleObject(d->hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs))) { + case WAIT_OBJECT_0: + ReleaseSemaphore(d->hSemaphore, 1, NULL); + return d->_q_notified(); + case WAIT_TIMEOUT: + return 0; + default: + qErrnoWarning("QWinOverlappedIoNotifier::waitForAnyNotified: WaitForSingleObject failed."); + return 0; + } +} + /*! * Wait synchronously for the notified signal. * @@ -300,28 +331,21 @@ void QWinOverlappedIoNotifier::setEnabled(bool enabled) */ bool QWinOverlappedIoNotifier::waitForNotified(int msecs, OVERLAPPED *overlapped) { - Q_D(QWinOverlappedIoNotifier); - if (!d->iocp->isRunning()) { - qWarning("Called QWinOverlappedIoNotifier::waitForNotified on inactive notifier."); - return false; - } - + int t = msecs; + QElapsedTimer stopWatch; + stopWatch.start(); forever { - if (msecs == 0) - d->iocp->drainQueue(); - DWORD result = WaitForSingleObject(d->hSemaphore, msecs == -1 ? INFINITE : DWORD(msecs)); - if (result == WAIT_OBJECT_0) { - ReleaseSemaphore(d->hSemaphore, 1, NULL); - if (d->_q_notified() == overlapped) - return true; - continue; - } else if (result == WAIT_TIMEOUT) { + OVERLAPPED *triggeredOverlapped = waitForAnyNotified(t); + if (!triggeredOverlapped) return false; + if (triggeredOverlapped == overlapped) + return true; + if (msecs != -1) { + t = msecs - stopWatch.elapsed(); + if (t < 0) + return false; } } - - qErrnoWarning("QWinOverlappedIoNotifier::waitForNotified: WaitForSingleObject failed."); - return false; } /*! diff --git a/src/corelib/io/qwinoverlappedionotifier_p.h b/src/corelib/io/qwinoverlappedionotifier_p.h index f90fd2e615..25c0f3a081 100644 --- a/src/corelib/io/qwinoverlappedionotifier_p.h +++ b/src/corelib/io/qwinoverlappedionotifier_p.h @@ -76,6 +76,7 @@ public: Qt::HANDLE handle() const; void setEnabled(bool enabled); + OVERLAPPED *waitForAnyNotified(int msecs); bool waitForNotified(int msecs, OVERLAPPED *overlapped); Q_SIGNALS: diff --git a/tests/auto/corelib/io/qwinoverlappedionotifier/tst_qwinoverlappedionotifier.cpp b/tests/auto/corelib/io/qwinoverlappedionotifier/tst_qwinoverlappedionotifier.cpp index 8321f76bec..16f94e7c5d 100644 --- a/tests/auto/corelib/io/qwinoverlappedionotifier/tst_qwinoverlappedionotifier.cpp +++ b/tests/auto/corelib/io/qwinoverlappedionotifier/tst_qwinoverlappedionotifier.cpp @@ -58,6 +58,7 @@ private slots: void readFile(); void waitForNotified_data(); void waitForNotified(); + void waitForAnyNotified(); void brokenPipe(); void multipleOperations(); @@ -195,6 +196,45 @@ void tst_QWinOverlappedIoNotifier::waitForNotified() QCOMPARE(notifier.waitForNotified(100, &overlapped), false); } +void tst_QWinOverlappedIoNotifier::waitForAnyNotified() +{ + const QString fileName = QDir::toNativeSeparators(sourceFileInfo.absoluteFilePath()); + const int readBufferSize = sourceFileInfo.size(); + + QWinOverlappedIoNotifier notifier; + HANDLE hFile = CreateFile(reinterpret_cast(fileName.utf16()), + GENERIC_READ, FILE_SHARE_READ, + NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + notifier.setHandle(hFile); + notifier.setEnabled(true); + QVERIFY(notifier.waitForAnyNotified(100) == 0); + + OVERLAPPED overlapped1; + ZeroMemory(&overlapped1, sizeof(OVERLAPPED)); + QByteArray buffer1(readBufferSize, 0); + BOOL readSuccess = ReadFile(hFile, buffer1.data(), buffer1.size(), NULL, &overlapped1); + QVERIFY(readSuccess || GetLastError() == ERROR_IO_PENDING); + + OVERLAPPED overlapped2; + ZeroMemory(&overlapped2, sizeof(OVERLAPPED)); + QByteArray buffer2(readBufferSize, 0); + readSuccess = ReadFile(hFile, buffer2.data(), buffer2.size(), NULL, &overlapped2); + QVERIFY(readSuccess || GetLastError() == ERROR_IO_PENDING); + + QSet overlappedObjects; + overlappedObjects << &overlapped1 << &overlapped2; + + for (int i = 1; i <= 2; ++i) { + OVERLAPPED *notifiedOverlapped = notifier.waitForAnyNotified(3000); + QVERIFY(overlappedObjects.contains(notifiedOverlapped)); + overlappedObjects.remove(notifiedOverlapped); + } + + CloseHandle(hFile); + QVERIFY(overlappedObjects.isEmpty()); + QVERIFY(notifier.waitForAnyNotified(100) == 0); +} + void tst_QWinOverlappedIoNotifier::brokenPipe() { QWinOverlappedIoNotifier notifier;