From 78125ea2f051107b84fdc0354acdedb7885308ee Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Thu, 6 Dec 2012 16:47:27 -0600 Subject: Add real threading support, including per-thread event loops, to QThread --- src/kernel/qapplication.cpp | 124 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 110 insertions(+), 14 deletions(-) (limited to 'src/kernel/qapplication.cpp') diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp index 51aa247..a9c9fb8 100644 --- a/src/kernel/qapplication.cpp +++ b/src/kernel/qapplication.cpp @@ -68,6 +68,7 @@ #if defined(QT_THREAD_SUPPORT) # include "qmutex.h" # include "qthread.h" +# include #endif // QT_THREAD_SUPPORT #include @@ -383,7 +384,25 @@ Q_EXPORT Qt::HANDLE qt_get_application_thread_id() } #endif // QT_THREAD_SUPPORT +#ifndef QT_THREAD_SUPPORT QEventLoop *QApplication::eventloop = 0; // application event loop +#endif + +#ifdef QT_THREAD_SUPPORT +QEventLoop* QApplication::currentEventLoop() { + QThread* thread = QThread::currentThreadObject(); + if (thread) { + if (thread->d) { + return thread->d->eventLoop; + } + } + return NULL; +} +#else +QEventLoop* QApplication::currentEventLoop() { + return QApplication::eventloop; +} +#endif #ifndef QT_NO_ACCEL extern bool qt_dispatchAccelEvent( QWidget*, QKeyEvent* ); // def in qaccel.cpp @@ -516,6 +535,41 @@ QClipboard *qt_clipboard = 0; // global clipboard object #endif QWidgetList * qt_modal_stack=0; // stack of modal widgets +#ifdef QT_THREAD_SUPPORT +// thread wrapper for the main() thread +class QCoreApplicationThread : public QThread +{ +public: + inline QCoreApplicationThread() + { + QThreadInstance::setCurrentThread(this); + + // thread should be running and not finished for the lifetime + // of the application (even if QCoreApplication goes away) + d->running = true; + d->finished = false; + d->eventLoop = NULL; + } + inline ~QCoreApplicationThread() + { + // avoid warning from QThread + d->running = false; + } +private: + inline void run() + { + // this function should never be called, it is implemented + // only so that we can instantiate the object + qFatal("QCoreApplicationThread: internal error"); + } +}; + +static QCoreApplicationThread qt_main_thread; +static QThread *mainThread() { return &qt_main_thread; } +#else +static QThread* mainThread() { return QThread::currentThread(); } +#endif + // Definitions for posted events struct QPostEvent { QPostEvent( QObject *r, QEvent *e ): receiver( r ), event( e ) {} @@ -818,8 +872,8 @@ void QApplication::construct( int &argc, char **argv, Type type ) initialize( argc, argv ); if ( qt_is_gui_used ) qt_maxWindowRect = desktop()->rect(); - if ( eventloop ) - eventloop->appStartingUp(); + if ( currentEventLoop() ) + currentEventLoop()->appStartingUp(); } /*! @@ -874,8 +928,8 @@ QApplication::QApplication( Display* dpy, HANDLE visual, HANDLE colormap ) if ( qt_is_gui_used ) qt_maxWindowRect = desktop()->rect(); - if ( eventloop ) - eventloop->appStartingUp(); + if ( currentEventLoop() ) + currentEventLoop()->appStartingUp(); } /*! @@ -916,13 +970,26 @@ QApplication::QApplication(Display *dpy, int argc, char **argv, if ( qt_is_gui_used ) qt_maxWindowRect = desktop()->rect(); - if ( eventloop ) - eventloop->appStartingUp(); + if ( currentEventLoop() ) + currentEventLoop()->appStartingUp(); } #endif // Q_WS_X11 +#ifdef QT_THREAD_SUPPORT +QThread* QApplication::guiThread() { + return mainThread(); +} + +bool QApplication::isGuiThread() { + return (QThread::currentThreadObject() == guiThread()); +} +#else +bool QApplication::isGuiThread() { + return true; +} +#endif void QApplication::init_precmdline() { @@ -1030,8 +1097,8 @@ QApplication::~QApplication() } #endif - if ( eventloop ) - eventloop->appClosingDown(); + if ( currentEventLoop() ) + currentEventLoop()->appClosingDown(); if ( postRList ) { QVFuncList::Iterator it = postRList->begin(); while ( it != postRList->end() ) { // call post routines @@ -2698,8 +2765,20 @@ bool QApplication::internalNotify( QObject *receiver, QEvent * e) } - if (!handled) + if (!handled) { +#if defined(QT_THREAD_SUPPORT) + bool locked = QApplication::qt_mutex->locked(); + if (locked) { + QApplication::qt_mutex->unlock(); + } +#endif consumed = receiver->event( e ); +#if defined(QT_THREAD_SUPPORT) + if (locked) { + QApplication::qt_mutex->lock(); + } +#endif + } e->spont = FALSE; return consumed; } @@ -2793,9 +2872,10 @@ void QApplication::processOneEvent() */ QEventLoop *QApplication::eventLoop() { - if ( !eventloop && !is_app_closing ) + if ( !currentEventLoop() && !is_app_closing ) { (void) new QEventLoop( qApp, "default event loop" ); - return eventloop; + } + return currentEventLoop(); } @@ -3263,8 +3343,23 @@ void QApplication::postEvent( QObject *receiver, QEvent *event ) l->append( pe ); globalPostedEvents->append( pe ); - if (eventloop) - eventloop->wakeUp(); +#ifdef QT_THREAD_SUPPORT + if ( event->type() == QEvent::MetaCall ) { + // Wake up the receiver thread event loop + QThread* thread = receiver->contextThreadObject(); + if (thread) { + if (thread->d) { + if (thread->d->eventLoop) { + thread->d->eventLoop->wakeUp(); + } + } + } + return; + } +#endif + + if (currentEventLoop()) + currentEventLoop()->wakeUp(); } @@ -3326,7 +3421,8 @@ void QApplication::sendPostedEvents( QObject *receiver, int event_type ) && ( receiver == 0 // we send to all receivers || receiver == pe->receiver ) // we send to THAT receiver && ( event_type == 0 // we send all types - || event_type == pe->event->type() ) ) { // we send THAT type + || event_type == pe->event->type() ) // we send THAT type + && ( (!pe->receiver) || (pe->receiver->contextThreadObject() == QThread::currentThreadObject()) ) ) { // only send if active thread is receiver object owning thread // first, we diddle the event so that we can deliver // it, and that noone will try to touch it later. pe->event->posted = FALSE; -- cgit v1.2.1 From caf80d88243aaa00e8f1baeaa6b7e4c3aca75f63 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Thu, 6 Dec 2012 18:29:37 -0600 Subject: Add threading tutorial and fix a couple rare crashes --- src/kernel/qapplication.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) (limited to 'src/kernel/qapplication.cpp') diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp index a9c9fb8..f3b0119 100644 --- a/src/kernel/qapplication.cpp +++ b/src/kernel/qapplication.cpp @@ -2767,7 +2767,10 @@ bool QApplication::internalNotify( QObject *receiver, QEvent * e) if (!handled) { #if defined(QT_THREAD_SUPPORT) - bool locked = QApplication::qt_mutex->locked(); + bool locked = false; + if (QApplication::qt_mutex) { + locked = QApplication::qt_mutex->locked(); + } if (locked) { QApplication::qt_mutex->unlock(); } @@ -2775,7 +2778,9 @@ bool QApplication::internalNotify( QObject *receiver, QEvent * e) consumed = receiver->event( e ); #if defined(QT_THREAD_SUPPORT) if (locked) { - QApplication::qt_mutex->lock(); + if (QApplication::qt_mutex) { + QApplication::qt_mutex->lock(); + } } #endif } -- cgit v1.2.1 From 9bff9eeefc262c8509b2db7c1120f6001d65e64c Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Fri, 7 Dec 2012 15:01:56 -0600 Subject: Add level method to recursive mutex Enhance thread safety when making event calls Minor cleanup of whitespace in glib event loop --- src/kernel/qapplication.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src/kernel/qapplication.cpp') diff --git a/src/kernel/qapplication.cpp b/src/kernel/qapplication.cpp index f3b0119..5b43301 100644 --- a/src/kernel/qapplication.cpp +++ b/src/kernel/qapplication.cpp @@ -2767,18 +2767,21 @@ bool QApplication::internalNotify( QObject *receiver, QEvent * e) if (!handled) { #if defined(QT_THREAD_SUPPORT) - bool locked = false; + int locklevel = 0; + int llcount; if (QApplication::qt_mutex) { - locked = QApplication::qt_mutex->locked(); - } - if (locked) { - QApplication::qt_mutex->unlock(); + QApplication::qt_mutex->lock(); // 1 of 2 + locklevel = qt_mutex->level() - 1; + for (llcount=0; llcountunlock(); + } + QApplication::qt_mutex->unlock(); // 2 of 2 } #endif consumed = receiver->event( e ); #if defined(QT_THREAD_SUPPORT) - if (locked) { - if (QApplication::qt_mutex) { + if (QApplication::qt_mutex) { + for (llcount=0; llcountlock(); } } -- cgit v1.2.1