diff options
-rw-r--r-- | dist/changes-4.5.1 | 4 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_win.cpp | 15 | ||||
-rw-r--r-- | tests/auto/qtimer/tst_qtimer.cpp | 65 |
3 files changed, 81 insertions, 3 deletions
diff --git a/dist/changes-4.5.1 b/dist/changes-4.5.1 index de4eef7..eb8ec5f 100644 --- a/dist/changes-4.5.1 +++ b/dist/changes-4.5.1 @@ -68,6 +68,10 @@ Qt for Linux/X11 Qt for Windows -------------- +- QCoreApplication + * [247401] Fixed a bug that would cause a restarted timer to fire + too early, causing Javascript in QtWebKit to consume 100% CPU on + Windows. Qt for Mac OS X --------------- diff --git a/src/corelib/kernel/qeventdispatcher_win.cpp b/src/corelib/kernel/qeventdispatcher_win.cpp index 880e95c..c4061f4 100644 --- a/src/corelib/kernel/qeventdispatcher_win.cpp +++ b/src/corelib/kernel/qeventdispatcher_win.cpp @@ -1059,11 +1059,20 @@ bool QEventDispatcherWin32::event(QEvent *e) QZeroTimerEvent *zte = static_cast<QZeroTimerEvent*>(e); WinTimerInfo *t = d->timerDict.value(zte->timerId()); if (t) { + t->inTimerEvent = true; + QTimerEvent te(zte->timerId()); QCoreApplication::sendEvent(t->obj, &te); - WinTimerInfo *tn = d->timerDict.value(zte->timerId()); - if (tn && t == tn) - QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId())); + + t = d->timerDict.value(zte->timerId()); + if (t) { + if (t->interval == 0 && t->inTimerEvent) { + // post the next zero timer event as long as the timer was not restarted + QCoreApplication::postEvent(this, new QZeroTimerEvent(zte->timerId())); + } + + t->inTimerEvent = false; + } } return true; } else if (e->type() == QEvent::Timer) { diff --git a/tests/auto/qtimer/tst_qtimer.cpp b/tests/auto/qtimer/tst_qtimer.cpp index 527628c..bffb4f2 100644 --- a/tests/auto/qtimer/tst_qtimer.cpp +++ b/tests/auto/qtimer/tst_qtimer.cpp @@ -83,6 +83,7 @@ private slots: void recurringTimer(); void deleteLaterOnQTimer(); // long name, don't want to shadow QObject::deleteLater() void moveToThread(); + void restartedTimerFiresTooSoon(); }; class TimerHelper : public QObject @@ -416,5 +417,69 @@ void tst_QTimer::moveToThread() QVERIFY((ti3.timerId() & 0xffffff) != (ti1.timerId() & 0xffffff)); } +class RestartedTimerFiresTooSoonObject : public QObject +{ + Q_OBJECT + +public: + QBasicTimer m_timer; + + int m_interval; + QTime m_startedTime; + QEventLoop eventLoop; + + inline RestartedTimerFiresTooSoonObject() + : QObject(), m_interval(0) + { } + + void timerFired() + { + static int interval = 1000; + + m_interval = interval; + m_startedTime.start(); + m_timer.start(interval, this); + + // alternate between single-shot and 1 sec + interval = interval ? 0 : 1000; + } + + void timerEvent(QTimerEvent* ev) + { + if (ev->timerId() != m_timer.timerId()) + return; + + m_timer.stop(); + + QTime now = QTime::currentTime(); + int elapsed = m_startedTime.elapsed(); + + if (elapsed < m_interval / 2) { + // severely too early! + m_timer.stop(); + eventLoop.exit(-1); + return; + } + + timerFired(); + + // don't do this forever + static int count = 0; + if (count++ > 20) { + m_timer.stop(); + eventLoop.quit(); + return; + } + } +}; + +void tst_QTimer::restartedTimerFiresTooSoon() +{ + RestartedTimerFiresTooSoonObject object; + object.timerFired(); + QVERIFY(object.eventLoop.exec() == 0); +} + QTEST_MAIN(tst_QTimer) #include "tst_qtimer.moc" +\ |