diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-05-14 19:34:10 -0500 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2013-05-14 19:34:10 -0500 |
commit | 4eba9b823832a5bab1acffeabc245b06fe113d75 (patch) | |
tree | 9ec81ead726a66066c6450c805beb8e233391a65 /src/tools | |
parent | be8413249bb8a6d8dc2cfc693d9c1037284fd251 (diff) | |
download | qt3-4eba9b823832a5bab1acffeabc245b06fe113d75.tar.gz qt3-4eba9b823832a5bab1acffeabc245b06fe113d75.zip |
Fix a number of threading data races
Add proper thread termination handler
This partially resolves Bug 1508
Diffstat (limited to 'src/tools')
-rw-r--r-- | src/tools/qshared.h | 1 | ||||
-rw-r--r-- | src/tools/qstring.cpp | 329 | ||||
-rw-r--r-- | src/tools/qstring.h | 46 | ||||
-rw-r--r-- | src/tools/qthreadinstance_p.h | 1 |
4 files changed, 292 insertions, 85 deletions
diff --git a/src/tools/qshared.h b/src/tools/qshared.h index 290592c..7fe2593 100644 --- a/src/tools/qshared.h +++ b/src/tools/qshared.h @@ -45,7 +45,6 @@ #include "qglobal.h" #endif // QT_H - struct Q_EXPORT QShared { QShared() : count( 1 ) { } diff --git a/src/tools/qstring.cpp b/src/tools/qstring.cpp index 8717f6a..0630cd3 100644 --- a/src/tools/qstring.cpp +++ b/src/tools/qstring.cpp @@ -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 } /*! diff --git a/src/tools/qstring.h b/src/tools/qstring.h index 58830db..8715395 100644 --- a/src/tools/qstring.h +++ b/src/tools/qstring.h @@ -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(); } diff --git a/src/tools/qthreadinstance_p.h b/src/tools/qthreadinstance_p.h index 7580b25..34550a8 100644 --- a/src/tools/qthreadinstance_p.h +++ b/src/tools/qthreadinstance_p.h @@ -101,6 +101,7 @@ public: #endif // Q_OS_WIN32 QEventLoop* eventLoop; + int cleanupType; }; #endif // QT_THREAD_SUPPORT |