diff options
author | Bradley T. Hughes <bradley.hughes@nokia.com> | 2009-09-23 11:51:17 (GMT) |
---|---|---|
committer | Bradley T. Hughes <bradley.hughes@nokia.com> | 2009-10-05 11:03:49 (GMT) |
commit | 0ed23e95fa756fd851f509a565f91ab43fc30449 (patch) | |
tree | 9c4f8dd088587ed2aab8708ac52b37f3ba89cab4 | |
parent | 0573653f830fada99311c88ab46e8f5a37854b90 (diff) | |
download | Qt-0ed23e95fa756fd851f509a565f91ab43fc30449.zip Qt-0ed23e95fa756fd851f509a565f91ab43fc30449.tar.gz Qt-0ed23e95fa756fd851f509a565f91ab43fc30449.tar.bz2 |
Fix regressions in qeventloop, qtimer, and qsocketnotifier autotests
Commit ed375675d4a4f6fd63edeb242e23c87b3de4be6f triggers a behavior in
Glib's mainloop implementation where some event sources are not
"serviced" every iteration of the mainloop context. This breaks an
invariant that many tests relied on, so we need to solve the problem.
The invariant is that a newly added timer that would normally fire on
the next pass of the event loop (liker a zero timer) SHOULD actually
fire. We do this by registering 2 timer event sources with Glib's
mainloop: one normal priority source and one idle priority source. The
idle priority source is the one that will send events most of the
time, with the normal priority one taking over only when
processEvents() is called manually.
Task-number: QT-877
Reviewed-by: jbache
Reviewed-by: thiago
Reviewed-by: denis
(cherry picked from commit d0d0fdb8e46351b4ab8492de31e5363ef6662b57)
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_glib.cpp | 133 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_glib_p.h | 2 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_unix.cpp | 8 |
3 files changed, 112 insertions, 31 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp index 6e457f4..665b73e 100644 --- a/src/corelib/kernel/qeventdispatcher_glib.cpp +++ b/src/corelib/kernel/qeventdispatcher_glib.cpp @@ -127,16 +127,11 @@ struct GTimerSource GSource source; QTimerInfoList timerList; QEventLoop::ProcessEventsFlags processEventsFlags; + bool runWithIdlePriority; }; -static gboolean timerSourcePrepare(GSource *source, gint *timeout) +static gboolean timerSourcePrepareHelper(GTimerSource *src, gint *timeout) { - gint dummy; - if (!timeout) - timeout = &dummy; - - GTimerSource *src = reinterpret_cast<GTimerSource *>(source); - timeval tv = { 0l, 0l }; if (!(src->processEventsFlags & QEventLoop::X11ExcludeTimers) && src->timerList.timerWait(tv)) *timeout = (tv.tv_sec * 1000) + (tv.tv_usec / 1000); @@ -146,10 +141,8 @@ static gboolean timerSourcePrepare(GSource *source, gint *timeout) return (*timeout == 0); } -static gboolean timerSourceCheck(GSource *source) +static gboolean timerSourceCheckHelper(GTimerSource *src) { - GTimerSource *src = reinterpret_cast<GTimerSource *>(source); - if (src->timerList.isEmpty() || (src->processEventsFlags & QEventLoop::X11ExcludeTimers)) return false; @@ -160,9 +153,35 @@ static gboolean timerSourceCheck(GSource *source) return true; } +static gboolean timerSourcePrepare(GSource *source, gint *timeout) +{ + gint dummy; + if (!timeout) + timeout = &dummy; + + GTimerSource *src = reinterpret_cast<GTimerSource *>(source); + if (src->runWithIdlePriority) { + if (timeout) + *timeout = -1; + return false; + } + + return timerSourcePrepareHelper(src, timeout); +} + +static gboolean timerSourceCheck(GSource *source) +{ + GTimerSource *src = reinterpret_cast<GTimerSource *>(source); + if (src->runWithIdlePriority) + return false; + return timerSourceCheckHelper(src); +} + static gboolean timerSourceDispatch(GSource *source, GSourceFunc, gpointer) { - (void) reinterpret_cast<GTimerSource *>(source)->timerList.activateTimers(); + GTimerSource *timerSource = reinterpret_cast<GTimerSource *>(source); + timerSource->runWithIdlePriority = true; + (void) timerSource->timerList.activateTimers(); return true; // ??? don't remove, right again? } @@ -175,6 +194,53 @@ static GSourceFuncs timerSourceFuncs = { NULL }; +struct GIdleTimerSource +{ + GSource source; + GTimerSource *timerSource; +}; + +static gboolean idleTimerSourcePrepare(GSource *source, gint *timeout) +{ + GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source); + GTimerSource *timerSource = idleTimerSource->timerSource; + if (!timerSource->runWithIdlePriority) { + // Yield to the normal priority timer source + if (timeout) + *timeout = -1; + return false; + } + + return timerSourcePrepareHelper(timerSource, timeout); +} + +static gboolean idleTimerSourceCheck(GSource *source) +{ + GIdleTimerSource *idleTimerSource = reinterpret_cast<GIdleTimerSource *>(source); + GTimerSource *timerSource = idleTimerSource->timerSource; + if (!timerSource->runWithIdlePriority) { + // Yield to the normal priority timer source + return false; + } + return timerSourceCheckHelper(timerSource); +} + +static gboolean idleTimerSourceDispatch(GSource *source, GSourceFunc, gpointer) +{ + GTimerSource *timerSource = reinterpret_cast<GIdleTimerSource *>(source)->timerSource; + (void) timerSourceDispatch(&timerSource->source, 0, 0); + return true; +} + +static GSourceFuncs idleTimerSourceFuncs = { + idleTimerSourcePrepare, + idleTimerSourceCheck, + idleTimerSourceDispatch, + NULL, + NULL, + NULL +}; + struct GPostEventSource { GSource source; @@ -235,14 +301,15 @@ QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(GMainContext *context) g_main_context_ref(mainContext); } else { QCoreApplication *app = QCoreApplication::instance(); - if (app && QThread::currentThread() == app->thread()) { - mainContext = g_main_context_default(); - g_main_context_ref(mainContext); - } else { - mainContext = g_main_context_new(); - } + if (app && QThread::currentThread() == app->thread()) { + mainContext = g_main_context_default(); + g_main_context_ref(mainContext); + } else { + mainContext = g_main_context_new(); + } } + // setup post event source postEventSource = reinterpret_cast<GPostEventSource *>(g_source_new(&postEventSourceFuncs, sizeof(GPostEventSource))); postEventSource->serialNumber = 1; @@ -257,14 +324,21 @@ QEventDispatcherGlibPrivate::QEventDispatcherGlibPrivate(GMainContext *context) g_source_set_can_recurse(&socketNotifierSource->source, true); g_source_attach(&socketNotifierSource->source, mainContext); - // setup timerSource + // setup normal and idle timer sources timerSource = reinterpret_cast<GTimerSource *>(g_source_new(&timerSourceFuncs, sizeof(GTimerSource))); (void) new (&timerSource->timerList) QTimerInfoList(); timerSource->processEventsFlags = QEventLoop::AllEvents; + timerSource->runWithIdlePriority = false; g_source_set_can_recurse(&timerSource->source, true); - g_source_set_priority(&timerSource->source, G_PRIORITY_DEFAULT_IDLE); g_source_attach(&timerSource->source, mainContext); + + idleTimerSource = reinterpret_cast<GIdleTimerSource *>(g_source_new(&idleTimerSourceFuncs, + sizeof(GIdleTimerSource))); + idleTimerSource->timerSource = timerSource; + g_source_set_can_recurse(&idleTimerSource->source, true); + g_source_set_priority(&idleTimerSource->source, G_PRIORITY_DEFAULT_IDLE); + g_source_attach(&idleTimerSource->source, mainContext); } QEventDispatcherGlib::QEventDispatcherGlib(QObject *parent) @@ -272,12 +346,9 @@ QEventDispatcherGlib::QEventDispatcherGlib(QObject *parent) { } -QEventDispatcherGlib::QEventDispatcherGlib(GMainContext *mainContext, - QObject *parent) - : QAbstractEventDispatcher(*(new QEventDispatcherGlibPrivate(mainContext)), - parent) -{ -} +QEventDispatcherGlib::QEventDispatcherGlib(GMainContext *mainContext, QObject *parent) + : QAbstractEventDispatcher(*(new QEventDispatcherGlibPrivate(mainContext)), parent) +{ } QEventDispatcherGlib::~QEventDispatcherGlib() { @@ -289,6 +360,9 @@ QEventDispatcherGlib::~QEventDispatcherGlib() g_source_destroy(&d->timerSource->source); g_source_unref(&d->timerSource->source); d->timerSource = 0; + g_source_destroy(&d->idleTimerSource->source); + g_source_unref(&d->idleTimerSource->source); + d->idleTimerSource = 0; // destroy socket notifier source for (int i = 0; i < d->socketNotifierSource->pollfds.count(); ++i) { @@ -324,11 +398,16 @@ bool QEventDispatcherGlib::processEvents(QEventLoop::ProcessEventsFlags flags) // tell postEventSourcePrepare() and timerSource about any new flags QEventLoop::ProcessEventsFlags savedFlags = d->timerSource->processEventsFlags; d->timerSource->processEventsFlags = flags; - + + if (!(flags & QEventLoop::EventLoopExec)) { + // force timers to be sent at normal priority + d->timerSource->runWithIdlePriority = false; + } + bool result = g_main_context_iteration(d->mainContext, canWait); while (!result && canWait) result = g_main_context_iteration(d->mainContext, canWait); - + d->timerSource->processEventsFlags = savedFlags; if (canWait) diff --git a/src/corelib/kernel/qeventdispatcher_glib_p.h b/src/corelib/kernel/qeventdispatcher_glib_p.h index 8dbc44d..6a4e726 100644 --- a/src/corelib/kernel/qeventdispatcher_glib_p.h +++ b/src/corelib/kernel/qeventdispatcher_glib_p.h @@ -98,6 +98,7 @@ protected: struct GPostEventSource; struct GSocketNotifierSource; struct GTimerSource; +struct GIdleTimerSource; class Q_CORE_EXPORT QEventDispatcherGlibPrivate : public QAbstractEventDispatcherPrivate { @@ -108,6 +109,7 @@ public: GPostEventSource *postEventSource; GSocketNotifierSource *socketNotifierSource; GTimerSource *timerSource; + GIdleTimerSource *idleTimerSource; }; QT_END_NAMESPACE diff --git a/src/corelib/kernel/qeventdispatcher_unix.cpp b/src/corelib/kernel/qeventdispatcher_unix.cpp index c775c9a..7e1971f 100644 --- a/src/corelib/kernel/qeventdispatcher_unix.cpp +++ b/src/corelib/kernel/qeventdispatcher_unix.cpp @@ -423,10 +423,10 @@ bool QTimerInfoList::timerWait(timeval &tm) // Find first waiting timer not already active QTimerInfo *t = 0; for (QTimerInfoList::const_iterator it = constBegin(); it != constEnd(); ++it) { - if (!(*it)->inTimerEvent) { - t = *it; - break; - } + if (!(*it)->inTimerEvent) { + t = *it; + break; + } } if (!t) |