summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2013-05-14 19:34:10 -0500
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2013-05-14 19:34:10 -0500
commit4eba9b823832a5bab1acffeabc245b06fe113d75 (patch)
tree9ec81ead726a66066c6450c805beb8e233391a65 /src/tools
parentbe8413249bb8a6d8dc2cfc693d9c1037284fd251 (diff)
downloadqt3-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.h1
-rw-r--r--src/tools/qstring.cpp329
-rw-r--r--src/tools/qstring.h46
-rw-r--r--src/tools/qthreadinstance_p.h1
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