QWinOverlappedIoNotifier: Add an extended waitForAnyNotified() method
The existing waitForNotified method has the design limitation that it doesn't allow the tracking of multiple I/O operations on a single file handle. Therefore we introduce an additional method waitForAnyNotified that returns a pointer to the triggered OVERLAPPED object. Change-Id: I536ed7f6828daa2b0ce03f2d662eeb10aa89ca99 Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@digia.com> Reviewed-by: Joerg Bornemann <joerg.bornemann@digia.com>
This commit is contained in:
parent
0ab9188ad7
commit
aefa611f0c
@ -41,6 +41,7 @@
|
||||
|
||||
#include "qwinoverlappedionotifier_p.h"
|
||||
#include <qdebug.h>
|
||||
#include <qelapsedtimer.h>
|
||||
#include <qmutex.h>
|
||||
#include <qpointer.h>
|
||||
#include <qqueue.h>
|
||||
@ -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)
|
||||
OVERLAPPED *triggeredOverlapped = waitForAnyNotified(t);
|
||||
if (!triggeredOverlapped)
|
||||
return false;
|
||||
if (triggeredOverlapped == overlapped)
|
||||
return true;
|
||||
continue;
|
||||
} else if (result == WAIT_TIMEOUT) {
|
||||
if (msecs != -1) {
|
||||
t = msecs - stopWatch.elapsed();
|
||||
if (t < 0)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
qErrnoWarning("QWinOverlappedIoNotifier::waitForNotified: WaitForSingleObject failed.");
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -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:
|
||||
|
@ -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<const wchar_t*>(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<OVERLAPPED *> 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;
|
||||
|
Loading…
Reference in New Issue
Block a user