diff options
author | Joerg Bornemann <joerg.bornemann@qt.io> | 2017-06-12 14:37:39 +0200 |
---|---|---|
committer | Joerg Bornemann <joerg.bornemann@qt.io> | 2017-06-26 05:05:38 +0000 |
commit | 5c6210e3452f78cab2f58887e747eb5cb2501f70 (patch) | |
tree | bc310dfa08032700155682f7b920c89ea6bd8a1d /src/corelib/kernel/qeventdispatcher_win.cpp | |
parent | 58d3a3eda271ad696d5df6f16b09bad97f9b54a1 (diff) | |
download | qtbase-5c6210e3452f78cab2f58887e747eb5cb2501f70.tar.gz |
Support more than 62 instances of QWinEventNotifier
QWinEventNotifiers were limited to 62 instances, because of
WaitForMultipleObject's limitation to MAXIMUM_WAIT_OBJECTS - 1 handles.
Use the RegisterWaitForSingleObject API which does not have this
restriction and executes waits in threads managed by the system. A
central manual reset event per event dispatcher is signaled in the
RegisterWaitForSingleObject callback and waited for in the event loop.
[ChangeLog][QtCore][QWinEventNotifier] QWinEventNotifier is not
restricted to 62 instances anymore.
Task-number: QTBUG-8819
Change-Id: I2c749951453a4b699cc50dada0d6017440b67a4a
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Diffstat (limited to 'src/corelib/kernel/qeventdispatcher_win.cpp')
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_win.cpp | 67 |
1 files changed, 41 insertions, 26 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 0952464f53..fc34dd0a6b 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -53,6 +53,7 @@ #include "qcoreapplication_p.h" #include <private/qthread_p.h> #include <private/qmutexpool_p.h> +#include <private/qwineventnotifier_p.h> QT_BEGIN_NAMESPACE @@ -96,13 +97,14 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA QEventDispatcherWin32Private::QEventDispatcherWin32Private() : threadId(GetCurrentThreadId()), interrupt(false), closingDown(false), internalHwnd(0), getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0), - wakeUps(0) - , activateNotifiersPosted(false) + wakeUps(0), activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL) { } QEventDispatcherWin32Private::~QEventDispatcherWin32Private() { + if (winEventNotifierActivatedEvent) + CloseHandle(winEventNotifierActivatedEvent); if (internalHwnd) DestroyWindow(internalHwnd); } @@ -537,12 +539,14 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) bool needWM_QT_SENDPOSTEDEVENTS = false; do { DWORD waitRet = 0; - HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1]; + DWORD nCount = 0; + HANDLE *pHandles = nullptr; + if (d->winEventNotifierActivatedEvent) { + nCount = 1; + pHandles = &d->winEventNotifierActivatedEvent; + } QVarLengthArray<MSG> processedTimers; while (!d->interrupt) { - DWORD nCount = d->winEventNotifierList.count(); - Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1); - MSG msg; bool haveMessage; @@ -584,8 +588,6 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) } if (!haveMessage) { // no message - check for signalled objects - for (int i=0; i<(int)nCount; i++) - pHandles[i] = d->winEventNotifierList.at(i)->handle(); waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE); if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) { // a new message has arrived, process it @@ -626,7 +628,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) DispatchMessage(&msg); } } else if (waitRet - WAIT_OBJECT_0 < nCount) { - d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); + activateEventNotifiers(); } else { // nothing todo so break break; @@ -639,16 +641,11 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) && !d->interrupt && (flags & QEventLoop::WaitForMoreEvents)); if (canWait) { - DWORD nCount = d->winEventNotifierList.count(); - Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1); - for (int i=0; i<(int)nCount; i++) - pHandles[i] = d->winEventNotifierList.at(i)->handle(); - emit aboutToBlock(); waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); emit awake(); if (waitRet - WAIT_OBJECT_0 < nCount) { - d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); + activateEventNotifiers(); retVal = true; } } @@ -906,12 +903,12 @@ bool QEventDispatcherWin32::registerEventNotifier(QWinEventNotifier *notifier) if (d->winEventNotifierList.contains(notifier)) return true; - if (d->winEventNotifierList.count() >= MAXIMUM_WAIT_OBJECTS - 2) { - qWarning("QWinEventNotifier: Cannot have more than %d enabled at one time", MAXIMUM_WAIT_OBJECTS - 2); - return false; - } d->winEventNotifierList.append(notifier); - return true; + + if (!d->winEventNotifierActivatedEvent) + d->winEventNotifierActivatedEvent = CreateEvent(0, TRUE, FALSE, nullptr); + + return QWinEventNotifierPrivate::get(notifier)->registerWaitObject(); } void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier) @@ -927,17 +924,35 @@ void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier) Q_D(QEventDispatcherWin32); int i = d->winEventNotifierList.indexOf(notifier); - if (i != -1) - d->winEventNotifierList.takeAt(i); + if (i == -1) + return; + d->winEventNotifierList.takeAt(i); + QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier); + if (nd->waitHandle) + nd->unregisterWaitObject(); } void QEventDispatcherWin32::activateEventNotifiers() { Q_D(QEventDispatcherWin32); - //### this could break if events are removed/added in the activation - for (int i=0; i<d->winEventNotifierList.count(); i++) { - if (WaitForSingleObjectEx(d->winEventNotifierList.at(i)->handle(), 0, TRUE) == WAIT_OBJECT_0) - d->activateEventNotifier(d->winEventNotifierList.at(i)); + ResetEvent(d->winEventNotifierActivatedEvent); + + // Iterate backwards, because the notifier might remove itself on activate(). + for (int i = d->winEventNotifierList.count(); --i >= 0;) { + QWinEventNotifier *notifier = d->winEventNotifierList.at(i); + QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier); + if (WaitForSingleObject(nd->handleToEvent, 0) == WAIT_OBJECT_0) { + nd->unregisterWaitObject(); + d->activateEventNotifier(notifier); + } + } + + // Re-register the remaining activated notifiers. + for (int i = 0; i < d->winEventNotifierList.count(); ++i) { + QWinEventNotifier *notifier = d->winEventNotifierList.at(i); + QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier); + if (nd->waitHandle || !nd->registerWaitObject()) + return; } } |