Add real threading support, including per-thread event loops, to QThread

pull/2/head
Timothy Pearson 12 years ago
parent 7aa5ac7f0e
commit 78125ea2f0

@ -68,6 +68,7 @@
#if defined(QT_THREAD_SUPPORT)
# include "qmutex.h"
# include "qthread.h"
# include <private/qthreadinstance_p.h>
#endif // QT_THREAD_SUPPORT
#include <stdlib.h>
@ -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;

@ -63,6 +63,7 @@ class QWSDecoration;
#ifdef QT_THREAD_SUPPORT
class QMutex;
class QThread;
#endif // QT_THREAD_SUPPORT
@ -369,7 +370,9 @@ private:
#ifndef QT_NO_CURSOR
static QCursor *app_cursor;
#endif
#ifndef QT_THREAD_SUPPORT
static QEventLoop* eventloop;
#endif
static int app_tracking;
static bool is_app_running;
static bool is_app_closing;
@ -425,6 +428,7 @@ private:
static void removePostedEvent( QEvent * );
static void removePostedEvents( QObject *receiver, int event_type );
friend class QObject;
friend class QWidget;
friend class QETWidget;
friend class QDialog;
@ -444,6 +448,15 @@ private: // Disabled copy constructor and operator=
QApplication( const QApplication & );
QApplication &operator=( const QApplication & );
#endif
private:
static QEventLoop* currentEventLoop();
public:
#ifdef QT_THREAD_SUPPORT
static QThread* guiThread();
#endif
static bool isGuiThread();
};
inline int QApplication::argc() const

@ -137,6 +137,8 @@ public:
HelpRequest = 95, // CE (?) button pressed
WindowStateChange = 96, // window state has changed
IconDrag = 97, // proxy icon dragged
MetaCall = 98, // meta method call (internal)
ThreadChange = 99, // thread changed
User = 1000, // first user event id
MaxUser = 65535 // last user event id
};

