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/qstring.cpp | |
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/qstring.cpp')
-rw-r--r-- | src/tools/qstring.cpp | 329 |
1 files changed, 283 insertions, 46 deletions
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 } /*! |