From a7865cf6918fc3457d0141522e791a92bcf62810 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Fri, 7 Dec 2012 20:06:25 -0600 Subject: [PATCH] Fix glib event loop threading --- src/kernel/qeventloop_glib_p.h | 58 ++++++++++----------- src/kernel/qeventloop_x11_glib.cpp | 81 +++++++++++++++--------------- 2 files changed, 70 insertions(+), 69 deletions(-) diff --git a/src/kernel/qeventloop_glib_p.h b/src/kernel/qeventloop_glib_p.h index 7de324d..ef0e6ac 100644 --- a/src/kernel/qeventloop_glib_p.h +++ b/src/kernel/qeventloop_glib_p.h @@ -84,49 +84,49 @@ struct QSockNotGPollFD class QEventLoopPrivate { public: - QEventLoopPrivate() - { - reset(); - } - - void reset() { - looplevel = 0; - quitcode = 0; - quitnow = FALSE; - exitloop = FALSE; - shortcut = FALSE; - singletoolkit = TRUE; - } - - int looplevel; - int quitcode; - unsigned int quitnow : 1; - unsigned int exitloop : 1; - unsigned int shortcut : 1; + QEventLoopPrivate() + { + reset(); + } + + void reset() { + looplevel = 0; + quitcode = 0; + quitnow = FALSE; + exitloop = FALSE; + shortcut = FALSE; + singletoolkit = TRUE; + } + + int looplevel; + int quitcode; + unsigned int quitnow : 1; + unsigned int exitloop : 1; + unsigned int shortcut : 1; #if defined(Q_WS_X11) - int xfd; + int xfd; GPollFD x_gPollFD; #endif // Q_WS_X11 - int thread_pipe[2]; - + int thread_pipe[2]; GPollFD threadPipe_gPollFD; - - QPtrList sn_list; - // pending socket notifiers list - QPtrList sn_pending_list; - + QPtrList sn_list; + + // pending socket notifiers list + QPtrList sn_pending_list; + // store flags for one iteration uint pev_flags; - + // My GSource - GSource * gSource; bool singletoolkit; + // main context + GMainContext *ctx; }; #endif // QEVENTLOOP_GLIB_P_H diff --git a/src/kernel/qeventloop_x11_glib.cpp b/src/kernel/qeventloop_x11_glib.cpp index 0d2275e..771428b 100644 --- a/src/kernel/qeventloop_x11_glib.cpp +++ b/src/kernel/qeventloop_x11_glib.cpp @@ -48,6 +48,7 @@ #if defined(QT_THREAD_SUPPORT) # include "qmutex.h" +# include "qthread.h" #endif // QT_THREAD_SUPPORT #include @@ -79,7 +80,7 @@ static GSourceFuncs qt_gsource_funcs = { // forward main loop callbacks to QEventLoop methods! static gboolean qt_gsource_prepare ( GSource *source, - gint *timeout ) + gint *timeout ) { QtGSource * qtGSource; qtGSource = (QtGSource*) source; @@ -97,9 +98,18 @@ static gboolean qt_gsource_dispatch ( GSource *source, { Q_UNUSED(callback); Q_UNUSED(user_data); - + QtGSource * qtGSource = (QtGSource*) source; - return qtGSource->qeventLoop->gsourceDispatch(source); + QEventLoop* candidateEventLoop = qtGSource->qeventLoop; + QEventLoop* activeThreadEventLoop = QApplication::eventLoop(); + + if (candidateEventLoop == activeThreadEventLoop) { + return candidateEventLoop->gsourceDispatch(source); + } + else { + // Dispatch failed + return FALSE; + } } @@ -171,7 +181,7 @@ void QEventLoop::init() { // initialize ProcessEventFlags (all events & wait for more) d->pev_flags = AllEvents | WaitForMore; - + // initialize the common parts of the event loop if (pipe( d->thread_pipe ) < 0) { // Error! @@ -185,35 +195,33 @@ void QEventLoop::init() d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() ); } + // new main context for thread + d->ctx = g_main_context_new(); + g_main_context_push_thread_default(d->ctx); + // new GSource QtGSource * qtGSource = (QtGSource*) g_source_new(&qt_gsource_funcs, sizeof(QtGSource)); - g_source_set_can_recurse ((GSource*)qtGSource, TRUE); - qtGSource->qeventLoop = this; - // init main loop and attach gsource + // init main loop and attach gsource #ifdef DEBUG_QT_GLIBMAINLOOP printf("inside init(1)\n"); #endif - g_main_loop_new (NULL, 1); - - g_source_attach( (GSource*)qtGSource, NULL ); - + g_main_loop_new (d->ctx, 1); + g_source_attach( (GSource*)qtGSource, d->ctx ); d->gSource = (GSource*) qtGSource; - + // poll for X11 events - if ( qt_is_gui_used && QApplication::isGuiThread() ) { d->x_gPollFD.fd = d->xfd; d->x_gPollFD.events = G_IO_IN | G_IO_HUP; - g_source_add_poll(d->gSource, &d->x_gPollFD); + g_source_add_poll(d->gSource, &d->x_gPollFD); } // poll thread-pipe - d->threadPipe_gPollFD.fd = d->thread_pipe[0]; d->threadPipe_gPollFD.events = G_IO_IN | G_IO_HUP; @@ -231,10 +239,13 @@ void QEventLoop::cleanup() close( d->thread_pipe[0] ); close( d->thread_pipe[1] ); cleanupTimers(); - + // cleanup the X11 parts of the event loop d->xfd = -1; - + + // unref the main context + g_main_context_unref(d->ctx); + // todo: destroy gsource } @@ -251,7 +262,7 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags ) d->pev_flags = flags; - rval = g_main_context_iteration(NULL, flags & WaitForMore ? TRUE : FALSE); + rval = g_main_context_iteration(d->ctx, flags & WaitForMore ? TRUE : FALSE); d->pev_flags = save_flags; @@ -411,40 +422,30 @@ bool QEventLoop::gsourcePrepare(GSource *gs, int * timeout) for ( it = qt_preselect_handler->begin(); it != end; ++it ) (**it)(); } - - // unlock the GUI mutex and select. when we return from this function, there is - // something for us to do -#if defined(QT_THREAD_SUPPORT) - locker.mutex()->unlock(); -#endif - + #ifdef DEBUG_QT_GLIBMAINLOOP printf("inside gsourcePrepare(2.1) canwait=%d\n", canWait); #endif // do we have to dispatch events? - if (hasPendingEvents()) { + if (hasPendingEvents()) { *timeout = 0; // no time to stay in poll - - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourcePrepare(3a)\n"); - #endif - +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourcePrepare(3a)\n"); +#endif return FALSE; } // stay in poll until something happens? if (!tm) { // fixme *timeout = -1; // wait forever - #ifdef DEBUG_QT_GLIBMAINLOOP - printf("inside gsourcePrepare(3b) timeout=%d \n", *timeout); - #endif - - +#ifdef DEBUG_QT_GLIBMAINLOOP + printf("inside gsourcePrepare(3b) timeout=%d \n", *timeout); +#endif return FALSE; } - // else timeout >=0 + // else timeout >=0 *timeout = tm->tv_sec * 1000 + tm->tv_usec/1000; #ifdef DEBUG_QT_GLIBMAINLOOP @@ -529,7 +530,7 @@ bool QEventLoop::gsourceDispatch(GSource *gs) { QMutexLocker locker( QApplication::qt_mutex ); #endif #if defined(QT_THREAD_SUPPORT) - locker.mutex()->lock(); + if (locker.mutex()) locker.mutex()->lock(); #endif int nevents=0; @@ -598,13 +599,13 @@ bool QEventLoop::gsourceDispatch(GSource *gs) { qt_reset_color_avail(); #if defined(QT_THREAD_SUPPORT) - locker.mutex()->unlock(); + if (locker.mutex()) locker.mutex()->unlock(); #endif processX11Events(); } else { #if defined(QT_THREAD_SUPPORT) - locker.mutex()->unlock(); + if (locker.mutex()) locker.mutex()->unlock(); #endif }