Windows: improve QTimer::remainingTime when called before processEvents

This checks that intenalHwnd in QEventDispatcherWin32::remainingTime is
initialized. If calling remaningTime, before createInternalHwnd
is called, the timeout member in the WinTimerInfo struct is not
initialized and contains a random value. This adds a check for that and
in that case returns the requested timer interval as the timer has not
yet been started. createInternalHwnd is called on the first request to
process events.

It also adds a test for checking the remaining time. But the issue can
only be seen if solely running the remainingTimeInitial test in
tst_QTimer. If running the test along side another test the other
test likely calls processEvents indirectly, which hides the issue. I
don't know if this is an issue in practice (the bug has been there
for as long a the git history goes back, 2011), but it causes the
basic_chrono test to fail if run as the only test.

Change-Id: I05c35105da778912dedf8d749aa7c953841d986e
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Christian Andersen 2019-01-27 17:41:15 +01:00
parent 8b91afe12e
commit 6a7e2fedef
2 changed files with 37 additions and 2 deletions

View File

@ -992,8 +992,14 @@ int QEventDispatcherWin32::remainingTime(int timerId)
quint64 currentTime = qt_msectime();
for (const WinTimerInfo *t : qAsConst(d->timerVec)) {
if (t && t->timerId == timerId) // timer found, return time to wait
return t->timeout > currentTime ? t->timeout - currentTime : 0;
if (t && t->timerId == timerId) {
// timer found, return time to wait
if (d->internalHwnd)
return t->timeout > currentTime ? t->timeout - currentTime : 0;
else
return t->interval;
}
}
#ifndef QT_NO_DEBUG

View File

@ -51,6 +51,8 @@ private slots:
void singleShotTimeout();
void timeout();
void remainingTime();
void remainingTimeInitial_data();
void remainingTimeInitial();
void remainingTimeDuringActivation_data();
void remainingTimeDuringActivation();
void basic_chrono();
@ -143,6 +145,33 @@ void tst_QTimer::remainingTime()
QVERIFY2(remainingTime >= 50, qPrintable(QString::number(remainingTime)));
}
void tst_QTimer::remainingTimeInitial_data()
{
QTest::addColumn<int>("startTimeMs");
QTest::addColumn<Qt::TimerType>("timerType");
QTest::addRow("precise time 0ms") << 0 << Qt::PreciseTimer;
QTest::addRow("precise time 1ms") << 1 << Qt::PreciseTimer;
QTest::addRow("precise time 10ms") << 10 << Qt::PreciseTimer;
QTest::addRow("coarse time 0ms") << 0 << Qt::CoarseTimer;
QTest::addRow("coarse time 1ms") << 1 << Qt::CoarseTimer;
QTest::addRow("coarse time 10ms") << 10 << Qt::CoarseTimer;
}
void tst_QTimer::remainingTimeInitial()
{
QFETCH(int, startTimeMs);
QFETCH(Qt::TimerType, timerType);
QTimer timer;
timer.setTimerType(timerType);
timer.start(startTimeMs);
const int rt = timer.remainingTime();
QVERIFY2(rt >= 0 && rt <= startTimeMs, qPrintable(QString::number(rt)));
}
void tst_QTimer::remainingTimeDuringActivation_data()
{
QTest::addColumn<bool>("singleShot");