Allow QWinEventNotifier to coexist with waiting functions

Many subclasses of QIODevice have a functionality to block execution
until some asynchronous I/O operation completes. In case we are using
QWinEventNotifier, a typical reimplemented waitFor{ReadyRead
|BytesWritten}() function could look like:

  if (WaitForSingleObject(notifier.handle(),...) == WAIT_OBJECT_0) {
      notifier.setEnabled(false);
      ResetEvent(notifier.handle());

      bool res = GetOverlappedResult(...);
      ...
      return true;
  }

Despite the fact that the operation ends synchronously, it leaves the
notifier in a state that indicates it has received the event, so its
next call to setEnabled(true) will produce a fake notification.

So, we should reset a notifier's history before enabling it again.

Change-Id: I62a9dd809ce6a7a40e9d8038f2a49299b36f8142
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Reviewed-by: Joerg Bornemann <joerg.bornemann@qt.io>
This commit is contained in:
Alex Trotsenko 2018-03-22 17:34:16 +02:00
parent 09f3b19f98
commit cdbd68fc2f
2 changed files with 25 additions and 3 deletions

View File

@ -157,7 +157,6 @@ void QWinEventNotifier::setHandle(HANDLE hEvent)
Q_D(QWinEventNotifier);
setEnabled(false);
d->handleToEvent = hEvent;
d->signaledCount = 0;
}
/*!
@ -209,10 +208,12 @@ void QWinEventNotifier::setEnabled(bool enable)
return;
}
if (enable)
if (enable) {
d->signaledCount = 0;
eventDispatcher->registerEventNotifier(this);
else
} else {
eventDispatcher->unregisterEventNotifier(this);
}
}
/*!

View File

@ -46,6 +46,7 @@ protected slots:
private slots:
void simple_data();
void simple();
void blockedWaiting();
void manyNotifiers();
void disableNotifiersInActivatedSlot_data();
void disableNotifiersInActivatedSlot();
@ -104,6 +105,26 @@ void tst_QWinEventNotifier::simple()
QVERIFY(simpleActivated);
}
void tst_QWinEventNotifier::blockedWaiting()
{
simpleHEvent = CreateEvent(0, true, false, 0);
QWinEventNotifier n(simpleHEvent);
QObject::connect(&n, &QWinEventNotifier::activated,
this, &tst_QWinEventNotifier::simple_activated);
simpleActivated = false;
SetEvent(simpleHEvent);
QCOMPARE(WaitForSingleObject(simpleHEvent, 1000), WAIT_OBJECT_0);
n.setEnabled(false);
ResetEvent(simpleHEvent);
n.setEnabled(true);
QTestEventLoop::instance().enterLoop(1);
QVERIFY(QTestEventLoop::instance().timeout());
QVERIFY(!simpleActivated);
}
class EventWithNotifier : public QObject
{
Q_OBJECT