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
QMutex *QApplication::qt_mutex = 0;
static QMutex *postevent_mutex = 0;
static Qt::HANDLE qt_application_thread_id = 0;
QMutex *qt_sharedStringMutex = 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()
{
return qt_application_thread_id;
@ -600,6 +605,10 @@ static QPostEventList *globalPostedEvents = 0; // list of posted events
uint qGlobalPostedEventsCount()
{
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( postevent_mutex );
#endif // QT_THREAD_SUPPORT
if (!globalPostedEvents) {
return 0;
}
@ -1015,6 +1024,11 @@ void QApplication::initialize( int argc, char **argv )
{
#ifdef QT_THREAD_SUPPORT
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 );
qt_application_thread_id = QThread::currentThread();
#endif // QT_THREAD_SUPPORT
@ -1184,6 +1198,17 @@ QApplication::~QApplication()
session_key = 0;
#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_app_has_font = FALSE;
app_tracking = 0;
@ -2425,35 +2450,40 @@ bool QApplication::notify( QObject *receiver, QEvent *e )
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
QMutexLocker locker( postevent_mutex );
#endif // QT_THREAD_SUPPORT
// the QObject destructor calls QObject::removeChild, which calls
// QApplication::sendEvent() directly. this can 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 for this object.
if ( receiver->postedEvents ) {
// if this is a child remove event and the child insert
// hasn't been dispatched yet, kill that insert
QPostEventList * l = receiver->postedEvents;
QObject * c = ((QChildEvent*)e)->child();
QPostEvent * pe;
l->first();
while( ( pe = l->current()) != 0 ) {
if ( pe->event && pe->receiver == receiver &&
pe->event->type() == QEvent::ChildInserted &&
((QChildEvent*)pe->event)->child() == c ) {
pe->event->posted = FALSE;
delete pe->event;
pe->event = 0;
l->remove();
continue;
if (globalPostedEvents) {
// the QObject destructor calls QObject::removeChild, which calls
// QApplication::sendEvent() directly. this can 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 for this object.
if ( receiver->postedEvents ) {
// if this is a child remove event and the child insert
// hasn't been dispatched yet, kill that insert
QPostEventList * l = receiver->postedEvents;
QObject * c = ((QChildEvent*)e)->child();
QPostEvent * pe;
l->first();
while( ( pe = l->current()) != 0 ) {
if ( pe->event && pe->receiver == receiver &&
pe->event->type() == QEvent::ChildInserted &&
((QChildEvent*)pe->event)->child() == c ) {
pe->event->posted = FALSE;
delete pe->event;
pe->event = 0;
l->remove();
continue;
}
l->next();
}
}
l->next();
}
}
}
@ -3545,8 +3575,9 @@ void QApplication::removePostedEvents( QObject *receiver )
void QApplication::removePostedEvents( QObject *receiver, int event_type )
{
if ( !receiver )
if ( !receiver ) {
return;
}
#ifdef QT_THREAD_SUPPORT
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,
// and when we get here, we may not have any more posted events
// for this object.
if ( !receiver->postedEvents )
if ( !receiver->postedEvents ) {
return;
}
// iterate over the object-specifc list and delete the events.
// 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 )
{
if ( !event || !event->posted )
if ( !event || !event->posted ) {
return;
}
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( postevent_mutex );
#endif // QT_THREAD_SUPPORT
if ( !globalPostedEvents ) {
#if defined(QT_DEBUG)
@ -3607,10 +3644,6 @@ void QApplication::removePostedEvent( QEvent * event )
#endif
}
#ifdef QT_THREAD_SUPPORT
QMutexLocker locker( postevent_mutex );
#endif // QT_THREAD_SUPPORT
QPostEventListIt it( *globalPostedEvents );
QPostEvent * pe;
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
Sets the active window in reaction to a system event. Call this

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

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

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

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

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

@ -157,6 +157,7 @@ class QMetaObject;
class QSignal;
class QConnection;
class QEvent;
class QMutex;
struct QMetaData;
class QConnectionList;
class QConnectionListIt;
@ -165,6 +166,8 @@ class QObjectList;
class QObjectListIt;
class QMemberDict;
extern QMutex *qt_sharedMetaObjectMutex;
Q_EXPORT void *qt_find_obj_child( QObject *, const char *, const char * );
#define Q_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
\brief The QStyleOption class specifies optional parameters for QStyle functions.

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

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

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

@ -47,6 +47,7 @@ typedef pthread_mutex_t Q_MUTEX_T;
#include <private/qmutex_p.h>
#include <private/qmutexpool_p.h>
#include <qthreadstorage.h>
#include <qapplication.h>
#include <errno.h>
#include <sched.h>
@ -109,6 +110,7 @@ void QThreadInstance::init(unsigned int stackSize)
thread_id = 0;
eventLoop = 0;
cleanupType = QThread::CleanupMergeObjects;
// threads have not been initialized yet, do it now
if (! qt_thread_mutexpool) QThread::initialize();
@ -150,6 +152,8 @@ void QThreadInstance::finish( void * )
return;
}
QApplication::threadTerminationHandler((QThread*)d->args[0]);
QMutexLocker locker( d->mutex() );
d->running = FALSE;
d->finished = TRUE;
@ -179,7 +183,6 @@ void QThreadInstance::terminate()
pthread_cancel( thread_id );
}
/**************************************************************************
** QThread
*************************************************************************/
@ -398,6 +401,9 @@ void QThread::start(Priority priority)
d->args[0] = this;
d->args[1] = d;
#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
g_thread_init(NULL);
@ -408,8 +414,6 @@ void QThread::start(Priority priority)
else {
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
ret = pthread_create( &d->thread_id, &attr, (QtThreadCallback)QThreadInstance::start, d->args );
#if defined (Q_OS_HPUX)
@ -495,6 +499,36 @@ bool QThread::wait( unsigned long time )
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
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
//
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 )
fprintf( out, " QMetaObject* parentObject = staticQtMetaObject();\n" );
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
//
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" );
//

@ -5812,7 +5812,9 @@ void generateClass() // generate C++ source code for a class
// Generate staticMetaObject member function
//
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 )
fprintf( out, " QMetaObject* parentObject = staticQtMetaObject();\n" );
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
//
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" );
//

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

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

@ -87,6 +87,12 @@
#define ULLONG_MAX Q_UINT64_C(18446744073709551615)
#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 )
{
const QChar *a = as.unicode();
@ -1033,12 +1039,54 @@ static inline bool format(QChar::Decomposition tag, QString & str,
} // format()
#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() {
if ( unicode ) delete[] ((char*)unicode);
if ( ascii && security_unpaged ) {
munlock(ascii, LINUX_MEMLOCK_LIMIT_BYTES);
}
if ( ascii ) delete[] ascii;
if ( unicode ) delete[] ((char*)unicode);
if ( ascii && security_unpaged ) {
munlock(ascii, LINUX_MEMLOCK_LIMIT_BYTES);
}
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;
}
static QChar* internalLatin1ToUnicode( const char *str, uint* len,
uint maxlen = (uint)-1 )
static QChar* internalLatin1ToUnicode( const char *str, uint* len, uint maxlen = (uint)-1 )
{
QChar* result = 0;
uint l = 0;
if ( str ) {
if ( maxlen != (uint)-1 ) {
while ( l < maxlen && str[l] )
while ( l < maxlen && str[l] ) {
l++;
} else {
}
}
else {
// Faster?
l = int(strlen( str ));
}
QChar *uc = QT_ALLOC_QCHAR_VEC( l );
result = uc;
uint i = l;
while ( i-- )
while ( i-- ) {
*uc++ = *str++;
}
}
if ( len )
if ( len ) {
*len = l;
}
return result;
}
@ -1395,11 +1446,26 @@ QT_STATIC_CONST_IMPL QChar QChar::nbsp((ushort)0x00a0);
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;
#if defined( Q_OS_MAC ) || defined(Q_OS_SOLARIS) || defined(Q_OS_HPUX) || defined(Q_OS_AIX)
QString *that = const_cast<QString *>(&QString::null);
that->d = QString::shared_null;
#endif
#ifdef QT_THREAD_SUPPORT
if (qt_sharedStringMutex) qt_sharedStringMutex->unlock();
#endif // QT_THREAD_SUPPORT
return QString::shared_null;
}
@ -1412,6 +1478,24 @@ QStringData* QString::makeSharedNull()
\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.
*/
@ -1428,7 +1512,15 @@ QString::QString( QChar ch )
QString::QString( const QString &s ) :
d(s.d)
{
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
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 );
} else {
d = shared_null ? shared_null : (shared_null=new QStringData);
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
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 ) {
d = shared_null ? shared_null : makeSharedNull();
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
d->ref();
} else {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
else {
QChar* uc = QT_ALLOC_QCHAR_VEC( length );
if ( unicode )
if ( unicode ) {
memcpy(uc, unicode, length*sizeof(QChar));
}
d = new QStringData(uc,unicode ? length : 0,length);
}
}
@ -1556,6 +1662,10 @@ QString::QString( const std::string &str )
}
#endif
QString::QString( QStringData* dd, bool /* dummy */ ) {
d = dd;
}
/*!
\fn QString::~QString()
@ -1563,6 +1673,31 @@ QString::QString( const std::string &str )
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.
@ -1580,11 +1715,25 @@ void QString::real_detach()
void QString::deref()
{
if ( d && d->deref() ) {
if ( d != shared_null )
delete d;
d = 0;
}
if ( d ) {
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#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()
@ -1624,9 +1773,16 @@ void QStringData::deleteSelf()
*/
QString &QString::operator=( const QString &s )
{
#ifdef QT_THREAD_SUPPORT
s.d->mutex->lock();
#endif // QT_THREAD_SUPPORT
s.d->ref();
#ifdef QT_THREAD_SUPPORT
s.d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
deref();
d = s.d;
return *this;
}
@ -1730,6 +1886,10 @@ void QString::truncate( 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 ||
( newLen * 4 < d->maxl && d->maxl > 4 ) ) {
// detach, grow or shrink
@ -1739,12 +1899,24 @@ void QString::setLength( uint newLen )
uint len = QMIN( d->len, newLen );
memcpy( nd, d->unicode, sizeof(QChar) * len );
bool unpaged = d->security_unpaged;
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
deref();
d = new QStringData( nd, newLen, newMax );
setSecurityUnPaged(unpaged);
}
} else {
else {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
}
}
else {
d->len = newLen;
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
d->setDirty();
}
}
@ -1830,10 +2002,21 @@ void QString::squeeze()
*/
void QString::grow( uint newLen )
{
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
if ( d->count != 1 || newLen > d->maxl ) {
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
setLength( newLen );
} else {
}
else {
d->len = newLen;
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#endif // QT_THREAD_SUPPORT
d->setDirty();
}
}
@ -5868,13 +6051,15 @@ static QChar *addOne(QChar *qch, QString &str)
*/
QString QString::fromUtf8( const char* utf8, int len )
{
if ( !utf8 )
if ( !utf8 ) {
return QString::null;
}
int slen = 0;
if (len >= 0) {
while (slen < len && utf8[slen])
while (slen < len && utf8[slen]) {
slen++;
}
} else {
slen = int(strlen(utf8));
}
@ -6012,10 +6197,13 @@ QString QString::fromLatin1( const char* chars, int len )
{
uint l;
QChar *uc;
if ( len < 0 )
if ( len < 0 ) {
len = -1;
}
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++;
QChar* uc = QT_ALLOC_QCHAR_VEC( length );
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()
*/
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
@ -6300,27 +6508,48 @@ void QString::subat( uint i )
QString& QString::setUnicode( const QChar *unicode, uint len )
{
if ( len == 0 ) { // set to null string
if ( d != shared_null ) { // beware of nullstring being set to nullstring
deref();
d = shared_null ? shared_null : makeSharedNull();
d->ref();
if ( len == 0 ) { // set to null string
if ( d != shared_null ) { // beware of nullstring being set to nullstring
deref();
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
}
}
} else if ( d->count != 1 || len > d->maxl ||
( len * 4 < d->maxl && d->maxl > 4 ) ) {
// detach, grown or shrink
uint newMax = computeNewMax( len );
QChar* nd = QT_ALLOC_QCHAR_VEC( newMax );
if ( unicode )
memcpy( nd, unicode, sizeof(QChar)*len );
deref();
d = new QStringData( nd, len, newMax );
} else {
d->len = len;
d->setDirty();
if ( unicode )
memcpy( d->unicode, unicode, sizeof(QChar)*len );
}
else {
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
if ( d->count != 1 || len > d->maxl || ( len * 4 < d->maxl && d->maxl > 4 ) ) {
// detach, grown or shrink
uint newMax = computeNewMax( len );
QChar* nd = QT_ALLOC_QCHAR_VEC( newMax );
if ( unicode ) {
memcpy( nd, unicode, sizeof(QChar)*len );
}
#ifdef QT_THREAD_SUPPORT
d->mutex->unlock();
#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;
}
@ -7024,15 +7253,23 @@ QConstString::QConstString( const QChar* unicode, uint length ) :
*/
QConstString::~QConstString()
{
#ifdef QT_THREAD_SUPPORT
d->mutex->lock();
#endif // QT_THREAD_SUPPORT
if ( d->count > 1 ) {
QChar* cp = QT_ALLOC_QCHAR_VEC( d->len );
memcpy( cp, d->unicode, d->len*sizeof(QChar) );
d->unicode = cp;
} else {
}
else {
d->unicode = 0;
}
// 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 QString;
class QCharRef;
class QMutex;
template <class T> class QDeepCopy;
class Q_EXPORT QChar {
@ -359,22 +360,14 @@ inline bool operator>( QChar c1, QChar c2 ) { return !(c2>=c1); }
// internal
struct Q_EXPORT QStringData : public QShared {
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) :
QShared(), unicode(u), ascii(0), len(l), issimpletext(FALSE), maxl(m), islatin1(FALSE), security_unpaged(FALSE) { }
QStringData();
QStringData(QChar *u, uint l, uint m);
~QStringData();
void deleteSelf();
QChar *unicode;
char *ascii;
void setDirty() {
if ( ascii ) {
delete [] ascii;
ascii = 0;
}
issimpletext = FALSE;
}
void setDirty();
#ifdef Q_OS_MAC9
uint len;
#else
@ -390,6 +383,8 @@ struct Q_EXPORT QStringData : public QShared {
bool security_unpaged : 1;
QMutex* mutex;
private:
#if defined(Q_DISABLE_COPY)
QStringData( const QStringData& );
@ -646,13 +641,7 @@ public:
QChar constref(uint i) const
{ return at(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];
}
QChar& ref(uint i);
const QChar* unicode() const { return d->unicode; }
const char* ascii() const;
@ -747,7 +736,7 @@ private:
friend class QConstString;
friend class QTextStream;
QString( QStringData* dd, bool /* dummy */ ) : d(dd) { }
QString( QStringData* dd, bool /* dummy */ );
// needed for QDeepCopy
void detach();
@ -839,25 +828,6 @@ Q_EXPORT QDataStream &operator>>( QDataStream &, QString & );
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
inline void QString::detach()
{ real_detach(); }

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

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

Loading…
Cancel
Save