283 lines
10 KiB
Diff
283 lines
10 KiB
Diff
commit 063bded33b417cdf92fd51366fc7fdb06dea00ba
|
|
Author: Bradley T. Hughes <bradley.hughes@nokia.com>
|
|
Date: Wed Sep 23 13:51:17 2009 +0200
|
|
|
|
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)
|
|
(cherry picked from commit 0ed23e95fa756fd851f509a565f91ab43fc30449)
|
|
|
|
diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp
|
|
index 87e9728..7f6dbb6 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 eb7fb75..4103aa3 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 897bb49..903b0eb 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)
|