Support more than 62 instances of QWinEventNotifier, take 2
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. Task-number: QTBUG-8819 Change-Id: I3061811c18e669becf9de603bbdd7ba96e4d2fcd Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@qt.io> Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
parent
7b2debda2b
commit
85403d0af0
@ -79,7 +79,8 @@ win32 {
|
|||||||
kernel/qsharedmemory_win.cpp \
|
kernel/qsharedmemory_win.cpp \
|
||||||
kernel/qsystemsemaphore_win.cpp
|
kernel/qsystemsemaphore_win.cpp
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
kernel/qwineventnotifier.h
|
kernel/qwineventnotifier.h \
|
||||||
|
kernel/qwineventnotifier_p.h
|
||||||
|
|
||||||
winrt {
|
winrt {
|
||||||
SOURCES += kernel/qeventdispatcher_winrt.cpp
|
SOURCES += kernel/qeventdispatcher_winrt.cpp
|
||||||
|
@ -53,6 +53,7 @@
|
|||||||
#include "qcoreapplication_p.h"
|
#include "qcoreapplication_p.h"
|
||||||
#include <private/qthread_p.h>
|
#include <private/qthread_p.h>
|
||||||
#include <private/qmutexpool_p.h>
|
#include <private/qmutexpool_p.h>
|
||||||
|
#include <private/qwineventnotifier_p.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@ -96,13 +97,14 @@ LRESULT QT_WIN_CALLBACK qt_internal_proc(HWND hwnd, UINT message, WPARAM wp, LPA
|
|||||||
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
|
QEventDispatcherWin32Private::QEventDispatcherWin32Private()
|
||||||
: threadId(GetCurrentThreadId()), interrupt(false), closingDown(false), internalHwnd(0),
|
: threadId(GetCurrentThreadId()), interrupt(false), closingDown(false), internalHwnd(0),
|
||||||
getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0),
|
getMessageHook(0), serialNumber(0), lastSerialNumber(0), sendPostedEventsWindowsTimerId(0),
|
||||||
wakeUps(0)
|
wakeUps(0), activateNotifiersPosted(false), winEventNotifierActivatedEvent(NULL)
|
||||||
, activateNotifiersPosted(false)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
QEventDispatcherWin32Private::~QEventDispatcherWin32Private()
|
QEventDispatcherWin32Private::~QEventDispatcherWin32Private()
|
||||||
{
|
{
|
||||||
|
if (winEventNotifierActivatedEvent)
|
||||||
|
CloseHandle(winEventNotifierActivatedEvent);
|
||||||
if (internalHwnd)
|
if (internalHwnd)
|
||||||
DestroyWindow(internalHwnd);
|
DestroyWindow(internalHwnd);
|
||||||
}
|
}
|
||||||
@ -537,12 +539,14 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||||||
bool needWM_QT_SENDPOSTEDEVENTS = false;
|
bool needWM_QT_SENDPOSTEDEVENTS = false;
|
||||||
do {
|
do {
|
||||||
DWORD waitRet = 0;
|
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;
|
QVarLengthArray<MSG> processedTimers;
|
||||||
while (!d->interrupt) {
|
while (!d->interrupt) {
|
||||||
DWORD nCount = d->winEventNotifierList.count();
|
|
||||||
Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1);
|
|
||||||
|
|
||||||
MSG msg;
|
MSG msg;
|
||||||
bool haveMessage;
|
bool haveMessage;
|
||||||
|
|
||||||
@ -584,8 +588,6 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||||||
}
|
}
|
||||||
if (!haveMessage) {
|
if (!haveMessage) {
|
||||||
// no message - check for signalled objects
|
// 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);
|
waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, 0, QS_ALLINPUT, MWMO_ALERTABLE);
|
||||||
if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) {
|
if ((haveMessage = (waitRet == WAIT_OBJECT_0 + nCount))) {
|
||||||
// a new message has arrived, process it
|
// a new message has arrived, process it
|
||||||
@ -626,7 +628,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
} else if (waitRet - WAIT_OBJECT_0 < nCount) {
|
} else if (waitRet - WAIT_OBJECT_0 < nCount) {
|
||||||
d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
|
activateEventNotifiers();
|
||||||
} else {
|
} else {
|
||||||
// nothing todo so break
|
// nothing todo so break
|
||||||
break;
|
break;
|
||||||
@ -639,16 +641,11 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags)
|
|||||||
&& !d->interrupt
|
&& !d->interrupt
|
||||||
&& (flags & QEventLoop::WaitForMoreEvents));
|
&& (flags & QEventLoop::WaitForMoreEvents));
|
||||||
if (canWait) {
|
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();
|
emit aboutToBlock();
|
||||||
waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
|
waitRet = MsgWaitForMultipleObjectsEx(nCount, pHandles, INFINITE, QS_ALLINPUT, MWMO_ALERTABLE | MWMO_INPUTAVAILABLE);
|
||||||
emit awake();
|
emit awake();
|
||||||
if (waitRet - WAIT_OBJECT_0 < nCount) {
|
if (waitRet - WAIT_OBJECT_0 < nCount) {
|
||||||
d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0));
|
activateEventNotifiers();
|
||||||
retVal = true;
|
retVal = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -906,12 +903,12 @@ bool QEventDispatcherWin32::registerEventNotifier(QWinEventNotifier *notifier)
|
|||||||
if (d->winEventNotifierList.contains(notifier))
|
if (d->winEventNotifierList.contains(notifier))
|
||||||
return true;
|
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);
|
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)
|
void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier)
|
||||||
@ -927,17 +924,35 @@ void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier)
|
|||||||
Q_D(QEventDispatcherWin32);
|
Q_D(QEventDispatcherWin32);
|
||||||
|
|
||||||
int i = d->winEventNotifierList.indexOf(notifier);
|
int i = d->winEventNotifierList.indexOf(notifier);
|
||||||
if (i != -1)
|
if (i == -1)
|
||||||
|
return;
|
||||||
d->winEventNotifierList.takeAt(i);
|
d->winEventNotifierList.takeAt(i);
|
||||||
|
QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier);
|
||||||
|
if (nd->waitHandle)
|
||||||
|
nd->unregisterWaitObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
void QEventDispatcherWin32::activateEventNotifiers()
|
void QEventDispatcherWin32::activateEventNotifiers()
|
||||||
{
|
{
|
||||||
Q_D(QEventDispatcherWin32);
|
Q_D(QEventDispatcherWin32);
|
||||||
//### this could break if events are removed/added in the activation
|
ResetEvent(d->winEventNotifierActivatedEvent);
|
||||||
for (int i=0; i<d->winEventNotifierList.count(); i++) {
|
|
||||||
if (WaitForSingleObjectEx(d->winEventNotifierList.at(i)->handle(), 0, TRUE) == WAIT_OBJECT_0)
|
// Iterate backwards, because the notifier might remove itself on activate().
|
||||||
d->activateEventNotifier(d->winEventNotifierList.at(i));
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,6 +161,7 @@ class Q_CORE_EXPORT QEventDispatcherWin32Private : public QAbstractEventDispatch
|
|||||||
public:
|
public:
|
||||||
QEventDispatcherWin32Private();
|
QEventDispatcherWin32Private();
|
||||||
~QEventDispatcherWin32Private();
|
~QEventDispatcherWin32Private();
|
||||||
|
static QEventDispatcherWin32Private *get(QEventDispatcherWin32 *q) { return q->d_func(); }
|
||||||
|
|
||||||
DWORD threadId;
|
DWORD threadId;
|
||||||
|
|
||||||
@ -192,6 +193,7 @@ public:
|
|||||||
void postActivateSocketNotifiers();
|
void postActivateSocketNotifiers();
|
||||||
void doWsaAsyncSelect(int socket, long event);
|
void doWsaAsyncSelect(int socket, long event);
|
||||||
|
|
||||||
|
HANDLE winEventNotifierActivatedEvent;
|
||||||
QList<QWinEventNotifier *> winEventNotifierList;
|
QList<QWinEventNotifier *> winEventNotifierList;
|
||||||
void activateEventNotifier(QWinEventNotifier * wen);
|
void activateEventNotifier(QWinEventNotifier * wen);
|
||||||
|
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
**
|
**
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#include "qwineventnotifier.h"
|
#include "qwineventnotifier_p.h"
|
||||||
|
|
||||||
#ifdef Q_OS_WINRT
|
#ifdef Q_OS_WINRT
|
||||||
#include "qeventdispatcher_winrt_p.h"
|
#include "qeventdispatcher_winrt_p.h"
|
||||||
@ -50,19 +50,6 @@
|
|||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QWinEventNotifierPrivate : public QObjectPrivate
|
|
||||||
{
|
|
||||||
Q_DECLARE_PUBLIC(QWinEventNotifier)
|
|
||||||
public:
|
|
||||||
QWinEventNotifierPrivate()
|
|
||||||
: handleToEvent(0), enabled(false) {}
|
|
||||||
QWinEventNotifierPrivate(HANDLE h, bool e)
|
|
||||||
: handleToEvent(h), enabled(e) {}
|
|
||||||
|
|
||||||
HANDLE handleToEvent;
|
|
||||||
bool enabled;
|
|
||||||
};
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\class QWinEventNotifier
|
\class QWinEventNotifier
|
||||||
\inmodule QtCore
|
\inmodule QtCore
|
||||||
@ -246,4 +233,49 @@ bool QWinEventNotifier::event(QEvent * e)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(Q_OS_WINRT)
|
||||||
|
|
||||||
|
bool QWinEventNotifierPrivate::registerWaitObject()
|
||||||
|
{
|
||||||
|
Q_UNIMPLEMENTED();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QWinEventNotifierPrivate::unregisterWaitObject()
|
||||||
|
{
|
||||||
|
Q_UNIMPLEMENTED();
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // defined(Q_OS_WINRT)
|
||||||
|
|
||||||
|
static void CALLBACK wfsoCallback(void *context, BOOLEAN /*ignore*/)
|
||||||
|
{
|
||||||
|
QWinEventNotifierPrivate *nd = reinterpret_cast<QWinEventNotifierPrivate *>(context);
|
||||||
|
QAbstractEventDispatcher *eventDispatcher = nd->threadData->eventDispatcher.load();
|
||||||
|
QEventDispatcherWin32Private *edp = QEventDispatcherWin32Private::get(
|
||||||
|
static_cast<QEventDispatcherWin32 *>(eventDispatcher));
|
||||||
|
SetEvent(edp->winEventNotifierActivatedEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool QWinEventNotifierPrivate::registerWaitObject()
|
||||||
|
{
|
||||||
|
if (RegisterWaitForSingleObject(&waitHandle, handleToEvent, wfsoCallback, this,
|
||||||
|
INFINITE, WT_EXECUTEONLYONCE) == 0) {
|
||||||
|
qErrnoWarning("QWinEventNotifier: RegisterWaitForSingleObject failed.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QWinEventNotifierPrivate::unregisterWaitObject()
|
||||||
|
{
|
||||||
|
// Unregister the wait handle and wait for pending callbacks to finish.
|
||||||
|
if (UnregisterWaitEx(waitHandle, INVALID_HANDLE_VALUE))
|
||||||
|
waitHandle = NULL;
|
||||||
|
else
|
||||||
|
qErrnoWarning("QWinEventNotifier: UnregisterWaitEx failed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // !defined(Q_OS_WINRT)
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
81
src/corelib/kernel/qwineventnotifier_p.h
Normal file
81
src/corelib/kernel/qwineventnotifier_p.h
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2017 The Qt Company Ltd.
|
||||||
|
** Contact: https://www.qt.io/licensing/
|
||||||
|
**
|
||||||
|
** This file is part of the QtCore module of the Qt Toolkit.
|
||||||
|
**
|
||||||
|
** $QT_BEGIN_LICENSE:LGPL$
|
||||||
|
** Commercial License Usage
|
||||||
|
** Licensees holding valid commercial Qt licenses may use this file in
|
||||||
|
** accordance with the commercial license agreement provided with the
|
||||||
|
** Software or, alternatively, in accordance with the terms contained in
|
||||||
|
** a written agreement between you and The Qt Company. For licensing terms
|
||||||
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
||||||
|
** information use the contact form at https://www.qt.io/contact-us.
|
||||||
|
**
|
||||||
|
** GNU Lesser General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
||||||
|
** General Public License version 3 as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.LGPL3 included in the
|
||||||
|
** packaging of this file. Please review the following information to
|
||||||
|
** ensure the GNU Lesser General Public License version 3 requirements
|
||||||
|
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
|
||||||
|
**
|
||||||
|
** GNU General Public License Usage
|
||||||
|
** Alternatively, this file may be used under the terms of the GNU
|
||||||
|
** General Public License version 2.0 or (at your option) the GNU General
|
||||||
|
** Public license version 3 or any later version approved by the KDE Free
|
||||||
|
** Qt Foundation. The licenses are as published by the Free Software
|
||||||
|
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
|
||||||
|
** included in the packaging of this file. Please review the following
|
||||||
|
** information to ensure the GNU General Public License requirements will
|
||||||
|
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
|
||||||
|
** https://www.gnu.org/licenses/gpl-3.0.html.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef QWINEVENTNOTIFIER_P_H
|
||||||
|
#define QWINEVENTNOTIFIER_P_H
|
||||||
|
|
||||||
|
//
|
||||||
|
// W A R N I N G
|
||||||
|
// -------------
|
||||||
|
//
|
||||||
|
// This file is not part of the Qt API. It exists purely as an
|
||||||
|
// implementation detail. This header file may change from version to
|
||||||
|
// version without notice, or even be removed.
|
||||||
|
//
|
||||||
|
// We mean it.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "qwineventnotifier.h"
|
||||||
|
|
||||||
|
#include <private/qobject_p.h>
|
||||||
|
#include <QtCore/qt_windows.h>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class QWinEventNotifierPrivate : public QObjectPrivate
|
||||||
|
{
|
||||||
|
Q_DECLARE_PUBLIC(QWinEventNotifier)
|
||||||
|
public:
|
||||||
|
QWinEventNotifierPrivate()
|
||||||
|
: handleToEvent(0), enabled(false) {}
|
||||||
|
QWinEventNotifierPrivate(HANDLE h, bool e)
|
||||||
|
: handleToEvent(h), enabled(e) {}
|
||||||
|
|
||||||
|
static QWinEventNotifierPrivate *get(QWinEventNotifier *q) { return q->d_func(); }
|
||||||
|
bool registerWaitObject();
|
||||||
|
void unregisterWaitObject();
|
||||||
|
|
||||||
|
HANDLE handleToEvent;
|
||||||
|
HANDLE waitHandle = NULL;
|
||||||
|
bool enabled;
|
||||||
|
};
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // QWINEVENTNOTIFIER_P_H
|
@ -31,6 +31,8 @@
|
|||||||
#include <qtimer.h>
|
#include <qtimer.h>
|
||||||
#include <qt_windows.h>
|
#include <qt_windows.h>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
class tst_QWinEventNotifier : public QObject
|
class tst_QWinEventNotifier : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -40,6 +42,7 @@ protected slots:
|
|||||||
void simple_timerSet();
|
void simple_timerSet();
|
||||||
private slots:
|
private slots:
|
||||||
void simple();
|
void simple();
|
||||||
|
void manyNotifiers();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
HANDLE simpleHEvent;
|
HANDLE simpleHEvent;
|
||||||
@ -87,6 +90,91 @@ void tst_QWinEventNotifier::simple()
|
|||||||
QVERIFY(simpleActivated);
|
QVERIFY(simpleActivated);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class EventWithNotifier : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
EventWithNotifier()
|
||||||
|
{
|
||||||
|
connect(¬ifier, &QWinEventNotifier::activated,
|
||||||
|
this, &EventWithNotifier::onNotifierActivated);
|
||||||
|
notifier.setHandle(CreateEvent(0, TRUE, FALSE, 0));
|
||||||
|
notifier.setEnabled(true);
|
||||||
|
|
||||||
|
static int nextIndex = 0;
|
||||||
|
idx = nextIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
~EventWithNotifier()
|
||||||
|
{
|
||||||
|
notifier.setEnabled(false);
|
||||||
|
CloseHandle(notifier.handle());
|
||||||
|
}
|
||||||
|
|
||||||
|
HANDLE eventHandle() const { return notifier.handle(); }
|
||||||
|
int numberOfTimesActivated() const { return activatedCount; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void activated();
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void onNotifierActivated()
|
||||||
|
{
|
||||||
|
ResetEvent(notifier.handle());
|
||||||
|
activatedCount++;
|
||||||
|
emit activated();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
QWinEventNotifier notifier;
|
||||||
|
int activatedCount = 0;
|
||||||
|
int idx = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
void tst_QWinEventNotifier::manyNotifiers()
|
||||||
|
{
|
||||||
|
const size_t maxEvents = 100;
|
||||||
|
const size_t middleEvenEvent = maxEvents / 2;
|
||||||
|
Q_ASSERT(middleEvenEvent % 2 == 0);
|
||||||
|
using EventWithNotifierPtr = std::unique_ptr<EventWithNotifier>;
|
||||||
|
std::vector<EventWithNotifierPtr> events(maxEvents);
|
||||||
|
std::generate(events.begin(), events.end(), [] () {
|
||||||
|
return EventWithNotifierPtr(new EventWithNotifier);
|
||||||
|
});
|
||||||
|
|
||||||
|
QTestEventLoop loop;
|
||||||
|
auto connection = connect(events.at(8).get(), &EventWithNotifier::activated, &loop, &QTestEventLoop::exitLoop);
|
||||||
|
for (const auto &ewn : events) {
|
||||||
|
connect(ewn.get(), &EventWithNotifier::activated, [&events, &loop] () {
|
||||||
|
if (std::all_of(events.cbegin(), events.cend(),
|
||||||
|
[] (const EventWithNotifierPtr &ewn) {
|
||||||
|
return ewn->numberOfTimesActivated() > 0; })) {
|
||||||
|
loop.exitLoop();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Activate all even events before running the event loop.
|
||||||
|
for (size_t i = 0; i < events.size(); i += 2)
|
||||||
|
SetEvent(events.at(i)->eventHandle());
|
||||||
|
|
||||||
|
// Wait until event notifier with index 8 has been activated.
|
||||||
|
loop.enterLoop(30);
|
||||||
|
QObject::disconnect(connection);
|
||||||
|
|
||||||
|
// Activate all odd events after the event loop has run for a bit.
|
||||||
|
for (size_t i = 1; i < events.size(); i += 2)
|
||||||
|
SetEvent(events.at(i)->eventHandle());
|
||||||
|
|
||||||
|
// Wait until all event notifiers have fired.
|
||||||
|
loop.enterLoop(30);
|
||||||
|
|
||||||
|
// All notifiers must have been activated exactly once.
|
||||||
|
QVERIFY(std::all_of(events.cbegin(), events.cend(), [] (const EventWithNotifierPtr &ewn) {
|
||||||
|
return ewn->numberOfTimesActivated() == 1;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
QTEST_MAIN(tst_QWinEventNotifier)
|
QTEST_MAIN(tst_QWinEventNotifier)
|
||||||
|
|
||||||
#include "tst_qwineventnotifier.moc"
|
#include "tst_qwineventnotifier.moc"
|
||||||
|
Loading…
Reference in New Issue
Block a user