@ -41,6 +41,11 @@
#include "qapplication.h"
#include "qdatetime.h"
#ifdef QT_THREAD_SUPPORT
# include "qthread.h"
# include "qthreadinstance_p.h"
#endif
/*!
\class QEventLoop
\brief The QEventLoop class manages the event queue.
@ -100,15 +105,27 @@ QEventLoop::QEventLoop( QObject *parent, const char *name )
: QObject( parent, name )
{
#if defined(QT_CHECK_STATE)
if ( QApplication::eventloop )
qFatal( "QEventLoop: there must be only one event loop object. \nConstruct it before QApplication." );
// for now ;)
if ( QApplication::currentEventLoop() )
qFatal( "QEventLoop: there must be only one event loop object per thread. \nIf this is supposed to be the main GUI event loop, construct it before QApplication." );
if (!QThread::currentThreadObject()) {
qFatal( "QEventLoop: this object can only be used in threads constructed via QThread." );
}
#endif // QT_CHECK_STATE
d = new QEventLoopPrivate;
init();
#ifdef QT_THREAD_SUPPORT
QThread* thread = QThread::currentThreadObject();
if (thread) {
if (thread->d) {
thread->d->eventLoop = this;
}
}
#else
QApplication::eventloop = this;
#endif
}
/*!
@ -118,7 +135,16 @@ QEventLoop::~QEventLoop()
{
cleanup();
delete d;
#ifdef QT_THREAD_SUPPORT
QThread* thread = QThread::currentThreadObject();
if (thread) {
if (thread->d) {
thread->d->eventLoop = 0;
}
}
#else
QApplication::eventloop = 0;
#endif
}
/*!

@ -40,6 +40,7 @@
#include "qeventloop.h"
#include "qapplication.h"
#include "qbitarray.h"
#include "qmutex.h"
#include <stdlib.h>
#include <sys/types.h>

@ -44,6 +44,7 @@
#include "qeventloop.h"
#include "qapplication.h"
#include "qbitarray.h"
#include "qmutex.h"
#include <stdlib.h>
#include <sys/types.h>
@ -579,12 +580,9 @@ int QEventLoop::activateSocketNotifiers()
++it;
d->sn_pending_list.removeRef( sn );
if ( sn->pending ) {
#ifdef DEBUG_QT_GLIBMAINLOOP
printf("activate sn : send event fd=%d\n", sn->gPollFD.fd );
#endif
sn->pending = FALSE;
QApplication::sendEvent( sn->obj, &event );
n_act++;

@ -146,6 +146,7 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags )
if ( qt_is_gui_used ) {
QApplication::sendPostedEvents();
if (QApplication::isGuiThread()) {
// Two loops so that posted events accumulate
while ( XPending( QPaintDevice::x11AppDisplay() ) ) {
// also flushes output buffer
@ -197,6 +198,7 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags )
}
}
}
}
if ( d->shortcut ) {
return FALSE;
@ -261,7 +263,7 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags )
FD_ZERO( &d->sn_vec[2].select_fds );
}
if ( qt_is_gui_used ) {
if ( qt_is_gui_used && QApplication::isGuiThread() ) {
// select for events on the event socket - only on X11
FD_SET( d->xfd, &d->sn_vec[0].select_fds );
highest = QMAX( highest, d->xfd );

@ -39,7 +39,6 @@
**
**********************************************************************/
#include "qeventloop_glib_p.h" // includes qplatformdefs.h
#include "qeventloop.h"
#include "qapplication.h"
@ -62,11 +61,9 @@ typedef struct {
QEventLoop * qeventLoop;
} QtGSource;
static gboolean qt_gsource_prepare ( GSource *source,
gint *timeout );
static gboolean qt_gsource_prepare ( GSource *source, gint *timeout );
static gboolean qt_gsource_check ( GSource *source );
static gboolean qt_gsource_dispatch ( GSource *source,
GSourceFunc callback, gpointer user_data );
static gboolean qt_gsource_dispatch ( GSource *source, GSourceFunc callback, gpointer user_data );
static GSourceFuncs qt_gsource_funcs = {
qt_gsource_prepare,
@ -134,38 +131,43 @@ static QVFuncList *qt_postselect_handler = 0;
void qt_install_preselect_handler( VFPTR handler )
{
if ( !qt_preselect_handler )
if ( !qt_preselect_handler ) {
qt_preselect_handler = new QVFuncList;
}
qt_preselect_handler->append( handler );
}
void qt_remove_preselect_handler( VFPTR handler )
{
if ( qt_preselect_handler ) {
QVFuncList::Iterator it = qt_preselect_handler->find( handler );
if ( it != qt_preselect_handler->end() )
if ( it != qt_preselect_handler->end() ) {
qt_preselect_handler->remove( it );
}
}
}
void qt_install_postselect_handler( VFPTR handler )
{
if ( !qt_postselect_handler )
if ( !qt_postselect_handler ) {
qt_postselect_handler = new QVFuncList;
}
qt_postselect_handler->prepend( handler );
}
void qt_remove_postselect_handler( VFPTR handler )
{
if ( qt_postselect_handler ) {
QVFuncList::Iterator it = qt_postselect_handler->find( handler );
if ( it != qt_postselect_handler->end() )
if ( it != qt_postselect_handler->end() ) {
qt_postselect_handler->remove( it );
}
}
}
void QEventLoop::init()
{
// initialize ProcessEventFlags (all events & wait for more)
d->pev_flags = AllEvents | WaitForMore;
// initialize the common parts of the event loop
@ -177,13 +179,12 @@ void QEventLoop::init()
// intitialize the X11 parts of the event loop
d->xfd = -1;
if ( qt_is_gui_used )
if ( qt_is_gui_used && QApplication::isGuiThread() ) {
d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() );
}
// new GSource
QtGSource * qtGSource = (QtGSource*) g_source_new(&qt_gsource_funcs,
sizeof(QtGSource));
QtGSource * qtGSource = (QtGSource*) g_source_new(&qt_gsource_funcs, sizeof(QtGSource));
g_source_set_can_recurse ((GSource*)qtGSource, TRUE);
@ -203,9 +204,7 @@ void QEventLoop::init()
// poll for X11 events
if ( qt_is_gui_used ) {
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);
@ -243,6 +242,7 @@ bool QEventLoop::processEvents( ProcessEventsFlags flags )
#ifdef DEBUG_QT_GLIBMAINLOOP
printf("inside processEvents(1) looplevel=%d\n", d->looplevel );
#endif
ProcessEventsFlags save_flags;
int rval;
save_flags = d->pev_flags;
@ -276,6 +276,7 @@ bool QEventLoop::processX11Events()
if ( qt_is_gui_used ) {
QApplication::sendPostedEvents();
if (QApplication::isGuiThread()) {
// Two loops so that posted events accumulate
while ( XPending( QPaintDevice::x11AppDisplay() ) ) {
// also flushes output buffer
@ -327,6 +328,7 @@ bool QEventLoop::processX11Events()
}
}
}
}
if ( d->shortcut ) {
return FALSE;
@ -336,8 +338,7 @@ bool QEventLoop::processX11Events()
const uint exclude_all = ExcludeSocketNotifiers | 0x08;
// 0x08 == ExcludeTimers for X11 only
if ( nevents > 0 && ( flags & exclude_all ) == exclude_all &&
( flags & WaitForMore ) ) {
if ( nevents > 0 && ( flags & exclude_all ) == exclude_all && ( flags & WaitForMore ) ) {
return TRUE;
}
return FALSE;
@ -369,15 +370,15 @@ bool QEventLoop::gsourcePrepare(GSource *gs, int * timeout)
if ( ! ( flags & 0x08 ) ) { // 0x08 == ExcludeTimers for X11 only
tm = qt_wait_timer(); // wait for timer or X event
if ( !canWait ) {
if ( !tm )
if ( !tm ) {
tm = &zerotm;
}
tm->tv_sec = 0; // no time to wait
tm->tv_usec = 0;
}
}
// include or exclude SocketNotifiers (by setting or cleaning poll events)
if ( ! ( flags & ExcludeSocketNotifiers ) ) {
QPtrListIterator<QSockNotGPollFD> it( d->sn_list );
QSockNotGPollFD *sn;
@ -385,7 +386,8 @@ bool QEventLoop::gsourcePrepare(GSource *gs, int * timeout)
++it;
sn->gPollFD.events = sn->events; // restore poll events
}
} else {
}
else {
QPtrListIterator<QSockNotGPollFD> it( d->sn_list );
QSockNotGPollFD *sn;
while ( (sn=it.current()) ) {
@ -398,9 +400,9 @@ bool QEventLoop::gsourcePrepare(GSource *gs, int * timeout)
printf("inside gsourcePrepare(2) canwait=%d\n", canWait);
#endif
if ( canWait )
if ( canWait ) {
emit aboutToBlock();
}
if ( qt_preselect_handler ) {
QVFuncList::Iterator it, end = qt_preselect_handler->end();
@ -447,7 +449,6 @@ bool QEventLoop::gsourcePrepare(GSource *gs, int * timeout)
printf("inside gsourcePrepare(3c) timeout=%d \n", *timeout);
#endif
return FALSE;
}
@ -562,8 +563,6 @@ bool QEventLoop::gsourceDispatch(GSource *gs) {
// if select says data is ready on any socket, then set the socket notifier
// to pending
// if ( &d->sn_list ) {
QPtrList<QSockNotGPollFD> *list = &d->sn_list;
QSockNotGPollFD *sn = list->first();
while ( sn ) {
@ -582,8 +581,6 @@ bool QEventLoop::gsourceDispatch(GSource *gs) {
nevents += activateTimers();
}
// return true if we handled events, false otherwise
//return (nevents > 0);
@ -595,12 +592,10 @@ bool QEventLoop::gsourceDispatch(GSource *gs) {
if (hasPendingEvents()) {
// color approx. optimization - only on X11
qt_reset_color_avail();
processX11Events();
}
#if defined(QT_THREAD_SUPPORT)
@ -618,14 +613,15 @@ bool QEventLoop::gsourceDispatch(GSource *gs) {
bool QEventLoop::hasPendingEvents() const
{
extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
return ( qGlobalPostedEventsCount() || ( qt_is_gui_used ? XPending( QPaintDevice::x11AppDisplay() ) : 0));
return ( qGlobalPostedEventsCount() || ( (qt_is_gui_used && QApplication::isGuiThread()) ? XPending( QPaintDevice::x11AppDisplay() ) : 0));
}
void QEventLoop::appStartingUp()
{
if ( qt_is_gui_used )
if ( qt_is_gui_used ) {
d->xfd = XConnectionNumber( QPaintDevice::x11AppDisplay() );
}
}
void QEventLoop::appClosingDown()
{

@ -50,22 +50,107 @@
#include "qptrvector.h"
#ifdef QT_THREAD_SUPPORT
#include <qmutex.h>
#include "qmutex.h"
#include <private/qmutexpool_p.h>
#include "qthread.h"
#endif
#include <ctype.h>
#include <stdlib.h>
#ifndef QT_NO_USERDATA
class QObjectPrivate : public QPtrVector<QObjectUserData>
#else
class QObjectPrivate {
#endif
{
public:
#ifndef QT_NO_USERDATA
QObjectPrivate( uint s ) : QPtrVector<QObjectUserData>(s){ setAutoDelete( TRUE ); }
#endif
QThread* ownThread;
};
#else
class QObjectPrivate {
#if defined(QT_THREAD_SUPPORT)
void QObject::moveToThread_helper(QThread *targetThread)
{
QEvent e(QEvent::ThreadChange);
QApplication::sendEvent(this, &e);
if (childObjects) {
QObject *child;
QObjectListIt it(*childObjects);
while ( (child=it.current()) ) {
++it;
child->moveToThread_helper(targetThread);
}
}
}
void QObject::setThreadObject_helper(QThread *targetThread)
{
d->ownThread = targetThread;
if (childObjects) {
QObject *child;
QObjectListIt it(*childObjects);
while ( (child=it.current()) ) {
++it;
child->moveToThread_helper(targetThread);
}
}
}
/*!
Changes the thread affinity for this object and its children. The
object cannot be moved if it has a parent. Event processing will
continue in the \a targetThread. To move an object to the main
thread, pass QApplication::guiThread() as the \a targetThread.
Note that all active timers for the object will be reset. The
timers are first stopped in the current thread and restarted (with
the same interval) in the \a targetThread. As a result, constantly
moving an object between threads can postpone timer events
indefinitely.
\sa contextThreadObject()
*/
void QObject::moveToThread(QThread *targetThread)
{
QMutexLocker locker( QApplication::qt_mutex );
if (parentObj) {
#if defined(QT_DEBUG)
qWarning( "QObject::moveToThread: Cannot move objects with a parent" );
#endif
return;
}
if (isWidget) {
#if defined(QT_DEBUG)
qWarning( "QObject::moveToThread: Widgets cannot be moved to a new thread" );
#endif
return;
}
QThread *objectThread = contextThreadObject();
QThread *currentThread = QThread::currentThreadObject();
if (objectThread != currentThread) {
#if defined(QT_DEBUG)
qWarning( "QObject::moveToThread: Current thread is not the object's thread" );
#endif
return;
}
if (objectThread == targetThread) {
return;
}
moveToThread_helper(targetThread);
setThreadObject_helper(targetThread);
}
#endif
class QSenderObjectList : public QObjectList, public QShared
@ -75,6 +160,41 @@ public:
QObject *currentSender;
};
class Q_EXPORT QMetaCallEvent : public QEvent
{
public:
enum MetaCallType {
MetaCallEmit = 0,
MetaCallInvoke = 1
};
public:
QMetaCallEvent(int id, QObject *sender, QUObject *data, MetaCallType type);
~QMetaCallEvent();
inline int id() const { return id_; }
inline QObject *sender() const { return sender_; }
inline QUObject *data() const { return data_; }
inline MetaCallType type() const { return type_; }
private:
const int id_;
QObject *sender_;
QUObject *data_;
const MetaCallType type_;
};
/*! \internal
*/
QMetaCallEvent::QMetaCallEvent(int id, QObject *sender, QUObject *data, MetaCallType type)
:QEvent(MetaCall), id_(id), sender_(sender), data_(data), type_(type)
{ }
/*! \internal
*/
QMetaCallEvent::~QMetaCallEvent()
{ }
/*!
\class Qt qnamespace.h
@ -269,7 +389,21 @@ void *qt_find_obj_child( QObject *parent, const char *type, const char *name )
return 0;
}
#ifdef QT_THREAD_SUPPORT
/*!
Returns a pointer to the QThread* associated with
the current thread affinity of this object.
\sa moveToThread()
*/
QThread* QObject::contextThreadObject() const
{
return d->ownThread;
}
#endif
#ifndef QT_NO_PRELIMINARY_SIGNAL_SPY
/*
@ -436,6 +570,11 @@ QObject::QObject( QObject *parent, const char *name )
insert_tree( this );
isTree = TRUE;
}
if ( !d )
d = new QObjectPrivate(0);
d->ownThread = QThread::currentThreadObject();
}
@ -720,6 +859,36 @@ QObject* QObject::child( const char *objName, const char *inheritsClass,
return obj;
}
/*! \internal */
QUObject* deepCopyQUObjectArray(QUObject* origArray)
{
QUObject* newArray;
int count = 0;
while (!((origArray+count)->isLastObject)) {
count++;
}
count++;
newArray = (QUObject*)malloc(sizeof(QUObject)*count);
for (int i=0; i<count; i++) {
(origArray+i)->deepCopy(newArray+i);
}
return newArray;
}
/*! \internal */
void destroyDeepCopiedQUObjectArray(QUObject* uArray)
{
int count = 0;
while (!((uArray+count)->isLastObject)) {
count++;
}
count++;
for (int i=0; i<count; i++) {
(uArray+i)->~QUObject();
}
free(uArray);
}
/*!
\fn bool QObject::isWidgetType() const
@ -777,6 +946,40 @@ bool QObject::event( QEvent *e )
delete this;
return TRUE;
case QEvent::MetaCall:
{
QMetaCallEvent* metaEvent = dynamic_cast<QMetaCallEvent*>(e);
if (metaEvent) {
if (d->ownThread == QThread::currentThreadObject()) {
QSenderObjectList* sol;
QObject* oldSender = 0;
sol = senderObjects;
if ( sol ) {
oldSender = sol->currentSender;
sol->ref();
sol->currentSender = metaEvent->sender();
}
QUObject *o = metaEvent->data();
if (metaEvent->type() == QMetaCallEvent::MetaCallEmit) {
qt_emit( metaEvent->id(), o );
}
if (metaEvent->type() == QMetaCallEvent::MetaCallInvoke) {
qt_invoke( metaEvent->id(), o );
}
if (sol ) {
sol->currentSender = oldSender;
if ( sol->deref() ) {
delete sol;
}
}
}
else {
qWarning("QObject: Ignoring metacall event from non-owning thread");
}
destroyDeepCopiedQUObjectArray(metaEvent->data());
}
}
default:
if ( e->type() >= QEvent::User ) {
customEvent( (QCustomEvent*) e );
@ -2337,6 +2540,7 @@ void QObject::activate_signal( int signal )
if ( !signalsBlocked() && signal >= 0 &&
( !connections || !connections->at( signal ) ) ) {
QUObject o[1];
o[0].isLastObject = true;
qt_spy_signal( this, signal, o );
return;
}
@ -2349,6 +2553,7 @@ void QObject::activate_signal( int signal )
if ( !clist )
return;
QUObject o[1];
o[0].isLastObject = true;
activate_signal( clist, o );
}
@ -2364,6 +2569,8 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
qt_spy_signal( this, connections->findRef( clist), o );
#endif
const QThread *currentThread = QThread::currentThreadObject();
QObject *object;
QSenderObjectList* sol;
QObject* oldSender = 0;
@ -2377,10 +2584,26 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
sol->ref();
sol->currentSender = this;
}
if ( c->memberType() == QSIGNAL_CODE )
if ( c->memberType() == QSIGNAL_CODE ) {
if (object->d->ownThread == currentThread) {
object->qt_emit( c->member(), o );
else
}
else {
if (object->d->ownThread && !object->d->ownThread->finished()) {
QApplication::postEvent(object, new QMetaCallEvent(c->member(), this, deepCopyQUObjectArray(o), QMetaCallEvent::MetaCallEmit));
}
}
}
else {
if (object->d->ownThread == currentThread) {
object->qt_invoke( c->member(), o );
}
else {
if (object->d->ownThread && !object->d->ownThread->finished()) {
QApplication::postEvent(object, new QMetaCallEvent(c->member(), this, deepCopyQUObjectArray(o), QMetaCallEvent::MetaCallInvoke));
}
}
}
if ( sol ) {
sol->currentSender = oldSender;
if ( sol->deref() )
@ -2401,10 +2624,26 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
sol->ref();
sol->currentSender = this;
}
if ( c->memberType() == QSIGNAL_CODE )
if ( c->memberType() == QSIGNAL_CODE ) {
if (object->d->ownThread == currentThread) {
object->qt_emit( c->member(), o );
else
}
else {
if (object->d->ownThread && !object->d->ownThread->finished()) {
QApplication::postEvent(object, new QMetaCallEvent(c->member(), this, deepCopyQUObjectArray(o), QMetaCallEvent::MetaCallEmit));
}
}
}
else {
if (object->d->ownThread == currentThread) {
object->qt_invoke( c->member(), o );
}
else {
if (object->d->ownThread && !object->d->ownThread->finished()) {
QApplication::postEvent(object, new QMetaCallEvent(c->member(), this, deepCopyQUObjectArray(o), QMetaCallEvent::MetaCallInvoke));
}
}
}
if (sol ) {
sol->currentSender = oldSender;
if ( sol->deref() )
@ -2442,6 +2681,7 @@ void QObject::FNAME( int signal, TYPE param ) \
if ( !signalsBlocked() && signal >= 0 && \
( !connections || !connections->at( signal ) ) ) { \
QUObject o[2]; \
o[1].isLastObject = true; \
static_QUType_##TYPE.set( o+1, param ); \
qt_spy_signal( this, signal, o ); \
return; \
@ -2453,6 +2693,7 @@ void QObject::FNAME( int signal, TYPE param ) \
if ( !clist ) \
return; \
QUObject o[2]; \
o[1].isLastObject = true; \
static_QUType_##TYPE.set( o+1, param ); \
activate_signal( clist, o ); \
}
@ -2466,6 +2707,7 @@ void QObject::FNAME( int signal, TYPE param ) \
if ( !clist ) \
return; \
QUObject o[2]; \
o[1].isLastObject = true; \
static_QUType_##TYPE.set( o+1, param ); \
activate_signal( clist, o ); \
}

@ -63,6 +63,10 @@ class QObjectUserData;
#endif
struct QUObject;
#ifdef QT_THREAD_SUPPORT
class QThread;
#endif
class Q_EXPORT QObject: public Qt
{
Q_OBJECT
@ -217,6 +221,18 @@ private: // Disabled copy constructor and operator=
QObject( const QObject & );
QObject &operator=( const QObject & );
#endif
public:
#ifdef QT_THREAD_SUPPORT
QThread* contextThreadObject() const;
void moveToThread(QThread *targetThread);
#endif
private:
#ifdef QT_THREAD_SUPPORT
void moveToThread_helper(QThread *targetThread);
void setThreadObject_helper(QThread *targetThread);
#endif
};

@ -41,6 +41,7 @@
#include "qplatformdefs.h"
#include "qthread.h"
#include "qeventloop.h"
#include <private/qthreadinstance_p.h>
#ifndef QT_H
@ -238,4 +239,20 @@ void QThread::postEvent( QObject * receiver, QEvent * event )
}
#endif
QEventLoopThread::QEventLoopThread() : QThread()
{
//
}
QEventLoopThread::~QEventLoopThread()
{
//
}
void QEventLoopThread::run()
{
QEventLoop* eventLoop = QApplication::eventLoop();
if (eventLoop) eventLoop->exec();
}
#endif // QT_THREAD_SUPPORT

@ -118,11 +118,25 @@ protected:
private:
QThreadInstance * d;
friend class QThreadInstance;
friend class QCoreApplicationThread;
friend class QApplication;
friend class QEventLoop;
#if defined(Q_DISABLE_COPY)
QThread( const QThread & );
QThread &operator=( const QThread & );
#endif // Q_DISABLE_COPY
public:
static QThread* currentThreadObject();
};
class Q_EXPORT QEventLoopThread : public QThread
{
public:
QEventLoopThread();
~QEventLoopThread();
virtual void run();
};
#endif // QT_THREAD_SUPPORT

@ -52,11 +52,6 @@ typedef pthread_mutex_t Q_MUTEX_T;
#include <sched.h>
static QThreadInstance main_instance = {
0, { 0, &main_instance }, 0, 0, 1, 0, PTHREAD_COND_INITIALIZER, 0
};
static QMutexPool *qt_thread_mutexpool = 0;
@ -82,10 +77,20 @@ static void create_storage_key()
** QThreadInstance
*************************************************************************/
void QThreadInstance::setCurrentThread(QThread *thread)
{
pthread_once(&storage_key_once, create_storage_key);
pthread_setspecific(storage_key, thread);
}
QThreadInstance *QThreadInstance::current()
{
QThreadInstance *ret = NULL;
pthread_once( &storage_key_once, create_storage_key );
QThreadInstance *ret = (QThreadInstance *) pthread_getspecific( storage_key );
QThread *thread = (QThread *) pthread_getspecific( storage_key );
if (thread) {
ret = thread->d;
}
return ret;
}
@ -101,6 +106,8 @@ void QThreadInstance::init(unsigned int stackSize)
pthread_cond_init(&thread_done, NULL);
thread_id = 0;
eventLoop = 0;
// threads have not been initialized yet, do it now
if (! qt_thread_mutexpool) QThread::initialize();
}
@ -114,8 +121,8 @@ void *QThreadInstance::start( void *_arg )
{
void **arg = (void **) _arg;
pthread_once( &storage_key_once, create_storage_key );
pthread_setspecific( storage_key, arg[1] );
setCurrentThread( (QThread *) arg[0] );
pthread_cleanup_push( QThreadInstance::finish, arg[1] );
pthread_testcancel();
@ -192,9 +199,6 @@ void QThread::initialize()
qt_global_mutexpool = new QMutexPool( TRUE, 73 );
if ( ! qt_thread_mutexpool )
qt_thread_mutexpool = new QMutexPool( FALSE, 127 );
pthread_once( &storage_key_once, create_storage_key );
pthread_setspecific( storage_key, &main_instance );
}
/*! \internal
@ -206,11 +210,6 @@ void QThread::cleanup()
delete qt_thread_mutexpool;
qt_global_mutexpool = 0;
qt_thread_mutexpool = 0;
QThreadInstance::finish(&main_instance);
pthread_once( &storage_key_once, create_storage_key );
pthread_setspecific( storage_key, 0 );
}
/*!
@ -470,5 +469,20 @@ bool QThread::wait( unsigned long time )
return (ret == 0);
}
/*!
Returns a pointer to the currently executing QThread. If the
current thread was not started using the QThread API, this
function returns zero.
Note that QApplication creates a QThread object to represent the
main thread; calling this function from main() after creating
QApplication will return a valid pointer.
*/
QThread *QThread::currentThreadObject()
{
pthread_once(&storage_key_once, create_storage_key);
return reinterpret_cast<QThread *>(pthread_getspecific(storage_key));
}
#endif // QT_THREAD_SUPPORT

@ -56,6 +56,9 @@
#include "qstyle.h"
#include "qmetaobject.h"
#include "qguardedptr.h"
#if defined(QT_THREAD_SUPPORT)
#include "qthread.h"
#endif
#if defined(QT_ACCESSIBILITY_SUPPORT)
#include "qaccessible.h"
#endif
@ -887,6 +890,12 @@ QWidget::QWidget( QWidget *parent, const char *name, WFlags f, NFlags n )
}
#endif
#if defined(QT_THREAD_SUPPORT) && defined(QT_CHECK_STATE)
if (QThread::currentThreadObject() != QApplication::guiThread()) {
qFatal( "QWidget: Cannot create a QWidget outside of the main GUI thread" );
}
#endif
fstrut_dirty = 1;
isWidget = TRUE; // is a widget

@ -3193,6 +3193,7 @@ void generateClass() // generate C++ source code for a class
offset++;
}
}
fprintf( out, " o[%d].isLastObject = true;\n", f->args->count() + 0 );
fprintf( out, " activate_signal( clist, o );\n" );
// get return values from inOut parameters

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,58 +1,166 @@
#define CHAR_VAL 257
#define INT_VAL 258
#define DOUBLE_VAL 259
#define STRING 260
#define IDENTIFIER 261
#define FRIEND 262
#define TYPEDEF 263
#define AUTO 264
#define REGISTER 265
#define STATIC 266
#define EXTERN 267
#define INLINE 268
#define VIRTUAL 269
#define CONST 270
#define VOLATILE 271
#define CHAR 272
#define SHORT 273
#define INT 274
#define LONG 275
#define SIGNED 276
#define UNSIGNED 277
#define FLOAT 278
#define DOUBLE 279
#define VOID 280
#define ENUM 281
#define CLASS 282
#define STRUCT 283
#define UNION 284
#define ASM 285
#define PRIVATE 286
#define PROTECTED 287
#define PUBLIC 288
#define OPERATOR 289
#define DBL_COLON 290
#define TRIPLE_DOT 291
#define TEMPLATE 292
#define NAMESPACE 293
#define USING 294
#define MUTABLE 295
#define THROW 296
#define SIGNALS 297
#define SLOTS 298
#define Q_OBJECT 299
#define Q_PROPERTY 300
#define Q_OVERRIDE 301
#define Q_CLASSINFO 302
#define Q_ENUMS 303
#define Q_SETS 304
#define READ 305
#define WRITE 306
#define STORED 307
#define DESIGNABLE 308
#define SCRIPTABLE 309
#define RESET 310
typedef union {
/* A Bison parser, made by GNU Bison 2.4.1. */
/* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
CHAR_VAL = 258,
INT_VAL = 259,
DOUBLE_VAL = 260,
STRING = 261,
IDENTIFIER = 262,
FRIEND = 263,
TYPEDEF = 264,
AUTO = 265,
REGISTER = 266,
STATIC = 267,
EXTERN = 268,
INLINE = 269,
VIRTUAL = 270,
CONST = 271,
VOLATILE = 272,
CHAR = 273,
SHORT = 274,
INT = 275,
LONG = 276,
SIGNED = 277,
UNSIGNED = 278,
FLOAT = 279,
DOUBLE = 280,
VOID = 281,
ENUM = 282,
CLASS = 283,
STRUCT = 284,
UNION = 285,
ASM = 286,
PRIVATE = 287,
PROTECTED = 288,
PUBLIC = 289,
OPERATOR = 290,
DBL_COLON = 291,
TRIPLE_DOT = 292,
TEMPLATE = 293,
NAMESPACE = 294,
USING = 295,
MUTABLE = 296,
THROW = 297,
SIGNALS = 298,
SLOTS = 299,
Q_OBJECT = 300,
Q_PROPERTY = 301,
Q_OVERRIDE = 302,
Q_CLASSINFO = 303,
Q_ENUMS = 304,
Q_SETS = 305,
READ = 306,
WRITE = 307,
STORED = 308,
DESIGNABLE = 309,
SCRIPTABLE = 310,
RESET = 311
};
#endif
/* Tokens. */
#define CHAR_VAL 258
#define INT_VAL 259
#define DOUBLE_VAL 260
#define STRING 261
#define IDENTIFIER 262
#define FRIEND 263
#define TYPEDEF 264
#define AUTO 265
#define REGISTER 266
#define STATIC 267
#define EXTERN 268
#define INLINE 269
#define VIRTUAL 270
#define CONST 271
#define VOLATILE 272
#define CHAR 273
#define SHORT 274
#define INT 275
#define LONG 276
#define SIGNED 277
#define UNSIGNED 278
#define FLOAT 279
#define DOUBLE 280
#define VOID 281
#define ENUM 282
#define CLASS 283
#define STRUCT 284
#define UNION 285
#define ASM 286
#define PRIVATE 287
#define PROTECTED 288
#define PUBLIC 289
#define OPERATOR 290
#define DBL_COLON 291
#define TRIPLE_DOT 292
#define TEMPLATE 293
#define NAMESPACE 294
#define USING 295
#define MUTABLE 296
#define THROW 297
#define SIGNALS 298
#define SLOTS 299
#define Q_OBJECT 300
#define Q_PROPERTY 301
#define Q_OVERRIDE 302
#define Q_CLASSINFO 303
#define Q_ENUMS 304
#define Q_SETS 305
#define READ 306
#define WRITE 307
#define STORED 308
#define DESIGNABLE 309
#define SCRIPTABLE 310
#define RESET 311
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef union YYSTYPE
{
/* Line 1676 of yacc.c */
#line 692 "moc.y"
char char_val;
int int_val;
double double_val;
@ -61,5 +169,17 @@ typedef union {
Function *function;
ArgList *arg_list;
Argument *arg;
/* Line 1676 of yacc.c */
#line 177 "moc_yacc.h"
} YYSTYPE;
# define YYSTYPE_IS_TRIVIAL 1
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
#endif
extern YYSTYPE yylval;

@ -74,7 +74,6 @@ typedef pthread_mutex_t Q_MUTEX_T;
#include <errno.h>
#include <string.h>
// Private class declarations
class QRealMutexPrivate : public QMutexPrivate {

@ -62,8 +62,12 @@
#include <pthread.h>
#endif
class QThread;
class QEventLoop;
class QThreadInstance {
public:
static void setCurrentThread(QThread *thread);
static QThreadInstance *current();
void init(unsigned int stackSize);
@ -95,6 +99,8 @@ public:
static unsigned int __stdcall start( void * );
static void finish( QThreadInstance * );
#endif // Q_OS_WIN32
QEventLoop* eventLoop;
};
#endif // QT_THREAD_SUPPORT

@ -39,6 +39,9 @@
**********************************************************************/
#include "qucom_p.h"
#include "qucomextra_p.h"
#include "qvariant.h"
// Standard types
@ -545,3 +548,24 @@ void QUType_QString::clear( QUObject *o )
delete (QString*)o->payload.ptr;
o->payload.ptr = 0;
}
QUObject* QUObject::deepCopy(QUObject* newLocation) {
QUObject* ret;
if (newLocation) {
ret = new(newLocation) QUObject(*this);
}
else {
ret = new QUObject(*this);
}
// Any type that has a clear() method must be copied here!
if (*(type->uuid()) == TID_QUType_charstar) {
static_QUType_charstar.set( ret, (const char *)static_QUType_charstar.get(this), true );
}
if (*(type->uuid()) == TID_QUType_QString) {
static_QUType_QString.set( ret, (QString)static_QUType_QString.get(this) );
}
if (*(type->uuid()) == TID_QUType_QVariant) {
static_QUType_QVariant.set( ret, (QVariant)static_QUType_QVariant.get(this) );
}
return ret;
}

@ -127,7 +127,7 @@ extern Q_EXPORT QUType_Null static_QUType_Null;
struct Q_EXPORT QUObject
{
public: // scary MSVC bug makes this necessary
QUObject() : type( &static_QUType_Null ) {}
QUObject() : type( &static_QUType_Null ), isLastObject(false) {}
~QUObject() { type->clear( this ); }
QUType *type;
@ -184,6 +184,8 @@ public: // scary MSVC bug makes this necessary
} payload;
QUObject* deepCopy(QUObject*);
bool isLastObject;
};

Loading…
Cancel
Save