Fix a number of threading data races

Add proper thread termination handler
This partially resolves Bug 1508
pull/2/head
Timothy Pearson 11 years ago
parent be8413249b
commit 4eba9b8238

@ -377,8 +377,13 @@ int QApplication::composedUnicode = 0;
#ifdef QT_THREAD_SUPPORT #ifdef QT_THREAD_SUPPORT
QMutex *QApplication::qt_mutex = 0; QMutex *QApplication::qt_mutex = 0;
static QMutex *postevent_mutex = 0; QMutex *qt_sharedStringMutex = 0;
static Qt::HANDLE qt_application_thread_id = 0; Q_EXPORT QMutex * qt_sharedMetaObjectMutex = 0;
#ifdef QT_USE_GLIBMAINLOOP
QMutex *qt_timerListMutex = 0;
#endif // QT_USE_GLIBMAINLOOP
static QMutex *postevent_mutex = 0;
static Qt::HANDLE qt_application_thread_id = 0;
Q_EXPORT Qt::HANDLE qt_get_application_thread_id() Q_EXPORT Qt::HANDLE qt_get_application_thread_id()
{ {
return qt_application_thread_id; return qt_application_thread_id;
@ -600,6 +605,10 @@ static QPostEventList *globalPostedEvents = 0; // list of posted events
uint qGlobalPostedEventsCount() uint qGlobalPostedEventsCount()
{ {
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( postevent_mutex );
#endif // QT_THREAD_SUPPORT
if (!globalPostedEvents) { if (!globalPostedEvents) {
return 0; return 0;
} }
@ -1015,6 +1024,11 @@ void QApplication::initialize( int argc, char **argv )
{ {
#ifdef QT_THREAD_SUPPORT #ifdef QT_THREAD_SUPPORT
qt_mutex = new QMutex( TRUE ); qt_mutex = new QMutex( TRUE );
qt_sharedStringMutex = new QMutex( TRUE );
qt_sharedMetaObjectMutex = new QMutex( TRUE );
#ifdef QT_USE_GLIBMAINLOOP
qt_timerListMutex = new QMutex( TRUE );
#endif // QT_USE_GLIBMAINLOOP
postevent_mutex = new QMutex( TRUE ); postevent_mutex = new QMutex( TRUE );
qt_application_thread_id = QThread::currentThread(); qt_application_thread_id = QThread::currentThread();
#endif // QT_THREAD_SUPPORT #endif // QT_THREAD_SUPPORT
@ -1184,6 +1198,17 @@ QApplication::~QApplication()
session_key = 0; session_key = 0;
#endif //QT_NO_SESSIONMANAGER #endif //QT_NO_SESSIONMANAGER
#ifdef QT_THREAD_SUPPORT
delete qt_sharedMetaObjectMutex;
qt_sharedMetaObjectMutex = 0;
delete qt_sharedStringMutex;
qt_sharedStringMutex = 0;
#ifdef QT_USE_GLIBMAINLOOP
delete qt_timerListMutex;
qt_timerListMutex = 0;
#endif // QT_USE_GLIBMAINLOOP
#endif // QT_THREAD_SUPPORT
qt_explicit_app_style = FALSE; qt_explicit_app_style = FALSE;
qt_app_has_font = FALSE; qt_app_has_font = FALSE;
app_tracking = 0; app_tracking = 0;
@ -2425,35 +2450,40 @@ bool QApplication::notify( QObject *receiver, QEvent *e )
return FALSE; return FALSE;
} }
if ( e->type() == QEvent::ChildRemoved && receiver->postedEvents && globalPostedEvents) { if ( receiver && (e->type() == QEvent::Destroy) ) {
return TRUE;
}
if ( e->type() == QEvent::ChildRemoved && receiver->postedEvents) {
#ifdef QT_THREAD_SUPPORT #ifdef QT_THREAD_SUPPORT
QMutexLocker locker( postevent_mutex ); QMutexLocker locker( postevent_mutex );
#endif // QT_THREAD_SUPPORT #endif // QT_THREAD_SUPPORT
// the QObject destructor calls QObject::removeChild, which calls if (globalPostedEvents) {
// QApplication::sendEvent() directly. this can happen while the event // the QObject destructor calls QObject::removeChild, which calls
// loop is in the middle of posting events, and when we get here, we may // QApplication::sendEvent() directly. this can happen while the event
// not have any more posted events for this object. // loop is in the middle of posting events, and when we get here, we may
if ( receiver->postedEvents ) { // not have any more posted events for this object.
// if this is a child remove event and the child insert if ( receiver->postedEvents ) {
// hasn't been dispatched yet, kill that insert // if this is a child remove event and the child insert
QPostEventList * l = receiver->postedEvents; // hasn't been dispatched yet, kill that insert
QObject * c = ((QChildEvent*)e)->child(); QPostEventList * l = receiver->postedEvents;
QPostEvent * pe; QObject * c = ((QChildEvent*)e)->child();
l->first(); QPostEvent * pe;
while( ( pe = l->current()) != 0 ) { l->first();
if ( pe->event && pe->receiver == receiver && while( ( pe = l->current()) != 0 ) {
pe->event->type() == QEvent::ChildInserted && if ( pe->event && pe->receiver == receiver &&
((QChildEvent*)pe->event)->child() == c ) { pe->event->type() == QEvent::ChildInserted &&
pe->event->posted = FALSE; ((QChildEvent*)pe->event)->child() == c ) {
delete pe->event; pe->event->posted = FALSE;
pe->event = 0; delete pe->event;
l->remove(); pe->event = 0;
continue; l->remove();
continue;
}
l->next();
}
} }
l->next();
}
} }
} }
@ -3545,8 +3575,9 @@ void QApplication::removePostedEvents( QObject *receiver )
void QApplication::removePostedEvents( QObject *receiver, int event_type ) void QApplication::removePostedEvents( QObject *receiver, int event_type )
{ {
if ( !receiver ) if ( !receiver ) {
return; return;
}
#ifdef QT_THREAD_SUPPORT #ifdef QT_THREAD_SUPPORT
QMutexLocker locker( postevent_mutex ); QMutexLocker locker( postevent_mutex );
@ -3556,8 +3587,9 @@ void QApplication::removePostedEvents( QObject *receiver, int event_type )
// happen while the event loop is in the middle of posting events, // happen while the event loop is in the middle of posting events,
// and when we get here, we may not have any more posted events // and when we get here, we may not have any more posted events
// for this object. // for this object.
if ( !receiver->postedEvents ) if ( !receiver->postedEvents ) {
return; return;
}
// iterate over the object-specifc list and delete the events. // iterate over the object-specifc list and delete the events.
// leave the QPostEvent objects; they'll be deleted by // leave the QPostEvent objects; they'll be deleted by
@ -3596,8 +3628,13 @@ void QApplication::removePostedEvents( QObject *receiver, int event_type )
void QApplication::removePostedEvent( QEvent * event ) void QApplication::removePostedEvent( QEvent * event )
{ {
if ( !event || !event->posted ) if ( !event || !event->posted ) {
return; return;
}
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( postevent_mutex );
#endif // QT_THREAD_SUPPORT
if ( !globalPostedEvents ) { if ( !globalPostedEvents ) {
#if defined(QT_DEBUG) #if defined(QT_DEBUG)
@ -3607,10 +3644,6 @@ void QApplication::removePostedEvent( QEvent * event )
#endif #endif
} }
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( postevent_mutex );
#endif // QT_THREAD_SUPPORT
QPostEventListIt it( *globalPostedEvents ); QPostEventListIt it( *globalPostedEvents );
QPostEvent * pe; QPostEvent * pe;
while( (pe = it.current()) != 0 ) { while( (pe = it.current()) != 0 ) {
@ -3696,6 +3729,51 @@ void QApplication::removePostedEvent( QEvent * event )
} }
} }
void qThreadTerminationHandlerRecursive( QObject* object, QThread* originThread, QThread* destinationThread ) {
#ifdef QT_THREAD_SUPPORT
QThread* objectThread = object->contextThreadObject();
if (objectThread != destinationThread) {
QThread::CleanupType cleanupType = objectThread->cleanupType();
if (cleanupType == QThread::CleanupMergeObjects) {
object->moveToThread(destinationThread);
}
else if (cleanupType == QThread::CleanupNone) {
// Do nothing
#if defined(QT_DEBUG)
qDebug( "QApplication::threadTerminationHandler: object %p still owned by thread %p at thread termination!", object, objectThread);
#endif // QT_DEBUG
}
else {
// Do nothing
#if defined(QT_DEBUG)
qDebug( "QApplication::threadTerminationHandler: invalid thread termination cleanup type %d specified", cleanupType);
#endif // QT_DEBUG
}
}
QObjectList children = object->childrenListObject();
QObject *childObject;
for ( childObject = children.first(); childObject; childObject = children.next() ) {
qThreadTerminationHandlerRecursive(childObject, originThread, destinationThread);
}
#endif // QT_THREAD_SUPPORT
}
/*!\internal
Migrates all objects from the specified thread in preparation
for thread destruction.
*/
void QApplication::threadTerminationHandler( QThread *originThread ) {
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( qt_mutex );
QThread* destinationThread = guiThread();
const QObjectList* objects = QObject::objectTrees();
for ( QObjectListIt objectit( *objects ) ; *objectit; ++objectit ) {
qThreadTerminationHandlerRecursive((*objectit), originThread, destinationThread);
}
#endif // QT_THREAD_SUPPORT
}
/*!\internal /*!\internal
Sets the active window in reaction to a system event. Call this Sets the active window in reaction to a system event. Call this

@ -352,11 +352,12 @@ private slots:
void postIMEvent( QObject *receiver, QIMEvent *event ); void postIMEvent( QObject *receiver, QIMEvent *event );
#endif #endif
private: public:
#ifdef QT_THREAD_SUPPORT #ifdef QT_THREAD_SUPPORT
static QMutex *qt_mutex; static QMutex *qt_mutex;
#endif // QT_THREAD_SUPPORT #endif // QT_THREAD_SUPPORT
private:
int app_argc; int app_argc;
char **app_argv; char **app_argv;
bool quit_now; bool quit_now;
@ -434,6 +435,7 @@ private:
friend class QDialog; friend class QDialog;
friend class QAccelManager; friend class QAccelManager;
friend class QEvent; friend class QEvent;
friend class QThread;
friend class QTranslator; friend class QTranslator;
friend class QEventLoop; friend class QEventLoop;
friend Q_EXPORT void qt_ucm_initialize( QApplication * ); friend Q_EXPORT void qt_ucm_initialize( QApplication * );
@ -457,6 +459,7 @@ public:
static QThread* guiThread(); static QThread* guiThread();
#endif #endif
static bool isGuiThread(); static bool isGuiThread();
static void threadTerminationHandler( QThread * );
}; };
inline int QApplication::argc() const inline int QApplication::argc() const

@ -55,6 +55,12 @@
#include <glib.h> #include <glib.h>
#ifdef QT_THREAD_SUPPORT
#ifdef QT_USE_GLIBMAINLOOP
extern QMutex *qt_timerListMutex;
#endif // QT_USE_GLIBMAINLOOP
#endif // QT_THREAD_SUPPORT
/***************************************************************************** /*****************************************************************************
Timer handling; UNIX has no application timer support so we'll have to Timer handling; UNIX has no application timer support so we'll have to
make our own from scratch. make our own from scratch.
@ -102,9 +108,6 @@ typedef QPtrList<TimerInfo> TimerList; // list of TimerInfo structs
static QBitArray *timerBitVec; // timer bit vector static QBitArray *timerBitVec; // timer bit vector
static TimerList *timerList = 0; // timer list static TimerList *timerList = 0; // timer list
#if defined(QT_THREAD_SUPPORT)
static QMutex *timerListMutex = 0; // timer list mutex
#endif
static void initTimers(); static void initTimers();
void cleanupTimers(); void cleanupTimers();
@ -184,7 +187,7 @@ static int allocTimerId() // find avail timer identifier
static void insertTimer( const TimerInfo *ti ) // insert timer info into list static void insertTimer( const TimerInfo *ti ) // insert timer info into list
{ {
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->lock(); qt_timerListMutex->lock();
#endif #endif
TimerInfo *t = timerList->first(); TimerInfo *t = timerList->first();
int index = 0; int index = 0;
@ -207,7 +210,7 @@ static void insertTimer( const TimerInfo *ti ) // insert timer info into list
} }
#endif #endif
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->unlock(); qt_timerListMutex->unlock();
#endif #endif
} }
@ -233,7 +236,7 @@ static inline void getTime( timeval &t ) // get time of day
static void repairTimer( const timeval &time ) // repair broken timer static void repairTimer( const timeval &time ) // repair broken timer
{ {
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->lock(); qt_timerListMutex->lock();
#endif #endif
timeval diff = watchtime - time; timeval diff = watchtime - time;
register TimerInfo *t = timerList->first(); register TimerInfo *t = timerList->first();
@ -242,7 +245,7 @@ static void repairTimer( const timeval &time ) // repair broken timer
t = timerList->next(); t = timerList->next();
} }
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->unlock(); qt_timerListMutex->unlock();
#endif #endif
} }
@ -260,7 +263,7 @@ static void repairTimer( const timeval &time ) // repair broken timer
timeval *qt_wait_timer() timeval *qt_wait_timer()
{ {
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
if (timerListMutex) timerListMutex->lock(); qt_timerListMutex->lock();
#endif #endif
static timeval tm; static timeval tm;
bool first = TRUE; bool first = TRUE;
@ -286,19 +289,19 @@ timeval *qt_wait_timer()
tm = *qt_wait_timer_max; tm = *qt_wait_timer_max;
} }
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
if (timerListMutex) timerListMutex->unlock(); qt_timerListMutex->unlock();
#endif #endif
return &tm; return &tm;
} }
if ( qt_wait_timer_max ) { if ( qt_wait_timer_max ) {
tm = *qt_wait_timer_max; tm = *qt_wait_timer_max;
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
if (timerListMutex) timerListMutex->unlock(); qt_timerListMutex->unlock();
#endif #endif
return &tm; return &tm;
} }
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
if (timerListMutex) timerListMutex->unlock(); qt_timerListMutex->unlock();
#endif #endif
return 0; // no timers return 0; // no timers
} }
@ -314,7 +317,7 @@ static void initTimers() // initialize timers
} }
timerList = new TimerList; timerList = new TimerList;
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex = new QMutex(true); qt_timerListMutex = new QMutex(true);
#endif #endif
Q_CHECK_PTR( timerList ); Q_CHECK_PTR( timerList );
timerList->setAutoDelete( TRUE ); timerList->setAutoDelete( TRUE );
@ -328,20 +331,25 @@ void cleanupTimers()
timerList = 0; timerList = 0;
delete timerBitVec; delete timerBitVec;
timerBitVec = 0; timerBitVec = 0;
#if defined(QT_THREAD_SUPPORT)
delete timerListMutex;
timerListMutex = 0;
#endif
} }
// Main timer functions for starting and killing timers // Main timer functions for starting and killing timers
int qStartTimer( int interval, QObject *obj ) int qStartTimer( int interval, QObject *obj )
{ {
#if defined(QT_THREAD_SUPPORT)
if (qt_timerListMutex) qt_timerListMutex->lock();
#endif
if ( !timerList ) { // initialize timer data if ( !timerList ) { // initialize timer data
initTimers(); initTimers();
#if defined(QT_THREAD_SUPPORT)
if (qt_timerListMutex) qt_timerListMutex->lock();
#endif
} }
int id = allocTimerId(); // get free timer id int id = allocTimerId(); // get free timer id
if ( (id <= 0) || (id > (int)timerBitVec->size()) || (!obj) ) { // cannot create timer if ( (id <= 0) || (id > (int)timerBitVec->size()) || (!obj) ) { // cannot create timer
#if defined(QT_THREAD_SUPPORT)
if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif
return 0; return 0;
} }
timerBitVec->setBit( id-1 ); // set timer active timerBitVec->setBit( id-1 ); // set timer active
@ -355,18 +363,24 @@ int qStartTimer( int interval, QObject *obj )
t->timeout = currentTime + t->interval; t->timeout = currentTime + t->interval;
t->obj = obj; t->obj = obj;
insertTimer( t ); // put timer in list insertTimer( t ); // put timer in list
#if defined(QT_THREAD_SUPPORT)
if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif
return id; return id;
} }
bool qKillTimer( int id ) bool qKillTimer( int id )
{ {
#if defined(QT_THREAD_SUPPORT)
if (qt_timerListMutex) qt_timerListMutex->lock();
#endif
register TimerInfo *t; register TimerInfo *t;
if ( (!timerList) || (id <= 0) || (id > (int)timerBitVec->size()) || (!timerBitVec->testBit( id-1 )) ) { if ( (!timerList) || (id <= 0) || (id > (int)timerBitVec->size()) || (!timerBitVec->testBit( id-1 )) ) {
return FALSE; // not init'd or invalid timer
}
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->lock(); if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif #endif
return FALSE; // not init'd or invalid timer
}
t = timerList->first(); t = timerList->first();
while ( t && t->id != id ) { // find timer info in list while ( t && t->id != id ) { // find timer info in list
t = timerList->next(); t = timerList->next();
@ -376,13 +390,13 @@ bool qKillTimer( int id )
timerBitVec->clearBit( id-1 ); // set timer inactive timerBitVec->clearBit( id-1 ); // set timer inactive
ret = timerList->remove(); ret = timerList->remove();
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->unlock(); if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif #endif
return ret; return ret;
} }
else { // id not found else { // id not found
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->unlock(); if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif #endif
return FALSE; return FALSE;
} }
@ -390,13 +404,16 @@ bool qKillTimer( int id )
bool qKillTimer( QObject *obj ) bool qKillTimer( QObject *obj )
{ {
#if defined(QT_THREAD_SUPPORT)
if (qt_timerListMutex) qt_timerListMutex->lock();
#endif
register TimerInfo *t; register TimerInfo *t;
if ( !timerList ) { // not initialized if ( !timerList ) { // not initialized
return FALSE;
}
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->lock(); if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif #endif
return FALSE;
}
t = timerList->first(); t = timerList->first();
while ( t ) { // check all timers while ( t ) { // check all timers
if ( t->obj == obj ) { // object found if ( t->obj == obj ) { // object found
@ -409,7 +426,7 @@ bool qKillTimer( QObject *obj )
} }
} }
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->unlock(); if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif #endif
return TRUE; return TRUE;
} }
@ -615,12 +632,15 @@ int QEventLoop::timeToWait() const
int QEventLoop::activateTimers() int QEventLoop::activateTimers()
{ {
#if defined(QT_THREAD_SUPPORT)
if (qt_timerListMutex) qt_timerListMutex->lock();
#endif
if ( !timerList || !timerList->count() ) { // no timers if ( !timerList || !timerList->count() ) { // no timers
return 0;
}
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->lock(); if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif #endif
return 0;
}
bool first = TRUE; bool first = TRUE;
timeval currentTime; timeval currentTime;
int n_act = 0, maxCount = timerList->count(); int n_act = 0, maxCount = timerList->count();
@ -663,7 +683,7 @@ int QEventLoop::activateTimers()
n_act++; n_act++;
} }
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->unlock(); if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif #endif
QTimerEvent e( t->id ); QTimerEvent e( t->id );
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
@ -678,14 +698,14 @@ int QEventLoop::activateTimers()
QApplication::sendEvent( t->obj, &e ); // send event QApplication::sendEvent( t->obj, &e ); // send event
#endif // defined(QT_THREAD_SUPPORT) #endif // defined(QT_THREAD_SUPPORT)
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->lock(); if (qt_timerListMutex) qt_timerListMutex->lock();
#endif #endif
if ( timerList->findRef( begin ) == -1 ) { if ( timerList->findRef( begin ) == -1 ) {
begin = 0; begin = 0;
} }
} }
#if defined(QT_THREAD_SUPPORT) #if defined(QT_THREAD_SUPPORT)
timerListMutex->unlock(); if (qt_timerListMutex) qt_timerListMutex->unlock();
#endif #endif
return n_act; return n_act;
} }

@ -629,6 +629,10 @@ bool QEventLoop::gsourceDispatch(GSource *gs) {
bool QEventLoop::hasPendingEvents() const bool QEventLoop::hasPendingEvents() const
{ {
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( QApplication::qt_mutex );
#endif // QT_THREAD_SUPPORT
extern uint qGlobalPostedEventsCount(); // from qapplication.cpp extern uint qGlobalPostedEventsCount(); // from qapplication.cpp
return ( qGlobalPostedEventsCount() || ( (qt_is_gui_used && QApplication::isGuiThread()) ? XPending( QPaintDevice::x11AppDisplay() ) : 0)); return ( qGlobalPostedEventsCount() || ( (qt_is_gui_used && QApplication::isGuiThread()) ? XPending( QPaintDevice::x11AppDisplay() ) : 0));
} }

@ -73,6 +73,8 @@ public:
} }
#endif #endif
QThread* ownThread; QThread* ownThread;
QMutex* senderObjectListMutex;
QMutex* childObjectListMutex;
bool disableThreadPostedEvents; bool disableThreadPostedEvents;
}; };
@ -83,6 +85,10 @@ void QObject::moveToThread_helper(QThread *targetThread)
QEvent e(QEvent::ThreadChange); QEvent e(QEvent::ThreadChange);
QApplication::sendEvent(this, &e); QApplication::sendEvent(this, &e);
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( d->childObjectListMutex );
#endif // QT_THREAD_SUPPORT
if (childObjects) { if (childObjects) {
QObject *child; QObject *child;
QObjectListIt it(*childObjects); QObjectListIt it(*childObjects);
@ -97,12 +103,16 @@ void QObject::setThreadObject_helper(QThread *targetThread)
{ {
d->ownThread = targetThread; d->ownThread = targetThread;
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( d->childObjectListMutex );
#endif // QT_THREAD_SUPPORT
if (childObjects) { if (childObjects) {
QObject *child; QObject *child;
QObjectListIt it(*childObjects); QObjectListIt it(*childObjects);
while ( (child=it.current()) ) { while ( (child=it.current()) ) {
++it; ++it;
child->moveToThread_helper(targetThread); child->setThreadObject_helper(targetThread);
} }
} }
} }
@ -123,7 +133,9 @@ void QObject::setThreadObject_helper(QThread *targetThread)
*/ */
void QObject::moveToThread(QThread *targetThread) void QObject::moveToThread(QThread *targetThread)
{ {
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( QApplication::qt_mutex ); QMutexLocker locker( QApplication::qt_mutex );
#endif // QT_THREAD_SUPPORT
if (parentObj) { if (parentObj) {
#if defined(QT_DEBUG) #if defined(QT_DEBUG)
@ -179,11 +191,23 @@ void QObject::disableThreadPostedEvents(bool disable) {
class QSenderObjectList : public QObjectList, public QShared class QSenderObjectList : public QObjectList, public QShared
{ {
public: public:
QSenderObjectList() : currentSender( 0 ) { } QSenderObjectList();
QObject *currentSender; ~QSenderObjectList();
public:
QObject *currentSender;
QMutex *listMutex;
}; };
QSenderObjectList::QSenderObjectList() : currentSender( 0 ) {
listMutex = new QMutex( TRUE );
}
QSenderObjectList::~QSenderObjectList() {
delete listMutex;
}
class Q_EXPORT QMetaCallEvent : public QEvent class Q_EXPORT QMetaCallEvent : public QEvent
{ {
public: public:
@ -369,8 +393,9 @@ bool qKillTimer( QObject *obj );
static void removeObjFromList( QObjectList *objList, const QObject *obj, static void removeObjFromList( QObjectList *objList, const QObject *obj,
bool single=FALSE ) bool single=FALSE )
{ {
if ( !objList ) if ( !objList ) {
return; return;
}
int index = objList->findRef( obj ); int index = objList->findRef( obj );
while ( index >= 0 ) { while ( index >= 0 ) {
objList->remove(); objList->remove();
@ -585,20 +610,25 @@ QObject::QObject( QObject *parent, const char *name )
postedEvents( 0 ), // no events posted postedEvents( 0 ), // no events posted
d( 0 ) d( 0 )
{ {
if ( !metaObj ) // will create object dict if ( !d ) {
d = new QObjectPrivate(0);
}
d->ownThread = QThread::currentThreadObject();
d->senderObjectListMutex = new QMutex( TRUE );
d->childObjectListMutex = new QMutex( TRUE );
if ( !metaObj ) { // will create object dict
(void) staticMetaObject(); (void) staticMetaObject();
}
if ( parent ) { // add object to parent if ( parent ) { // add object to parent
parent->insertChild( this ); parent->insertChild( this );
} else { }
else {
insert_tree( this ); insert_tree( this );
isTree = TRUE; isTree = TRUE;
} }
if ( !d )
d = new QObjectPrivate(0);
d->ownThread = QThread::currentThreadObject();
} }
@ -630,10 +660,15 @@ QObject::~QObject()
#endif #endif
return; return;
} }
if (qApp) {
QEvent destroyEvent(QEvent::Destroy);
qApp->notify(this, &destroyEvent);
}
wasDeleted = 1; wasDeleted = 1;
blockSig = 0; // unblock signals to keep QGuardedPtr happy blockSig = 0; // unblock signals to keep QGuardedPtr happy
emit destroyed( this ); emit destroyed( this );
emit destroyed(); emit destroyed();
if ( objname ) { if ( objname ) {
delete [] (char*)objname; delete [] (char*)objname;
} }
@ -669,8 +704,9 @@ QObject::~QObject()
QConnectionListIt cit(*clist); QConnectionListIt cit(*clist);
while( (c=cit.current()) ) { // for each connected slot... while( (c=cit.current()) ) { // for each connected slot...
++cit; ++cit;
if ( (obj=c->object()) ) if ( (obj=c->object()) ) {
removeObjFromList( obj->senderObjects, this ); removeObjFromList( obj->senderObjects, this );
}
} }
} }
delete connections; delete connections;
@ -691,6 +727,11 @@ QObject::~QObject()
delete childObjects; delete childObjects;
} }
#ifdef QT_THREAD_SUPPORT
delete d->childObjectListMutex;
delete d->senderObjectListMutex;
#endif // QT_THREAD_SUPPORT
delete d; delete d;
} }
@ -985,11 +1026,17 @@ bool QObject::event( QEvent *e )
QSenderObjectList* sol; QSenderObjectList* sol;
QObject* oldSender = 0; QObject* oldSender = 0;
sol = senderObjects; sol = senderObjects;
#ifdef QT_THREAD_SUPPORT
sol->listMutex->lock();
#endif // QT_THREAD_SUPPORT
if ( sol ) { if ( sol ) {
oldSender = sol->currentSender; oldSender = sol->currentSender;
sol->ref(); sol->ref();
sol->currentSender = metaEvent->sender(); sol->currentSender = metaEvent->sender();
} }
#ifdef QT_THREAD_SUPPORT
sol->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
QUObject *o = metaEvent->data(); QUObject *o = metaEvent->data();
if (metaEvent->type() == QMetaCallEvent::MetaCallEmit) { if (metaEvent->type() == QMetaCallEvent::MetaCallEmit) {
qt_emit( metaEvent->id(), o ); qt_emit( metaEvent->id(), o );
@ -997,12 +1044,20 @@ bool QObject::event( QEvent *e )
if (metaEvent->type() == QMetaCallEvent::MetaCallInvoke) { if (metaEvent->type() == QMetaCallEvent::MetaCallInvoke) {
qt_invoke( metaEvent->id(), o ); qt_invoke( metaEvent->id(), o );
} }
#ifdef QT_THREAD_SUPPORT
sol->listMutex->lock();
#endif // QT_THREAD_SUPPORT
if (sol ) { if (sol ) {
sol->currentSender = oldSender; sol->currentSender = oldSender;
if ( sol->deref() ) { if ( sol->deref() ) {
sol->listMutex->unlock();
delete sol; delete sol;
sol = NULL;
} }
} }
#ifdef QT_THREAD_SUPPORT
if (sol) sol->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
} }
else { else {
qWarning("QObject: Ignoring metacall event from non-owning thread"); qWarning("QObject: Ignoring metacall event from non-owning thread");
@ -1509,6 +1564,10 @@ QConnectionList *QObject::receivers( int signal ) const
void QObject::insertChild( QObject *obj ) void QObject::insertChild( QObject *obj )
{ {
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( d->childObjectListMutex );
#endif // QT_THREAD_SUPPORT
if ( obj->isTree ) { if ( obj->isTree ) {
remove_tree( obj ); remove_tree( obj );
obj->isTree = FALSE; obj->isTree = FALSE;
@ -1551,6 +1610,10 @@ void QObject::insertChild( QObject *obj )
void QObject::removeChild( QObject *obj ) void QObject::removeChild( QObject *obj )
{ {
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( d->childObjectListMutex );
#endif // QT_THREAD_SUPPORT
if ( childObjects && childObjects->removeRef(obj) ) { if ( childObjects && childObjects->removeRef(obj) ) {
obj->parentObj = 0; obj->parentObj = 0;
if ( !obj->wasDeleted ) { if ( !obj->wasDeleted ) {
@ -2135,9 +2198,25 @@ void QObject::connectInternal( const QObject *sender, int signal_index, const QO
QConnection *c = new QConnection( r, member_index, rm ? rm->name : "qt_invoke", membcode ); QConnection *c = new QConnection( r, member_index, rm ? rm->name : "qt_invoke", membcode );
Q_CHECK_PTR( c ); Q_CHECK_PTR( c );
clist->append( c ); clist->append( c );
if ( !r->senderObjects ) // create list of senders if ( !r->senderObjects ) { // create list of senders
#ifdef QT_THREAD_SUPPORT
r->d->senderObjectListMutex->lock();
#endif // QT_THREAD_SUPPORT
r->senderObjects = new QSenderObjectList; r->senderObjects = new QSenderObjectList;
#ifdef QT_THREAD_SUPPORT
r->senderObjects->listMutex->lock();
r->d->senderObjectListMutex->unlock();
#endif // QT_THREAD_SUPPORT
}
else {
#ifdef QT_THREAD_SUPPORT
r->senderObjects->listMutex->lock();
#endif // QT_THREAD_SUPPORT
}
r->senderObjects->append( s ); // add sender to list r->senderObjects->append( s ); // add sender to list
#ifdef QT_THREAD_SUPPORT
r->senderObjects->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
} }
@ -2343,13 +2422,25 @@ bool QObject::disconnectInternal( const QObject *sender, int signal_index,
c = clist->first(); c = clist->first();
while ( c ) { // for all receivers... while ( c ) { // for all receivers...
if ( r == 0 ) { // remove all receivers if ( r == 0 ) { // remove all receivers
#ifdef QT_THREAD_SUPPORT
if (c->object()->senderObjects) c->object()->senderObjects->listMutex->lock();
#endif // QT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s ); removeObjFromList( c->object()->senderObjects, s );
#ifdef QT_THREAD_SUPPORT
if (c->object()->senderObjects) c->object()->senderObjects->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
success = TRUE; success = TRUE;
c = clist->next(); c = clist->next();
} else if ( r == c->object() && } else if ( r == c->object() &&
( (member_index == -1) || ( (member_index == -1) ||
((member_index == c->member()) && (c->memberType() == membcode)) ) ) { ((member_index == c->member()) && (c->memberType() == membcode)) ) ) {
#ifdef QT_THREAD_SUPPORT
if (c->object()->senderObjects) c->object()->senderObjects->listMutex->lock();
#endif // QT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s, TRUE ); removeObjFromList( c->object()->senderObjects, s, TRUE );
#ifdef QT_THREAD_SUPPORT
if (c->object()->senderObjects) c->object()->senderObjects->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
success = TRUE; success = TRUE;
clist->remove(); clist->remove();
c = clist->current(); c = clist->current();
@ -2368,13 +2459,25 @@ bool QObject::disconnectInternal( const QObject *sender, int signal_index,
c = clist->first(); c = clist->first();
while ( c ) { // for all receivers... while ( c ) { // for all receivers...
if ( r == 0 ) { // remove all receivers if ( r == 0 ) { // remove all receivers
#ifdef QT_THREAD_SUPPORT
if (c->object()->senderObjects) c->object()->senderObjects->listMutex->lock();
#endif // QT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s, TRUE ); removeObjFromList( c->object()->senderObjects, s, TRUE );
#ifdef QT_THREAD_SUPPORT
if (c->object()->senderObjects) c->object()->senderObjects->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
success = TRUE; success = TRUE;
c = clist->next(); c = clist->next();
} else if ( r == c->object() && } else if ( r == c->object() &&
( (member_index == -1) || ( (member_index == -1) ||
((member_index == c->member()) && (c->memberType() == membcode)) ) ) { ((member_index == c->member()) && (c->memberType() == membcode)) ) ) {
#ifdef QT_THREAD_SUPPORT
if (c->object()->senderObjects) c->object()->senderObjects->listMutex->lock();
#endif // QT_THREAD_SUPPORT
removeObjFromList( c->object()->senderObjects, s, TRUE ); removeObjFromList( c->object()->senderObjects, s, TRUE );
#ifdef QT_THREAD_SUPPORT
if (c->object()->senderObjects) c->object()->senderObjects->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
success = TRUE; success = TRUE;
clist->remove(); clist->remove();
c = clist->current(); c = clist->current();
@ -2382,8 +2485,9 @@ bool QObject::disconnectInternal( const QObject *sender, int signal_index,
c = clist->next(); c = clist->next();
} }
} }
if ( r == 0 ) // disconnect all receivers if ( r == 0 ) { // disconnect all receivers
s->connections->insert( signal_index, 0 ); s->connections->insert( signal_index, 0 );
}
} }
return success; return success;
} }
@ -2578,11 +2682,13 @@ void QObject::activate_signal( int signal )
} }
#endif #endif
if ( !connections || signalsBlocked() || signal < 0 ) if ( !connections || signalsBlocked() || signal < 0 ) {
return; return;
}
QConnectionList *clist = connections->at( signal ); QConnectionList *clist = connections->at( signal );
if ( !clist ) if ( !clist ) {
return; return;
}
QUObject o[1]; QUObject o[1];
o[0].isLastObject = true; o[0].isLastObject = true;
activate_signal( clist, o ); activate_signal( clist, o );
@ -2592,12 +2698,14 @@ void QObject::activate_signal( int signal )
void QObject::activate_signal( QConnectionList *clist, QUObject *o ) void QObject::activate_signal( QConnectionList *clist, QUObject *o )
{ {
if ( !clist ) if ( !clist ) {
return; return;
}
#ifndef QT_NO_PRELIMINARY_SIGNAL_SPY #ifndef QT_NO_PRELIMINARY_SIGNAL_SPY
if ( qt_preliminary_signal_spy ) if ( qt_preliminary_signal_spy ) {
qt_spy_signal( this, connections->findRef( clist), o ); qt_spy_signal( this, connections->findRef( clist), o );
}
#endif #endif
const QThread *currentThread = QThread::currentThreadObject(); const QThread *currentThread = QThread::currentThreadObject();
@ -2610,6 +2718,9 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
c = clist->first(); c = clist->first();
object = c->object(); object = c->object();
sol = object->senderObjects; sol = object->senderObjects;
#ifdef QT_THREAD_SUPPORT
sol->listMutex->lock();
#endif // QT_THREAD_SUPPORT
if ( sol ) { if ( sol ) {
oldSender = sol->currentSender; oldSender = sol->currentSender;
sol->ref(); sol->ref();
@ -2617,7 +2728,13 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
} }
if ( c->memberType() == QSIGNAL_CODE ) { if ( c->memberType() == QSIGNAL_CODE ) {
if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) { if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) {
#ifdef QT_THREAD_SUPPORT
sol->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
object->qt_emit( c->member(), o ); object->qt_emit( c->member(), o );
#ifdef QT_THREAD_SUPPORT
sol->listMutex->lock();
#endif // QT_THREAD_SUPPORT
} }
else { else {
if (object->d->ownThread && !object->d->ownThread->finished()) { if (object->d->ownThread && !object->d->ownThread->finished()) {
@ -2627,7 +2744,13 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
} }
else { else {
if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) { if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) {
#ifdef QT_THREAD_SUPPORT
sol->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
object->qt_invoke( c->member(), o ); object->qt_invoke( c->member(), o );
#ifdef QT_THREAD_SUPPORT
sol->listMutex->lock();
#endif // QT_THREAD_SUPPORT
} }
else { else {
if (object->d->ownThread && !object->d->ownThread->finished()) { if (object->d->ownThread && !object->d->ownThread->finished()) {
@ -2637,9 +2760,15 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
} }
if ( sol ) { if ( sol ) {
sol->currentSender = oldSender; sol->currentSender = oldSender;
if ( sol->deref() ) if ( sol->deref() ) {
sol->listMutex->unlock();
delete sol; delete sol;
sol = NULL;
}
} }
#ifdef QT_THREAD_SUPPORT
if (sol) sol->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
} else { } else {
QConnection *cd = 0; QConnection *cd = 0;
QConnectionListIt it(*clist); QConnectionListIt it(*clist);
@ -2650,6 +2779,9 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
cd = c; cd = c;
object = c->object(); object = c->object();
sol = object->senderObjects; sol = object->senderObjects;
#ifdef QT_THREAD_SUPPORT
sol->listMutex->lock();
#endif // QT_THREAD_SUPPORT
if ( sol ) { if ( sol ) {
oldSender = sol->currentSender; oldSender = sol->currentSender;
sol->ref(); sol->ref();
@ -2657,7 +2789,13 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
} }
if ( c->memberType() == QSIGNAL_CODE ) { if ( c->memberType() == QSIGNAL_CODE ) {
if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) { if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) {
#ifdef QT_THREAD_SUPPORT
sol->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
object->qt_emit( c->member(), o ); object->qt_emit( c->member(), o );
#ifdef QT_THREAD_SUPPORT
sol->listMutex->lock();
#endif // QT_THREAD_SUPPORT
} }
else { else {
if (object->d->ownThread && !object->d->ownThread->finished()) { if (object->d->ownThread && !object->d->ownThread->finished()) {
@ -2667,7 +2805,13 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
} }
else { else {
if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) { if ((d->disableThreadPostedEvents) || (object->d->ownThread == currentThread)) {
#ifdef QT_THREAD_SUPPORT
sol->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
object->qt_invoke( c->member(), o ); object->qt_invoke( c->member(), o );
#ifdef QT_THREAD_SUPPORT
sol->listMutex->lock();
#endif // QT_THREAD_SUPPORT
} }
else { else {
if (object->d->ownThread && !object->d->ownThread->finished()) { if (object->d->ownThread && !object->d->ownThread->finished()) {
@ -2677,9 +2821,15 @@ void QObject::activate_signal( QConnectionList *clist, QUObject *o )
} }
if (sol ) { if (sol ) {
sol->currentSender = oldSender; sol->currentSender = oldSender;
if ( sol->deref() ) if ( sol->deref() ) {
sol->listMutex->unlock();
delete sol; delete sol;
sol = NULL;
}
} }
#ifdef QT_THREAD_SUPPORT
if (sol) sol->listMutex->unlock();
#endif // QT_THREAD_SUPPORT
} }
} }
} }
@ -2818,6 +2968,10 @@ void QObject::dumpObjectTree()
void QObject::dumpObjectInfo() void QObject::dumpObjectInfo()
{ {
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( d->senderObjectListMutex );
#endif // QT_THREAD_SUPPORT
#if defined(QT_DEBUG) #if defined(QT_DEBUG)
qDebug( "OBJECT %s::%s", className(), name( "unnamed" ) ); qDebug( "OBJECT %s::%s", className(), name( "unnamed" ) );
int n = 0; int n = 0;
@ -2852,8 +3006,9 @@ void QObject::dumpObjectInfo()
sender = senderObjects->next(); sender = senderObjects->next();
} }
} }
if ( n == 0 ) if ( n == 0 ) {
qDebug( "\t<None>" ); qDebug( "\t<None>" );
}
#endif #endif
} }

@ -46,6 +46,7 @@
#include "qwindowdefs.h" #include "qwindowdefs.h"
#include "qstring.h" #include "qstring.h"
#include "qevent.h" #include "qevent.h"
#include "qmutex.h"
#include "qnamespace.h" #include "qnamespace.h"
#endif // QT_H #endif // QT_H

@ -157,6 +157,7 @@ class QMetaObject;
class QSignal; class QSignal;
class QConnection; class QConnection;
class QEvent; class QEvent;
class QMutex;
struct QMetaData; struct QMetaData;
class QConnectionList; class QConnectionList;
class QConnectionListIt; class QConnectionListIt;
@ -165,6 +166,8 @@ class QObjectList;
class QObjectListIt; class QObjectListIt;
class QMemberDict; class QMemberDict;
extern QMutex *qt_sharedMetaObjectMutex;
Q_EXPORT void *qt_find_obj_child( QObject *, const char *, const char * ); Q_EXPORT void *qt_find_obj_child( QObject *, const char *, const char * );
#define Q_CHILD(parent,type,name) \ #define Q_CHILD(parent,type,name) \
((type*)qt_find_obj_child(parent,#type,name)) ((type*)qt_find_obj_child(parent,#type,name))

@ -62,6 +62,194 @@ public:
} }
}; };
QStyleOption::QStyleOption(StyleOptionDefault) :
def(TRUE),
tb(NULL),
i1(-1),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(int in1) :
def(FALSE),
tb(NULL),
i1(in1),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(int in1, int in2) :
def(FALSE),
tb(NULL),
i1(in1),
i2(in2),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(int in1, int in2, int in3, int in4) :
def(FALSE),
tb(NULL),
i1(in1),
i2(in2),
i3(in3),
i4(in4),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(QMenuItem* m) :
def(FALSE),
mi(m),
tb(NULL),
i1(-1),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(QMenuItem* m, int in1) :
def(FALSE),
mi(m),
tb(NULL),
i1(in1),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(QMenuItem* m, int in1, int in2) :
def(FALSE),
mi(m),
tb(NULL),
i1(in1),
i2(in2),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(const QColor& c) :
def(FALSE),
tb(NULL),
cl(&c),
i1(-1),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(QTab* t) :
def(FALSE),
tb(t),
i1(-1),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(QListViewItem* i) :
def(FALSE),
tb(NULL),
li(i),
i1(-1),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(QCheckListItem* i) :
def(FALSE),
tb(NULL),
i1(-1),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(i),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(Qt::ArrowType a) :
def(FALSE),
tb(NULL),
i1((int)a),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(const QRect& r) :
def(FALSE),
tb(NULL),
i1(r.x()),
i2(r.y()),
i3(r.width()),
i4(r.height()),
i5(-1),
cli(NULL),
tbh(NULL) {
//
}
QStyleOption::QStyleOption(QWidget *w) :
def(FALSE),
tb(NULL),
i1(-1),
i2(-1),
i3(-1),
i4(-1),
i5(-1),
cli(NULL),
p1((void*)w),
tbh(NULL) {
//
}
/*! /*!
\class QStyleOption qstyle.h \class QStyleOption qstyle.h
\brief The QStyleOption class specifies optional parameters for QStyle functions. \brief The QStyleOption class specifies optional parameters for QStyle functions.

@ -59,30 +59,24 @@ class QTab;
class QListViewItem; class QListViewItem;
class QCheckListItem; class QCheckListItem;
class QStyleOption { class Q_EXPORT QStyleOption {
public: public:
enum StyleOptionDefault { Default }; enum StyleOptionDefault { Default };
QStyleOption(StyleOptionDefault=Default) : def(TRUE), tb(NULL), cli(NULL), tbh(NULL) {} QStyleOption(StyleOptionDefault=Default);
QStyleOption(int in1);
// Note: we don't use default arguments since that is unnecessary QStyleOption(int in1, int in2);
// initialization. QStyleOption(int in1, int in2, int in3, int in4);
QStyleOption(int in1) : QStyleOption(QMenuItem* m);
def(FALSE), tb(NULL), i1(in1), cli(NULL), tbh(NULL) {} QStyleOption(QMenuItem* m, int in1);
QStyleOption(int in1, int in2) : QStyleOption(QMenuItem* m, int in1, int in2);
def(FALSE), tb(NULL), i1(in1), i2(in2), cli(NULL), tbh(NULL) {} QStyleOption(const QColor& c);
QStyleOption(int in1, int in2, int in3, int in4) : QStyleOption(QTab* t);
def(FALSE), tb(NULL), i1(in1), i2(in2), i3(in3), i4(in4), cli(NULL), tbh(NULL) {} QStyleOption(QListViewItem* i);
QStyleOption(QMenuItem* m) : def(FALSE), mi(m), tb(NULL), cli(NULL), tbh(NULL) {} QStyleOption(QCheckListItem* i);
QStyleOption(QMenuItem* m, int in1) : def(FALSE), mi(m), tb(NULL), i1(in1), cli(NULL), tbh(NULL) {} QStyleOption(Qt::ArrowType a);
QStyleOption(QMenuItem* m, int in1, int in2) : def(FALSE), mi(m), tb(NULL), i1(in1), i2(in2), cli(NULL), tbh(NULL) {} QStyleOption(const QRect& r);
QStyleOption(const QColor& c) : def(FALSE), tb(NULL), cl(&c), cli(NULL), tbh(NULL) {} QStyleOption(QWidget *w);
QStyleOption(QTab* t) : def(FALSE), tb(t), cli(NULL), tbh(NULL) {}
QStyleOption(QListViewItem* i) : def(FALSE), tb(NULL), li(i), cli(NULL), tbh(NULL) {}
QStyleOption(QCheckListItem* i) : def(FALSE), tb(NULL), cli(i), tbh(NULL) {}
QStyleOption(Qt::ArrowType a) : def(FALSE), tb(NULL), i1((int)a), cli(NULL), tbh(NULL) {}
QStyleOption(const QRect& r) : def(FALSE), tb(NULL), i1(r.x()), i2(r.y()), i3(r.width()), i4(r.height()), cli(NULL), tbh(NULL) {}
QStyleOption(QWidget *w) : def(FALSE), tb(NULL), cli(NULL), p1((void*)w), tbh(NULL) {}
bool isDefault() const { return def; } bool isDefault() const { return def; }

@ -132,6 +132,10 @@
QThread::QThread() QThread::QThread()
{ {
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( QApplication::qt_mutex );
#endif // QT_THREAD_SUPPORT
d = new QThreadInstance; d = new QThreadInstance;
d->init(0); d->init(0);
} }

@ -108,6 +108,14 @@ public:
bool finished() const; bool finished() const;
bool running() const; bool running() const;
enum CleanupType {
CleanupNone,
CleanupMergeObjects
};
CleanupType cleanupType();
void setCleanupType(CleanupType);
protected: protected:
virtual void run() = 0; virtual void run() = 0;

@ -47,6 +47,7 @@ typedef pthread_mutex_t Q_MUTEX_T;
#include <private/qmutex_p.h> #include <private/qmutex_p.h>
#include <private/qmutexpool_p.h> #include <private/qmutexpool_p.h>
#include <qthreadstorage.h> #include <qthreadstorage.h>
#include <qapplication.h>
#include <errno.h> #include <errno.h>
#include <sched.h> #include <sched.h>
@ -109,6 +110,7 @@ void QThreadInstance::init(unsigned int stackSize)
thread_id = 0; thread_id = 0;
eventLoop = 0; eventLoop = 0;
cleanupType = QThread::CleanupMergeObjects;
// threads have not been initialized yet, do it now // threads have not been initialized yet, do it now
if (! qt_thread_mutexpool) QThread::initialize(); if (! qt_thread_mutexpool) QThread::initialize();
@ -150,6 +152,8 @@ void QThreadInstance::finish( void * )
return; return;
} }
QApplication::threadTerminationHandler((QThread*)d->args[0]);
QMutexLocker locker( d->mutex() ); QMutexLocker locker( d->mutex() );
d->running = FALSE; d->running = FALSE;
d->finished = TRUE; d->finished = TRUE;
@ -179,7 +183,6 @@ void QThreadInstance::terminate()
pthread_cancel( thread_id ); pthread_cancel( thread_id );
} }
/************************************************************************** /**************************************************************************
** QThread ** QThread
*************************************************************************/ *************************************************************************/
@ -398,6 +401,9 @@ void QThread::start(Priority priority)
d->args[0] = this; d->args[0] = this;
d->args[1] = d; d->args[1] = d;
#if defined(QT_USE_GLIBMAINLOOP) #if defined(QT_USE_GLIBMAINLOOP)
// The correct thread_id is set in QThreadInstance::start using the value of d->args[1]
d->thread_id = NULL;
// Legacy glib versions require this threading system initialization call // Legacy glib versions require this threading system initialization call
g_thread_init(NULL); g_thread_init(NULL);
@ -408,8 +414,6 @@ void QThread::start(Priority priority)
else { else {
ret = -1; ret = -1;
} }
// The correct thread_id is set in QThreadInstance::start using the value of d->args[1]
d->thread_id = NULL;
#else // QT_USE_GLIBMAINLOOP #else // QT_USE_GLIBMAINLOOP
ret = pthread_create( &d->thread_id, &attr, (QtThreadCallback)QThreadInstance::start, d->args ); ret = pthread_create( &d->thread_id, &attr, (QtThreadCallback)QThreadInstance::start, d->args );
#if defined (Q_OS_HPUX) #if defined (Q_OS_HPUX)
@ -495,6 +499,36 @@ bool QThread::wait( unsigned long time )
return (ret == 0); return (ret == 0);
} }
/*!
Returns the current cleanup behaviour of the thread.
\sa setCleanupType
\sa CleanupType
*/
QThread::CleanupType QThread::cleanupType() {
return (QThread::CleanupType)d->cleanupType;
}
/*!
Sets the current cleanup behaviour of the thread. The default,
QThread::CleanupMergeObjects, will merge any objects owned by this thread
with the main GUI thread when this thread is terminated.
If faster thread termination performance is desired, QThread::CleanupNone
may be specified instead. However, this is not recommended as any objects
owned by this thread on termination can then cause events to become "stuck"
in the global event queue, leading to high CPU usage and other undesirable
behavior. You have been warned!
\sa cleanupType
\sa CleanupType
*/
void QThread::setCleanupType(CleanupType type) {
d->cleanupType = type;
}
/*! /*!
Returns a pointer to the currently executing QThread. If the Returns a pointer to the currently executing QThread. If the
current thread was not started using the QThread API, this current thread was not started using the QThread API, this

@ -2986,7 +2986,9 @@ void generateClass() // generate C++ source code for a class
// Generate staticMetaObject member function // Generate staticMetaObject member function
// //
fprintf( out, "QMetaObject* %s::staticMetaObject()\n{\n", (const char*)qualifiedClassName() ); fprintf( out, "QMetaObject* %s::staticMetaObject()\n{\n", (const char*)qualifiedClassName() );
fprintf( out, " if ( metaObj )\n\treturn metaObj;\n" ); fprintf( out, " if ( metaObj ) {\n\treturn metaObj;\n}\n" );
fprintf( out, "#ifdef QT_THREAD_SUPPORT\n if (qt_sharedMetaObjectMutex) qt_sharedMetaObjectMutex->lock();\n" );
fprintf( out, " if ( metaObj ) {\n\tif (qt_sharedMetaObjectMutex) qt_sharedMetaObjectMutex->unlock();\n\treturn metaObj;\n }\n#endif // QT_THREAD_SUPPORT\n" );
if ( isQObject ) if ( isQObject )
fprintf( out, " QMetaObject* parentObject = staticQtMetaObject();\n" ); fprintf( out, " QMetaObject* parentObject = staticQtMetaObject();\n" );
else if ( !g->superClassName.isEmpty() ) else if ( !g->superClassName.isEmpty() )
@ -3056,6 +3058,7 @@ void generateClass() // generate C++ source code for a class
// Setup cleanup handler and return meta object // Setup cleanup handler and return meta object
// //
fprintf( out, " cleanUp_%s.setMetaObject( metaObj );\n", cleanup.data() ); fprintf( out, " cleanUp_%s.setMetaObject( metaObj );\n", cleanup.data() );
fprintf( out, "#ifdef QT_THREAD_SUPPORT\n if (qt_sharedMetaObjectMutex) qt_sharedMetaObjectMutex->unlock();\n#endif // QT_THREAD_SUPPORT\n" );
fprintf( out, " return metaObj;\n}\n" ); fprintf( out, " return metaObj;\n}\n" );
// //

@ -5812,7 +5812,9 @@ void generateClass() // generate C++ source code for a class
// Generate staticMetaObject member function // Generate staticMetaObject member function
// //
fprintf( out, "QMetaObject* %s::staticMetaObject()\n{\n", (const char*)qualifiedClassName() ); fprintf( out, "QMetaObject* %s::staticMetaObject()\n{\n", (const char*)qualifiedClassName() );
fprintf( out, " if ( metaObj )\n\treturn metaObj;\n" ); fprintf( out, " if ( metaObj ) {\n\treturn metaObj;\n}\n" );
fprintf( out, "#ifdef QT_THREAD_SUPPORT\n if (qt_sharedMetaObjectMutex) qt_sharedMetaObjectMutex->lock();\n" );
fprintf( out, " if ( metaObj ) {\n\tif (qt_sharedMetaObjectMutex) qt_sharedMetaObjectMutex->unlock();\n\treturn metaObj;\n }\n#endif // QT_THREAD_SUPPORT\n" );
if ( isQObject ) if ( isQObject )
fprintf( out, " QMetaObject* parentObject = staticQtMetaObject();\n" ); fprintf( out, " QMetaObject* parentObject = staticQtMetaObject();\n" );
else if ( !g->superClassName.isEmpty() ) else if ( !g->superClassName.isEmpty() )
@ -5882,6 +5884,7 @@ void generateClass() // generate C++ source code for a class
// Setup cleanup handler and return meta object // Setup cleanup handler and return meta object
// //
fprintf( out, " cleanUp_%s.setMetaObject( metaObj );\n", cleanup.data() ); fprintf( out, " cleanUp_%s.setMetaObject( metaObj );\n", cleanup.data() );
fprintf( out, "#ifdef QT_THREAD_SUPPORT\n if (qt_sharedMetaObjectMutex) qt_sharedMetaObjectMutex->unlock();\n#endif // QT_THREAD_SUPPORT\n" );
fprintf( out, " return metaObj;\n}\n" ); fprintf( out, " return metaObj;\n}\n" );
// //

@ -42,6 +42,7 @@
#ifndef QT_NO_STYLE #ifndef QT_NO_STYLE
#include "qmutex.h"
#include "qmenubar.h" #include "qmenubar.h"
#include "qapplication.h" #include "qapplication.h"
#include "qpainter.h" #include "qpainter.h"
@ -2782,6 +2783,9 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleControlElementData &ceD
ret = QMAX( QFontMetrics(ceData.font).lineSpacing(), 18 ); ret = QMAX( QFontMetrics(ceData.font).lineSpacing(), 18 );
} }
} }
else {
ret = 0;
}
break; } break; }
case PM_ScrollBarSliderMin: case PM_ScrollBarSliderMin:
ret = 9; ret = 9;
@ -2853,12 +2857,15 @@ int QCommonStyle::pixelMetric(PixelMetric m, const QStyleControlElementData &ceD
int thickness = pixelMetric( PM_SliderControlThickness, ceData, elementFlags, widget ); int thickness = pixelMetric( PM_SliderControlThickness, ceData, elementFlags, widget );
int ticks = ceData.tickMarkSetting; int ticks = ceData.tickMarkSetting;
if ( ticks == QSlider::Both ) if ( ticks == QSlider::Both ) {
ret = (space - thickness) / 2; ret = (space - thickness) / 2;
else if ( ticks == QSlider::Above ) }
else if ( ticks == QSlider::Above ) {
ret = space - thickness; ret = space - thickness;
else }
else {
ret = 0; ret = 0;
}
break; break;
} }

@ -45,7 +45,6 @@
#include "qglobal.h" #include "qglobal.h"
#endif // QT_H #endif // QT_H
struct Q_EXPORT QShared struct Q_EXPORT QShared
{ {
QShared() : count( 1 ) { } QShared() : count( 1 ) { }

@ -87,6 +87,12 @@
#define ULLONG_MAX Q_UINT64_C(18446744073709551615) #define ULLONG_MAX Q_UINT64_C(18446744073709551615)
#endif #endif
#ifdef QT_THREAD_SUPPORT
#include "qmutex.h"
#endif // QT_THREAD_SUPPORT
extern QMutex *qt_sharedStringMutex;
static int ucstrcmp( const QString &as, const QString &bs ) static int ucstrcmp( const QString &as, const QString &bs )
{ {
const QChar *a = as.unicode(); const QChar *a = as.unicode();
@ -1033,12 +1039,54 @@ static inline bool format(QChar::Decomposition tag, QString & str,
} // format() } // format()
#endif #endif
QStringData::QStringData() : QShared(),
unicode(0),
ascii(0),
len(0),
issimpletext(TRUE),
maxl(0),
islatin1(FALSE),
security_unpaged(FALSE) {
#ifdef QT_THREAD_SUPPORT
mutex = new QMutex( TRUE );
mutex->lock();
#endif // QT_THREAD_SUPPORT
ref();
#ifdef QT_THREAD_SUPPORT
mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
QStringData::QStringData(QChar *u, uint l, uint m) : QShared(),
unicode(u),
ascii(0),
len(l),
issimpletext(FALSE),
maxl(m),
islatin1(FALSE),
security_unpaged(FALSE) {
#ifdef QT_THREAD_SUPPORT
mutex = new QMutex( TRUE );
#endif // QT_THREAD_SUPPORT
}
QStringData::~QStringData() { QStringData::~QStringData() {
if ( unicode ) delete[] ((char*)unicode); if ( unicode ) delete[] ((char*)unicode);
if ( ascii && security_unpaged ) { if ( ascii && security_unpaged ) {
munlock(ascii, LINUX_MEMLOCK_LIMIT_BYTES); munlock(ascii, LINUX_MEMLOCK_LIMIT_BYTES);
} }
if ( ascii ) delete[] ascii; if ( ascii ) delete[] ascii;
#ifdef QT_THREAD_SUPPORT
if ( mutex ) delete mutex;
#endif // QT_THREAD_SUPPORT
}
void QStringData::setDirty() {
if ( ascii ) {
delete [] ascii;
ascii = 0;
}
issimpletext = FALSE;
} }
/* /*
@ -1194,27 +1242,30 @@ QChar* QString::latin1ToUnicode( const char *str, uint* len, uint maxlen )
return result; return result;
} }
static QChar* internalLatin1ToUnicode( const char *str, uint* len, static QChar* internalLatin1ToUnicode( const char *str, uint* len, uint maxlen = (uint)-1 )
uint maxlen = (uint)-1 )
{ {
QChar* result = 0; QChar* result = 0;
uint l = 0; uint l = 0;
if ( str ) { if ( str ) {
if ( maxlen != (uint)-1 ) { if ( maxlen != (uint)-1 ) {
while ( l < maxlen && str[l] ) while ( l < maxlen && str[l] ) {
l++; l++;
} else { }
}
else {
// Faster? // Faster?
l = int(strlen( str )); l = int(strlen( str ));
} }
QChar *uc = QT_ALLOC_QCHAR_VEC( l ); QChar *uc = QT_ALLOC_QCHAR_VEC( l );
result = uc; result = uc;
uint i = l; uint i = l;
while ( i-- ) while ( i-- ) {
*uc++ = *str++; *uc++ = *str++;
}
} }
if ( len ) if ( len ) {
*len = l; *len = l;
}
return result; return result;
} }
@ -1395,11 +1446,26 @@ QT_STATIC_CONST_IMPL QChar QChar::nbsp((ushort)0x00a0);
QStringData* QString::makeSharedNull() QStringData* QString::makeSharedNull()
{ {
#ifdef QT_THREAD_SUPPORT
if (qt_sharedStringMutex) qt_sharedStringMutex->lock();
#endif // QT_THREAD_SUPPORT
if (QString::shared_null) {
#ifdef QT_THREAD_SUPPORT
if (qt_sharedStringMutex) qt_sharedStringMutex->unlock();
#endif // QT_THREAD_SUPPORT
return QString::shared_null;
}
QString::shared_null = new QStringData; QString::shared_null = new QStringData;
#if defined( Q_OS_MAC ) || defined(Q_OS_SOLARIS) || defined(Q_OS_HPUX) || defined(Q_OS_AIX) #if defined( Q_OS_MAC ) || defined(Q_OS_SOLARIS) || defined(Q_OS_HPUX) || defined(Q_OS_AIX)
QString *that = const_cast<QString *>(&QString::null); QString *that = const_cast<QString *>(&QString::null);
that->d = QString::shared_null; that->d = QString::shared_null;
#endif #endif
#ifdef QT_THREAD_SUPPORT
if (qt_sharedStringMutex) qt_sharedStringMutex->unlock();
#endif // QT_THREAD_SUPPORT
return QString::shared_null; return QString::shared_null;
} }
@ -1412,6 +1478,24 @@ QStringData* QString::makeSharedNull()
\sa isNull() \sa isNull()
*/ */
// FIXME
// Original Qt3 code stated that there is
// "No safe way to pre-init shared_null on ALL compilers/linkers"
// Is this still true?
QString::QString() :
d(0)
{
d = shared_null ? shared_null : makeSharedNull();
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
d->ref();
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
/*! /*!
Constructs a string of length one, containing the character \a ch. Constructs a string of length one, containing the character \a ch.
*/ */
@ -1428,7 +1512,15 @@ QString::QString( QChar ch )
QString::QString( const QString &s ) : QString::QString( const QString &s ) :
d(s.d) d(s.d)
{ {
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
d->ref(); d->ref();
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
} }
/*! /*!
@ -1451,7 +1543,13 @@ QString::QString( int size, bool /*dummy*/ )
d = new QStringData( uc, 0, l ); d = new QStringData( uc, 0, l );
} else { } else {
d = shared_null ? shared_null : (shared_null=new QStringData); d = shared_null ? shared_null : (shared_null=new QStringData);
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
d->ref(); d->ref();
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
} }
} }
@ -1493,11 +1591,19 @@ QString::QString( const QChar* unicode, uint length )
{ {
if ( !unicode && !length ) { if ( !unicode && !length ) {
d = shared_null ? shared_null : makeSharedNull(); d = shared_null ? shared_null : makeSharedNull();
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
d->ref(); d->ref();
} else { #ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
else {
QChar* uc = QT_ALLOC_QCHAR_VEC( length ); QChar* uc = QT_ALLOC_QCHAR_VEC( length );
if ( unicode ) if ( unicode ) {
memcpy(uc, unicode, length*sizeof(QChar)); memcpy(uc, unicode, length*sizeof(QChar));
}
d = new QStringData(uc,unicode ? length : 0,length); d = new QStringData(uc,unicode ? length : 0,length);
} }
} }
@ -1556,6 +1662,10 @@ QString::QString( const std::string &str )
} }
#endif #endif
QString::QString( QStringData* dd, bool /* dummy */ ) {
d = dd;
}
/*! /*!
\fn QString::~QString() \fn QString::~QString()
@ -1563,6 +1673,31 @@ QString::QString( const std::string &str )
last reference to the string. last reference to the string.
*/ */
QString::~QString()
{
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
if ( d->deref() ) {
if ( d != shared_null ) {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
d->deleteSelf();
}
else {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
}
else {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
}
/*! /*!
Deallocates any space reserved solely by this QString. Deallocates any space reserved solely by this QString.
@ -1580,11 +1715,25 @@ void QString::real_detach()
void QString::deref() void QString::deref()
{ {
if ( d && d->deref() ) { if ( d ) {
if ( d != shared_null ) #ifdef QT_THREAD_SUPPORT
delete d; d->mutex->lock();
d = 0; #endif // QT_THREAD_SUPPORT
} if ( d->deref() ) {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
if ( d != shared_null ) {
delete d;
}
d = 0;
}
else {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
}
} }
void QStringData::deleteSelf() void QStringData::deleteSelf()
@ -1624,9 +1773,16 @@ void QStringData::deleteSelf()
*/ */
QString &QString::operator=( const QString &s ) QString &QString::operator=( const QString &s )
{ {
#ifdef QT_THREAD_SUPPORT
s.d->mutex->lock();
#endif // QT_THREAD_SUPPORT
s.d->ref(); s.d->ref();
#ifdef QT_THREAD_SUPPORT
s.d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
deref(); deref();
d = s.d; d = s.d;
return *this; return *this;
} }
@ -1730,6 +1886,10 @@ void QString::truncate( uint newLen )
*/ */
void QString::setLength( uint newLen ) void QString::setLength( uint newLen )
{ {
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
if ( d->count != 1 || newLen > d->maxl || if ( d->count != 1 || newLen > d->maxl ||
( newLen * 4 < d->maxl && d->maxl > 4 ) ) { ( newLen * 4 < d->maxl && d->maxl > 4 ) ) {
// detach, grow or shrink // detach, grow or shrink
@ -1739,12 +1899,24 @@ void QString::setLength( uint newLen )
uint len = QMIN( d->len, newLen ); uint len = QMIN( d->len, newLen );
memcpy( nd, d->unicode, sizeof(QChar) * len ); memcpy( nd, d->unicode, sizeof(QChar) * len );
bool unpaged = d->security_unpaged; bool unpaged = d->security_unpaged;
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
deref(); deref();
d = new QStringData( nd, newLen, newMax ); d = new QStringData( nd, newLen, newMax );
setSecurityUnPaged(unpaged); setSecurityUnPaged(unpaged);
} }
} else { else {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
}
else {
d->len = newLen; d->len = newLen;
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
d->setDirty(); d->setDirty();
} }
} }
@ -1830,10 +2002,21 @@ void QString::squeeze()
*/ */
void QString::grow( uint newLen ) void QString::grow( uint newLen )
{ {
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
if ( d->count != 1 || newLen > d->maxl ) { if ( d->count != 1 || newLen > d->maxl ) {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
setLength( newLen ); setLength( newLen );
} else { }
else {
d->len = newLen; d->len = newLen;
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
d->setDirty(); d->setDirty();
} }
} }
@ -5868,13 +6051,15 @@ static QChar *addOne(QChar *qch, QString &str)
*/ */
QString QString::fromUtf8( const char* utf8, int len ) QString QString::fromUtf8( const char* utf8, int len )
{ {
if ( !utf8 ) if ( !utf8 ) {
return QString::null; return QString::null;
}
int slen = 0; int slen = 0;
if (len >= 0) { if (len >= 0) {
while (slen < len && utf8[slen]) while (slen < len && utf8[slen]) {
slen++; slen++;
}
} else { } else {
slen = int(strlen(utf8)); slen = int(strlen(utf8));
} }
@ -6012,10 +6197,13 @@ QString QString::fromLatin1( const char* chars, int len )
{ {
uint l; uint l;
QChar *uc; QChar *uc;
if ( len < 0 ) if ( len < 0 ) {
len = -1; len = -1;
}
uc = internalLatin1ToUnicode( chars, &l, len ); uc = internalLatin1ToUnicode( chars, &l, len );
return QString( new QStringData(uc, l, l), TRUE ); QString ret( new QStringData(uc, l, l), TRUE );
return ret;
} }
/*! /*!
@ -6178,7 +6366,8 @@ QString QString::fromUcs2( const unsigned short *str )
length++; length++;
QChar* uc = QT_ALLOC_QCHAR_VEC( length ); QChar* uc = QT_ALLOC_QCHAR_VEC( length );
memcpy( uc, str, length*sizeof(QChar) ); memcpy( uc, str, length*sizeof(QChar) );
return QString( new QStringData( uc, length, length ), TRUE ); QString ret( new QStringData( uc, length, length ), TRUE );
return ret;
} }
} }
@ -6225,6 +6414,25 @@ QString QString::fromUcs2( const unsigned short *str )
\sa constref() \sa constref()
*/ */
QChar& QString::ref(uint i) {
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
if ( (d->count != 1) || (i >= d->len) ) {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
subat( i );
}
else {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
d->setDirty();
return d->unicode[i];
}
/*! /*!
\fn QChar QString::operator[]( int ) const \fn QChar QString::operator[]( int ) const
@ -6300,27 +6508,48 @@ void QString::subat( uint i )
QString& QString::setUnicode( const QChar *unicode, uint len ) QString& QString::setUnicode( const QChar *unicode, uint len )
{ {
if ( len == 0 ) { // set to null string if ( len == 0 ) { // set to null string
if ( d != shared_null ) { // beware of nullstring being set to nullstring if ( d != shared_null ) { // beware of nullstring being set to nullstring
deref(); deref();
d = shared_null ? shared_null : makeSharedNull(); d = shared_null ? shared_null : makeSharedNull();
d->ref(); #ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
d->ref();
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
} }
} else if ( d->count != 1 || len > d->maxl || else {
( len * 4 < d->maxl && d->maxl > 4 ) ) { #ifdef QT_THREAD_SUPPORT
// detach, grown or shrink d->mutex->lock();
uint newMax = computeNewMax( len ); #endif // QT_THREAD_SUPPORT
QChar* nd = QT_ALLOC_QCHAR_VEC( newMax ); if ( d->count != 1 || len > d->maxl || ( len * 4 < d->maxl && d->maxl > 4 ) ) {
if ( unicode ) // detach, grown or shrink
memcpy( nd, unicode, sizeof(QChar)*len ); uint newMax = computeNewMax( len );
deref(); QChar* nd = QT_ALLOC_QCHAR_VEC( newMax );
d = new QStringData( nd, len, newMax ); if ( unicode ) {
} else { memcpy( nd, unicode, sizeof(QChar)*len );
d->len = len; }
d->setDirty(); #ifdef QT_THREAD_SUPPORT
if ( unicode ) d->mutex->unlock();
memcpy( d->unicode, unicode, sizeof(QChar)*len ); #endif // QT_THREAD_SUPPORT
} deref();
d = new QStringData( nd, len, newMax );
}
else {
d->len = len;
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
d->setDirty();
if ( unicode ) {
memcpy( d->unicode, unicode, sizeof(QChar)*len );
}
}
}
return *this; return *this;
} }
@ -7024,15 +7253,23 @@ QConstString::QConstString( const QChar* unicode, uint length ) :
*/ */
QConstString::~QConstString() QConstString::~QConstString()
{ {
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
if ( d->count > 1 ) { if ( d->count > 1 ) {
QChar* cp = QT_ALLOC_QCHAR_VEC( d->len ); QChar* cp = QT_ALLOC_QCHAR_VEC( d->len );
memcpy( cp, d->unicode, d->len*sizeof(QChar) ); memcpy( cp, d->unicode, d->len*sizeof(QChar) );
d->unicode = cp; d->unicode = cp;
} else { }
else {
d->unicode = 0; d->unicode = 0;
} }
// The original d->unicode is now unlinked. // The original d->unicode is now unlinked.
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
} }
/*! /*!

@ -71,6 +71,7 @@
class QRegExp; class QRegExp;
class QString; class QString;
class QCharRef; class QCharRef;
class QMutex;
template <class T> class QDeepCopy; template <class T> class QDeepCopy;
class Q_EXPORT QChar { class Q_EXPORT QChar {
@ -359,22 +360,14 @@ inline bool operator>( QChar c1, QChar c2 ) { return !(c2>=c1); }
// internal // internal
struct Q_EXPORT QStringData : public QShared { struct Q_EXPORT QStringData : public QShared {
QStringData() : QStringData();
QShared(), unicode(0), ascii(0), len(0), issimpletext(TRUE), maxl(0), islatin1(FALSE), security_unpaged(FALSE) { ref(); } QStringData(QChar *u, uint l, uint m);
QStringData(QChar *u, uint l, uint m) :
QShared(), unicode(u), ascii(0), len(l), issimpletext(FALSE), maxl(m), islatin1(FALSE), security_unpaged(FALSE) { }
~QStringData(); ~QStringData();
void deleteSelf(); void deleteSelf();
QChar *unicode; QChar *unicode;
char *ascii; char *ascii;
void setDirty() { void setDirty();
if ( ascii ) {
delete [] ascii;
ascii = 0;
}
issimpletext = FALSE;
}
#ifdef Q_OS_MAC9 #ifdef Q_OS_MAC9
uint len; uint len;
#else #else
@ -390,6 +383,8 @@ struct Q_EXPORT QStringData : public QShared {
bool security_unpaged : 1; bool security_unpaged : 1;
QMutex* mutex;
private: private:
#if defined(Q_DISABLE_COPY) #if defined(Q_DISABLE_COPY)
QStringData( const QStringData& ); QStringData( const QStringData& );
@ -646,13 +641,7 @@ public:
QChar constref(uint i) const QChar constref(uint i) const
{ return at(i); } { return at(i); }
QChar& ref(uint i) QChar& ref(uint i);
{ // Optimized for easy-inlining by simple compilers.
if ( d->count != 1 || i >= d->len )
subat( i );
d->setDirty();
return d->unicode[i];
}
const QChar* unicode() const { return d->unicode; } const QChar* unicode() const { return d->unicode; }
const char* ascii() const; const char* ascii() const;
@ -747,7 +736,7 @@ private:
friend class QConstString; friend class QConstString;
friend class QTextStream; friend class QTextStream;
QString( QStringData* dd, bool /* dummy */ ) : d(dd) { } QString( QStringData* dd, bool /* dummy */ );
// needed for QDeepCopy // needed for QDeepCopy
void detach(); void detach();
@ -839,25 +828,6 @@ Q_EXPORT QDataStream &operator>>( QDataStream &, QString & );
QString inline functions QString inline functions
*****************************************************************************/ *****************************************************************************/
// These two move code into makeSharedNull() and deletesData()
// to improve cache-coherence (and reduce code bloat), while
// keeping the common cases fast.
//
// No safe way to pre-init shared_null on ALL compilers/linkers.
inline QString::QString() :
d(shared_null ? shared_null : makeSharedNull())
{
d->ref();
}
//
inline QString::~QString()
{
if ( d->deref() ) {
if ( d != shared_null )
d->deleteSelf();
}
}
// needed for QDeepCopy // needed for QDeepCopy
inline void QString::detach() inline void QString::detach()
{ real_detach(); } { real_detach(); }

@ -101,6 +101,7 @@ public:
#endif // Q_OS_WIN32 #endif // Q_OS_WIN32
QEventLoop* eventLoop; QEventLoop* eventLoop;
int cleanupType;
}; };
#endif // QT_THREAD_SUPPORT #endif // QT_THREAD_SUPPORT

@ -33,6 +33,8 @@ void WorkerObject::run()
eventLoop->processEvents(QEventLoop::AllEvents); eventLoop->processEvents(QEventLoop::AllEvents);
} }
delete t;
eventLoop->exit(0); eventLoop->exit(0);
} }

Loading…
Cancel
Save