diff --git a/src/corelib/kernel/kernel.pri b/src/corelib/kernel/kernel.pri index 8abe9b2b44..29bd5bbc6c 100644 --- a/src/corelib/kernel/kernel.pri +++ b/src/corelib/kernel/kernel.pri @@ -79,8 +79,7 @@ win32 { kernel/qsharedmemory_win.cpp \ kernel/qsystemsemaphore_win.cpp HEADERS += \ - kernel/qwineventnotifier.h \ - kernel/qwineventnotifier_p.h + kernel/qwineventnotifier.h winrt { SOURCES += kernel/qeventdispatcher_winrt.cpp diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index fc34dd0a6b..0952464f53 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -53,7 +53,6 @@ #include "qcoreapplication_p.h" #include #include -#include QT_BEGIN_NAMESPACE @@ -97,14 +96,13 @@ 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), winEventNotifierActivatedEvent(NULL) + wakeUps(0) + , activateNotifiersPosted(false) { } QEventDispatcherWin32Private::~QEventDispatcherWin32Private() { - if (winEventNotifierActivatedEvent) - CloseHandle(winEventNotifierActivatedEvent); if (internalHwnd) DestroyWindow(internalHwnd); } @@ -539,14 +537,12 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) bool needWM_QT_SENDPOSTEDEVENTS = false; do { DWORD waitRet = 0; - DWORD nCount = 0; - HANDLE *pHandles = nullptr; - if (d->winEventNotifierActivatedEvent) { - nCount = 1; - pHandles = &d->winEventNotifierActivatedEvent; - } + HANDLE pHandles[MAXIMUM_WAIT_OBJECTS - 1]; QVarLengthArray processedTimers; while (!d->interrupt) { + DWORD nCount = d->winEventNotifierList.count(); + Q_ASSERT(nCount < MAXIMUM_WAIT_OBJECTS - 1); + MSG msg; bool haveMessage; @@ -588,6 +584,8 @@ 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 @@ -628,7 +626,7 @@ bool QEventDispatcherWin32::processEvents(QEventLoop::ProcessEventsFlags flags) DispatchMessage(&msg); } } else if (waitRet - WAIT_OBJECT_0 < nCount) { - activateEventNotifiers(); + d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); } else { // nothing todo so break break; @@ -641,11 +639,16 @@ 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) { - activateEventNotifiers(); + d->activateEventNotifier(d->winEventNotifierList.at(waitRet - WAIT_OBJECT_0)); retVal = true; } } @@ -903,12 +906,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); - - if (!d->winEventNotifierActivatedEvent) - d->winEventNotifierActivatedEvent = CreateEvent(0, TRUE, FALSE, nullptr); - - return QWinEventNotifierPrivate::get(notifier)->registerWaitObject(); + return true; } void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier) @@ -924,35 +927,17 @@ void QEventDispatcherWin32::unregisterEventNotifier(QWinEventNotifier *notifier) Q_D(QEventDispatcherWin32); int i = d->winEventNotifierList.indexOf(notifier); - if (i == -1) - return; - d->winEventNotifierList.takeAt(i); - QWinEventNotifierPrivate *nd = QWinEventNotifierPrivate::get(notifier); - if (nd->waitHandle) - nd->unregisterWaitObject(); + if (i != -1) + d->winEventNotifierList.takeAt(i); } void QEventDispatcherWin32::activateEventNotifiers() { Q_D(QEventDispatcherWin32); - 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; + //### this could break if events are removed/added in the activation + for (int i=0; iwinEventNotifierList.count(); i++) { + if (WaitForSingleObjectEx(d->winEventNotifierList.at(i)->handle(), 0, TRUE) == WAIT_OBJECT_0) + d->activateEventNotifier(d->winEventNotifierList.at(i)); } } diff --git a/src/corelib/kernel/qeventdispatcher_win_p.h b/src/corelib/kernel/qeventdispatcher_win_p.h index 683c7f8f36..f6d1bffdf5 100644 --- a/src/corelib/kernel/qeventdispatcher_win_p.h +++ b/src/corelib/kernel/qeventdispatcher_win_p.h @@ -161,7 +161,6 @@ class Q_CORE_EXPORT QEventDispatcherWin32Private : public QAbstractEventDispatch public: QEventDispatcherWin32Private(); ~QEventDispatcherWin32Private(); - static QEventDispatcherWin32Private *get(QEventDispatcherWin32 *q) { return q->d_func(); } DWORD threadId; @@ -193,7 +192,6 @@ public: void postActivateSocketNotifiers(); void doWsaAsyncSelect(int socket, long event); - HANDLE winEventNotifierActivatedEvent; QList winEventNotifierList; void activateEventNotifier(QWinEventNotifier * wen); diff --git a/src/corelib/kernel/qwineventnotifier.cpp b/src/corelib/kernel/qwineventnotifier.cpp index 6bfa6ca729..0808374a6a 100644 --- a/src/corelib/kernel/qwineventnotifier.cpp +++ b/src/corelib/kernel/qwineventnotifier.cpp @@ -37,7 +37,7 @@ ** ****************************************************************************/ -#include "qwineventnotifier_p.h" +#include "qwineventnotifier.h" #ifdef Q_OS_WINRT #include "qeventdispatcher_winrt_p.h" @@ -50,6 +50,19 @@ 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 \inmodule QtCore @@ -233,49 +246,4 @@ bool QWinEventNotifier::event(QEvent * e) 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(context); - QAbstractEventDispatcher *eventDispatcher = nd->threadData->eventDispatcher.load(); - QEventDispatcherWin32Private *edp = QEventDispatcherWin32Private::get( - static_cast(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 diff --git a/src/corelib/kernel/qwineventnotifier_p.h b/src/corelib/kernel/qwineventnotifier_p.h deleted file mode 100644 index bddeaaf134..0000000000 --- a/src/corelib/kernel/qwineventnotifier_p.h +++ /dev/null @@ -1,81 +0,0 @@ -/**************************************************************************** -** -** 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 -#include - -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 diff --git a/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp b/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp index 304f6121a5..3221587300 100644 --- a/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp +++ b/tests/auto/corelib/kernel/qwineventnotifier/tst_qwineventnotifier.cpp @@ -31,8 +31,6 @@ #include #include -#include - class tst_QWinEventNotifier : public QObject { Q_OBJECT @@ -42,7 +40,6 @@ protected slots: void simple_timerSet(); private slots: void simple(); - void manyNotifiers(); private: HANDLE simpleHEvent; @@ -90,91 +87,6 @@ void tst_QWinEventNotifier::simple() 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; - std::vector 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) #include "tst_qwineventnotifier.moc"