summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
authorBradley T. Hughes <bradley.hughes@nokia.com>2009-09-23 13:51:17 +0200
committerBradley T. Hughes <bradley.hughes@nokia.com>2009-10-05 13:03:49 +0200
commit0ed23e95fa756fd851f509a565f91ab43fc30449 (patch)
tree9c4f8dd088587ed2aab8708ac52b37f3ba89cab4 /src/corelib
parent0573653f830fada99311c88ab46e8f5a37854b90 (diff)
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)
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/kernel/qeventdispatcher_glib.cpp133
-rw-r--r--src/corelib/kernel/qeventdispatcher_glib_p.h2
-rw-r--r--src/corelib/kernel/qeventdispatcher_unix.cpp8
3 files changed, 112 insertions, 31 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_glib.cpp b/src/corelib/kernel/qeventdispatcher_glib.cpp
index 6e457f4ce5..665b73ef59 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 8dbc44d0c2..6a4e7260c7 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 c775c9a9b6..7e1971fb7a 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)