QAbstractEventDispatcher: port timer uses to the V2 API

Change-Id: I83dda2d36c904517b3c0fffd17b52b71739928dc
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
Reviewed-by: Ahmad Samir <a.samirh78@gmail.com>
bb10
Thiago Macieira 2024-02-18 21:09:59 -08:00
parent afa86c60e6
commit 1ca89b65d8
5 changed files with 76 additions and 50 deletions

View File

@ -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;
}

View File

@ -330,7 +330,7 @@ QBindable<std::chrono::nanoseconds> 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();
}

View File

@ -1453,7 +1453,7 @@ bool QObject::event(QEvent *e)
QThreadData *threadData = d->threadData.loadRelaxed();
QAbstractEventDispatcher *eventDispatcher = threadData->eventDispatcher.loadRelaxed();
if (eventDispatcher) {
QList<QAbstractEventDispatcher::TimerInfo> timers = eventDispatcher->registeredTimers(this);
QList<QAbstractEventDispatcher::TimerInfoV2> 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<std::chrono::milliseconds>(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);

View File

@ -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<milliseconds>(remaining).count();
}
return -1;

View File

@ -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<QAbstractEventDispatcher::TimerInfo> registeredTimers() const
QList<QAbstractEventDispatcher::TimerInfoV2> 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<QAbstractEventDispatcher::TimerInfo> timers = registeredTimers();
for (int i = 0; i < timers.size(); ++i) {
const QAbstractEventDispatcher::TimerInfo &timerInfo = timers.at(i);
const QList<QAbstractEventDispatcher::TimerInfoV2> 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<QAbstractEventDispatcherV2 *>(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);