diff --git a/src/corelib/kernel/qbasictimer.cpp b/src/corelib/kernel/qbasictimer.cpp index e7626f7426..17711a355e 100644 --- a/src/corelib/kernel/qbasictimer.cpp +++ b/src/corelib/kernel/qbasictimer.cpp @@ -165,7 +165,7 @@ void QBasicTimer::start(std::chrono::milliseconds duration, Qt::TimerType timerT } stop(); if (obj) - id = eventDispatcher->registerTimer(duration.count(), timerType, obj); + id = int(eventDispatcher->registerTimer(duration, timerType, obj)); } /*! @@ -177,7 +177,7 @@ void QBasicTimer::stop() { if (id) { QAbstractEventDispatcher *eventDispatcher = QAbstractEventDispatcher::instance(); - if (eventDispatcher && !eventDispatcher->unregisterTimer(id)) { + if (eventDispatcher && !eventDispatcher->unregisterTimer(Qt::TimerId(id))) { qWarning("QBasicTimer::stop: Failed. Possibly trying to stop from a different thread"); return; } diff --git a/src/corelib/kernel/qchronotimer.cpp b/src/corelib/kernel/qchronotimer.cpp index 4da7538278..a517c4446b 100644 --- a/src/corelib/kernel/qchronotimer.cpp +++ b/src/corelib/kernel/qchronotimer.cpp @@ -330,7 +330,7 @@ QBindable QChronoTimer::bindableInterval() std::chrono::nanoseconds QChronoTimer::remainingTime() const { if (isActive()) - return 1ms * QAbstractEventDispatcher::instance()->remainingTime(qToUnderlying(d_func()->id)); + return QAbstractEventDispatcher::instance()->remainingTime(d_func()->id); return std::chrono::nanoseconds::min(); } diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 162420532f..dba3529b94 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -1453,7 +1453,7 @@ bool QObject::event(QEvent *e) QThreadData *threadData = d->threadData.loadRelaxed(); QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed(); if (eventDispatcher) { - QList timers = eventDispatcher->registeredTimers(this); + QList timers = eventDispatcher->timersForObject(this); if (!timers.isEmpty()) { const bool res = eventDispatcher->unregisterTimers(this); // do not to release our timer ids back to the pool (since the timer ids are moving to a new thread). @@ -1920,11 +1920,10 @@ int QObject::startTimer(std::chrono::nanoseconds interval, Qt::TimerType timerTy } auto dispatcher = thisThreadData->eventDispatcher.loadRelaxed(); - const auto msecs = std::chrono::ceil(interval); - int timerId = dispatcher->registerTimer(msecs.count(), timerType, this); + Qt::TimerId timerId = dispatcher->registerTimer(interval, timerType, this); d->ensureExtraData(); - d->extraData->runningTimers.append(Qt::TimerId{timerId}); - return timerId; + d->extraData->runningTimers.append(timerId); + return int(timerId); } /*! @@ -1966,7 +1965,7 @@ void QObject::killTimer(Qt::TimerId id) auto thisThreadData = d->threadData.loadRelaxed(); if (thisThreadData->hasEventDispatcher()) - thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(qToUnderlying(id)); + thisThreadData->eventDispatcher.loadRelaxed()->unregisterTimer(id); d->extraData->runningTimers.remove(at); QAbstractEventDispatcherPrivate::releaseTimerId(id); diff --git a/src/corelib/kernel/qtimer.cpp b/src/corelib/kernel/qtimer.cpp index 3291c7d24b..cc46c1433b 100644 --- a/src/corelib/kernel/qtimer.cpp +++ b/src/corelib/kernel/qtimer.cpp @@ -632,7 +632,9 @@ int QTimer::remainingTime() const { Q_D(const QTimer); if (d->isActive()) { - return QAbstractEventDispatcher::instance()->remainingTime(qToUnderlying(d->id)); + using namespace std::chrono; + auto remaining = QAbstractEventDispatcher::instance()->remainingTime(d->id); + return ceil(remaining).count(); } return -1; diff --git a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp index eafcaf3b79..285d080960 100644 --- a/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp +++ b/tests/auto/corelib/kernel/qeventdispatcher/tst_qeventdispatcher.cpp @@ -22,11 +22,28 @@ static bool glibDisabled = []() { using namespace std::chrono_literals; -enum { - PreciseTimerInterval = 10, - CoarseTimerInterval = 200, - VeryCoarseTimerInterval = 1000 -}; +static constexpr auto PreciseTimerInterval = 10ms; +static constexpr auto CoarseTimerInterval = 200ms; +static constexpr auto VeryCoarseTimerInterval = 1s; + +static constexpr +std::chrono::nanoseconds fudgeInterval(std::chrono::nanoseconds interval, Qt::TimerType timerType) +{ + // Make the intervals have have fractions of milliseconds so we can check + // that they have been rounded & stored properly (where applicable). + switch (timerType) { + case Qt::VeryCoarseTimer: + // rounds down (floor) to seconds + return interval + 1010us; + case Qt::CoarseTimer: + // rounds up (ceil) to milliseconds + return interval - 10us; + case Qt::PreciseTimer: + // not rounded using QAbstractEventDispatcherV2; rounded up (ceil) on V1 + return interval - 10us; + } + Q_UNREACHABLE_RETURN(std::chrono::nanoseconds::min()); +} class tst_QEventDispatcher : public QObject { @@ -91,7 +108,7 @@ bool tst_QEventDispatcher::event(QEvent *e) // drain the system event queue after the test starts to avoid destabilizing the test functions void tst_QEventDispatcher::initTestCase() { - QDeadlineTimer deadline(CoarseTimerInterval * 1ms); + QDeadlineTimer deadline(CoarseTimerInterval); while (!deadline.hasExpired() && eventDispatcher->processEvents(QEventLoop::AllEvents)) ; } @@ -120,35 +137,36 @@ public: TimerManager(TimerManager &&) = delete; TimerManager &operator=(TimerManager &&) = delete; - int preciseTimerId() const { return m_preciseTimerId; } - int coarseTimerId() const { return m_coarseTimerId; } - int veryCoarseTimerId() const { return m_veryCoarseTimerId; } + int preciseTimerId() const { return int(m_preciseTimerId); } + int coarseTimerId() const { return int(m_coarseTimerId); } + int veryCoarseTimerId() const { return int(m_veryCoarseTimerId); } - bool foundPrecise() const { return m_preciseTimerId > 0; } - bool foundCoarse() const { return m_coarseTimerId > 0; } - bool foundVeryCoarse() const { return m_veryCoarseTimerId > 0; } + bool foundPrecise() const { return preciseTimerId() > 0; } + bool foundCoarse() const { return coarseTimerId() > 0; } + bool foundVeryCoarse() const { return veryCoarseTimerId() > 0; } - QList registeredTimers() const + QList registeredTimers() const { - return m_eventDispatcher->registeredTimers(m_parent); + return m_eventDispatcher->timersForObject(m_parent); } void registerAll() { // start 3 timers, each with the different timer types and different intervals - m_preciseTimerId = m_eventDispatcher->registerTimer( - PreciseTimerInterval, Qt::PreciseTimer, m_parent); - m_coarseTimerId = m_eventDispatcher->registerTimer( - CoarseTimerInterval, Qt::CoarseTimer, m_parent); - m_veryCoarseTimerId = m_eventDispatcher->registerTimer( - VeryCoarseTimerInterval, Qt::VeryCoarseTimer, m_parent); - QVERIFY(m_preciseTimerId > 0); - QVERIFY(m_coarseTimerId > 0); - QVERIFY(m_veryCoarseTimerId > 0); + auto registerTimer = [&](std::chrono::milliseconds interval, Qt::TimerType timerType) { + return m_eventDispatcher->registerTimer(fudgeInterval(interval, timerType), timerType, + m_parent); + }; + m_preciseTimerId = registerTimer(PreciseTimerInterval, Qt::PreciseTimer); + m_coarseTimerId = registerTimer(CoarseTimerInterval, Qt::CoarseTimer); + m_veryCoarseTimerId = registerTimer(VeryCoarseTimerInterval, Qt::VeryCoarseTimer); + QVERIFY(foundPrecise()); + QVERIFY(foundCoarse()); + QVERIFY(foundVeryCoarse()); findTimers(); } - void unregister(int timerId) + void unregister(Qt::TimerId timerId) { m_eventDispatcher->unregisterTimer(timerId); findTimers(); @@ -166,36 +184,43 @@ private: bool foundPrecise = false; bool foundCoarse = false; bool foundVeryCoarse = false; - const QList timers = registeredTimers(); - for (int i = 0; i < timers.size(); ++i) { - const QAbstractEventDispatcher::TimerInfo &timerInfo = timers.at(i); + const QList timers = registeredTimers(); + for (const QAbstractEventDispatcher::TimerInfoV2 &timerInfo : timers) { if (timerInfo.timerId == m_preciseTimerId) { - QCOMPARE(timerInfo.interval, int(PreciseTimerInterval)); + // For precise timers, we expect the fudge factor to be present + QAbstractEventDispatcher::Duration interval = + fudgeInterval(PreciseTimerInterval, Qt::PreciseTimer); +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) + if (!qobject_cast(m_eventDispatcher)) + interval = PreciseTimerInterval; +#endif + QCOMPARE(timerInfo.interval, interval); QCOMPARE(timerInfo.timerType, Qt::PreciseTimer); foundPrecise = true; } else if (timerInfo.timerId == m_coarseTimerId) { - QCOMPARE(timerInfo.interval, int(CoarseTimerInterval)); + // For other timers, the fudge factors ought to have been rounded away + QCOMPARE(timerInfo.interval, CoarseTimerInterval); QCOMPARE(timerInfo.timerType, Qt::CoarseTimer); foundCoarse = true; } else if (timerInfo.timerId == m_veryCoarseTimerId) { - QCOMPARE(timerInfo.interval, int(VeryCoarseTimerInterval)); + QCOMPARE(timerInfo.interval, VeryCoarseTimerInterval); QCOMPARE(timerInfo.timerType, Qt::VeryCoarseTimer); foundVeryCoarse = true; } } if (!foundPrecise) - m_preciseTimerId = -1; + m_preciseTimerId = Qt::TimerId::Invalid; if (!foundCoarse) - m_coarseTimerId = -1; + m_coarseTimerId = Qt::TimerId::Invalid; if (!foundVeryCoarse) - m_veryCoarseTimerId = -1; + m_veryCoarseTimerId = Qt::TimerId::Invalid; } QAbstractEventDispatcher *m_eventDispatcher = nullptr; - int m_preciseTimerId = -1; - int m_coarseTimerId = -1; - int m_veryCoarseTimerId = -1; + Qt::TimerId m_preciseTimerId = Qt::TimerId::Invalid; + Qt::TimerId m_coarseTimerId = Qt::TimerId::Invalid; + Qt::TimerId m_veryCoarseTimerId = Qt::TimerId::Invalid; QObject *m_parent = nullptr; }; @@ -235,13 +260,13 @@ void tst_QEventDispatcher::registerTimer() if (doubleTimer) QSKIP("Double timer during a single timeout - aborting test as flaky on macOS"); if (timerIdFromEvent != timers.preciseTimerId() - && elapsedTimer.elapsed() > PreciseTimerInterval * 3) + && elapsedTimer.durationElapsed() > PreciseTimerInterval * 3) QSKIP("Ignore flaky test behavior due to VM scheduling on macOS"); #endif QCOMPARE(timerIdFromEvent, timers.preciseTimerId()); // now unregister it and make sure it's gone - timers.unregister(timers.preciseTimerId()); + timers.unregister(Qt::TimerId(timers.preciseTimerId())); if (QTest::currentTestFailed()) return; QCOMPARE(timers.registeredTimers().size(), 2); @@ -259,13 +284,13 @@ void tst_QEventDispatcher::registerTimer() if (doubleTimer) QSKIP("Double timer during a single timeout - aborting test as flaky on macOS"); if (timerIdFromEvent != timers.coarseTimerId() - && elapsedTimer.elapsed() > CoarseTimerInterval * 3) + && elapsedTimer.durationElapsed() > CoarseTimerInterval * 3) QSKIP("Ignore flaky test behavior due to VM scheduling on macOS"); #endif QCOMPARE(timerIdFromEvent, timers.coarseTimerId()); // now unregister it and make sure it's gone - timers.unregister(timers.coarseTimerId()); + timers.unregister(Qt::TimerId(timers.coarseTimerId())); if (QTest::currentTestFailed()) return; QCOMPARE(timers.registeredTimers().size(), 1);