Prevent busy loop in glib event dispatcher
.. when running event loop with QEventLoop::ExcludeUserInputEvents. In a properly functioning code, g_main_context_iteration is expected to block until any event source becomes ready to dispatch an event (or interrupt occurs). Qt provides several custom event sources to the Glib event loop. The bug (busy loop) was caused by faulty event source implementation when QEventLoop::ExcludeUserInputEvents is set. As long as the window system's event queue was not empty, we signaled to the event dispatcher that there is an event ready to be dispatched. This results in the dispatcher calling the relevant dispatch function (which does handle the ExcludeUserInputEvents flag correctly). As we do not dispatch user events, the window system's event queue never becomes empty and we enter a busy loop (CPU running at 100%) where we signal that we have events to dispatch, but we actually do not dispatch them and g_main_context_iteration never gets to block. This busy loop can cause blocking GTK functions such as gtk_dialog_run() never return. Task-number: QTBUG-59760 Task-number: QTBUG-57101 Change-Id: I545b7951108eeaba019614ae8f5a1168c8b26c27 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> Reviewed-by: Lars Knoll <lars.knoll@qt.io> Reviewed-by: Gunnar Sletta <gunnar@crimson.no>bb10
parent
c2cac34e94
commit
fbb485d4f6
|
|
@ -141,6 +141,11 @@ int QWindowSystemInterfacePrivate::windowSystemEventsQueued()
|
|||
return windowSystemEventQueue.count();
|
||||
}
|
||||
|
||||
bool QWindowSystemInterfacePrivate::nonUserInputEventsQueued()
|
||||
{
|
||||
return windowSystemEventQueue.nonUserInputEventsQueued();
|
||||
}
|
||||
|
||||
QWindowSystemInterfacePrivate::WindowSystemEvent * QWindowSystemInterfacePrivate::getWindowSystemEvent()
|
||||
{
|
||||
return windowSystemEventQueue.takeFirstOrReturnNull();
|
||||
|
|
@ -955,6 +960,11 @@ int QWindowSystemInterface::windowSystemEventsQueued()
|
|||
return QWindowSystemInterfacePrivate::windowSystemEventsQueued();
|
||||
}
|
||||
|
||||
bool QWindowSystemInterface::nonUserInputEventsQueued()
|
||||
{
|
||||
return QWindowSystemInterfacePrivate::nonUserInputEventsQueued();
|
||||
}
|
||||
|
||||
// --------------------- QtTestLib support ---------------------
|
||||
|
||||
// The following functions are used by testlib, and need to be synchronous to avoid
|
||||
|
|
|
|||
|
|
@ -246,6 +246,7 @@ public:
|
|||
static bool flushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
|
||||
static void deferredFlushWindowSystemEvents(QEventLoop::ProcessEventsFlags flags);
|
||||
static int windowSystemEventsQueued();
|
||||
static bool nonUserInputEventsQueued();
|
||||
};
|
||||
|
||||
#ifndef QT_NO_DEBUG_STREAM
|
||||
|
|
|
|||
|
|
@ -458,6 +458,14 @@ public:
|
|||
return impl.takeAt(i);
|
||||
return 0;
|
||||
}
|
||||
bool nonUserInputEventsQueued()
|
||||
{
|
||||
const QMutexLocker locker(&mutex);
|
||||
for (int i = 0; i < impl.size(); ++i)
|
||||
if (!(impl.at(i)->type & QWindowSystemInterfacePrivate::UserInputEvent))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
void append(WindowSystemEvent *e)
|
||||
{ const QMutexLocker locker(&mutex); impl.append(e); }
|
||||
int count() const
|
||||
|
|
@ -488,6 +496,7 @@ public:
|
|||
static WindowSystemEventList windowSystemEventQueue;
|
||||
|
||||
static int windowSystemEventsQueued();
|
||||
static bool nonUserInputEventsQueued();
|
||||
static WindowSystemEvent *getWindowSystemEvent();
|
||||
static WindowSystemEvent *getNonUserInputWindowSystemEvent();
|
||||
static WindowSystemEvent *peekWindowSystemEvent(EventType t);
|
||||
|
|
|
|||
|
|
@ -46,8 +46,6 @@
|
|||
#include <glib.h>
|
||||
#include "private/qguiapplication_p.h"
|
||||
|
||||
#include <qdebug.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
struct GUserEventSource
|
||||
|
|
@ -56,12 +54,15 @@ struct GUserEventSource
|
|||
QPAEventDispatcherGlib *q;
|
||||
};
|
||||
|
||||
static gboolean userEventSourcePrepare(GSource *s, gint *timeout)
|
||||
static gboolean userEventSourcePrepare(GSource *source, gint *timeout)
|
||||
{
|
||||
Q_UNUSED(s)
|
||||
Q_UNUSED(timeout)
|
||||
|
||||
return QWindowSystemInterface::windowSystemEventsQueued() > 0;
|
||||
GUserEventSource *userEventSource = reinterpret_cast<GUserEventSource *>(source);
|
||||
QPAEventDispatcherGlib *dispatcher = userEventSource->q;
|
||||
if (dispatcher->m_flags & QEventLoop::ExcludeUserInputEvents)
|
||||
return QWindowSystemInterface::nonUserInputEventsQueued();
|
||||
else
|
||||
return QWindowSystemInterface::windowSystemEventsQueued() > 0;
|
||||
}
|
||||
|
||||
static gboolean userEventSourceCheck(GSource *source)
|
||||
|
|
|
|||
Loading…
Reference in New Issue