From 001bd63e813cf19d1d6abbbfeb2599e6804807d5 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 21 Jul 2011 16:33:17 +0200 Subject: Make the N parameter to the QXXXLiterals be the actual string length Before, it was the length + 1, to include the ending NUL or U+0000. This avoids mistakes of -1 in QStringBuilder and will allow us simpler code in the User-Defined Literal (future improvement) Change-Id: I75c47d6c44579124888f925e240817229347dc70 Merge-request: 31 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/1966 Reviewed-by: Qt Sanity Bot --- src/corelib/tools/qbytearray.h | 12 ++++++------ src/corelib/tools/qstring.h | 20 ++++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index dbac302d05..4190ffa18a 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -133,10 +133,10 @@ struct QByteArrayData inline const char *data() const { return d + sizeof(qptrdiff) + offset; } }; -template struct QConstByteArrayData +template struct QConstByteArrayData { const QByteArrayData ba; - const char data[n]; + const char data[N + 1]; }; template struct QConstByteArrayDataPtr @@ -147,9 +147,9 @@ template struct QConstByteArrayDataPtr #if defined(Q_COMPILER_LAMBDA) # define QByteArrayLiteral(str) ([]() { \ - enum { Size = sizeof(str) }; \ + enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData qbytearray_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ QConstByteArrayDataPtr holder = { &qbytearray_literal }; \ return holder; }()) @@ -160,9 +160,9 @@ template struct QConstByteArrayDataPtr # define QByteArrayLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(str) }; \ + enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData qbytearray_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ QConstByteArrayDataPtr holder = { &qbytearray_literal }; \ holder; }) #endif diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index af3e3f3ff9..4471da4b09 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -97,36 +97,36 @@ template struct QConstStringDataPtr }; #if defined(Q_COMPILER_UNICODE_STRINGS) -template struct QConstStringData +template struct QConstStringData { const QStringData str; - const char16_t data[n]; + const char16_t data[N + 1]; }; #define QT_QSTRING_UNICODE_MARKER u"" #elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) // wchar_t is 2 bytes -template struct QConstStringData +template struct QConstStringData { const QStringData str; - const wchar_t data[n]; + const wchar_t data[N + 1]; }; #define QT_QSTRING_UNICODE_MARKER L"" #else -template struct QConstStringData +template struct QConstStringData { const QStringData str; - const ushort data[n]; + const ushort data[N + 1]; }; #endif #if defined(QT_QSTRING_UNICODE_MARKER) # if defined(Q_COMPILER_LAMBDA) # define QStringLiteral(str) ([]() { \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ + enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ QConstStringDataPtr holder = { &qstring_literal }; \ return holder; }()) @@ -137,9 +137,9 @@ template struct QConstStringData # define QStringLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ + enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ QConstStringDataPtr holder = { &qstring_literal }; \ holder; }) # endif -- cgit v1.2.3 From 038d7c6c3b9815068e1f5b6df12625181f0313e1 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 21 Jul 2011 17:10:30 +0200 Subject: Fix the timeout calculation again. The commit 412ef92162f8874a1585221125c31ef5f8ccc9cb introduced a fix, but the fix was incomplete. Fix it for good. Change-Id: I3e7fbdb294f8e960fbbf2e830790750240ed813a Merge-request: 30 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/1991 Reviewed-by: Qt Sanity Bot --- src/corelib/thread/qmutex_unix.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index e692e19525..2a9d23c361 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -161,8 +161,8 @@ bool QMutexPrivate::wait(int timeout) return false; } - ts.tv_sec = timeout / Q_INT64_C(1000) / 1000 / 1000; - ts.tv_nsec = timeout % (Q_INT64_C(1000) * 1000 * 1000); + ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000; + ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000); } } return true; -- cgit v1.2.3 From a6d87b51141e362f39e323bf329491d27565b137 Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 21 Jul 2011 16:33:40 +0200 Subject: Add unit tests to QStringLiteral and QByteArrayLiteral with operator % This requires a fix for QByteArrayLiteral to work too. Change-Id: I3c2a50ad431d5b0c014a341e675fa54e7b206e70 Merge-request: 27 Reviewed-by: Olivier Goffart Reviewed-on: http://codereview.qt.nokia.com/1967 Reviewed-by: Qt Sanity Bot --- src/corelib/tools/qstringbuilder.h | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 6d998b62aa..63c487ef56 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -364,6 +364,27 @@ template <> struct QConcatenable : private QAbstractConcatenable } }; +template struct QConcatenable > : private QAbstractConcatenable +{ + typedef QConstByteArrayDataPtr type; + typedef QByteArray ConvertTo; + enum { ExactSize = false }; + static int size(const type &) { return N; } +#ifndef QT_NO_CAST_FROM_ASCII + static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out) + { + // adding 1 because convertFromAscii expects the size including the null-termination + QAbstractConcatenable::convertFromAscii(a.ptr->data, N + 1, out); + } +#endif + static inline void appendTo(const type &ba, char *&out) + { + const char *a = ba.ptr->data; + while (*a) + *out++ = *a++; + } +}; + namespace QtStringBuilder { template struct ConvertToTypeHelper { typedef A ConvertTo; }; -- cgit v1.2.3 From 345a8a67f0a8a1ddb9ed26ec2a12b20728c741da Mon Sep 17 00:00:00 2001 From: Martin Jones Date: Fri, 22 Jul 2011 11:02:19 +1000 Subject: Optimize QMetaObject::property(). Avoid using QByteArray. Change-Id: I7216bc88efdd6e4e57d84b8c45e7c38119dc7092 Reviewed-on: http://codereview.qt.nokia.com/2000 Reviewed-by: Qt Sanity Bot Reviewed-by: Michael Goddard --- src/corelib/kernel/qmetaobject.cpp | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp index c8ac15c1fa..b6de002cf4 100644 --- a/src/corelib/kernel/qmetaobject.cpp +++ b/src/corelib/kernel/qmetaobject.cpp @@ -859,20 +859,31 @@ QMetaProperty QMetaObject::property(int index) const if (flags & EnumOrFlag) { result.menum = enumerator(indexOfEnumerator(type)); if (!result.menum.isValid()) { - QByteArray enum_name = type; - QByteArray scope_name = d.stringdata; - int s = enum_name.lastIndexOf("::"); - if (s > 0) { - scope_name = enum_name.left(s); - enum_name = enum_name.mid(s + 2); + const char *enum_name = type; + const char *scope_name = d.stringdata; + char *scope_buffer = 0; + + const char *colon = strrchr(enum_name, ':'); + // ':' will always appear in pairs + Q_ASSERT(colon <= enum_name || *(colon-1) == ':'); + if (colon > enum_name) { + int len = colon-enum_name-1; + scope_buffer = (char *)qMalloc(len+1); + qMemCopy(scope_buffer, enum_name, len); + scope_buffer[len] = '\0'; + scope_name = scope_buffer; + enum_name = colon+1; } + const QMetaObject *scope = 0; - if (scope_name == "Qt") + if (qstrcmp(scope_name, "Qt") == 0) scope = &QObject::staticQtMetaObject; else scope = QMetaObject_findMetaObject(this, scope_name); if (scope) result.menum = scope->enumerator(scope->indexOfEnumerator(enum_name)); + if (scope_buffer) + qFree(scope_buffer); } } } -- cgit v1.2.3 From 769f5223425e24d4305c94482580970dea1e63c8 Mon Sep 17 00:00:00 2001 From: Ritt Konstantin Date: Thu, 21 Jul 2011 10:20:06 +0200 Subject: remove Qt3 leftovers Merge-request: 22 Reviewed-by: Olivier Goffart Change-Id: I5d25fb05894d9baa645f97946e1f9aaa1622c876 Reviewed-on: http://codereview.qt.nokia.com/1925 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qchar.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/tools/qchar.cpp b/src/corelib/tools/qchar.cpp index 00261daa95..736bc63b11 100644 --- a/src/corelib/tools/qchar.cpp +++ b/src/corelib/tools/qchar.cpp @@ -317,8 +317,6 @@ QT_BEGIN_NAMESPACE \value Vertical \value Wide - \omitvalue Single - \sa decomposition() */ @@ -382,12 +380,6 @@ QT_BEGIN_NAMESPACE \value ByteOrderSwapped \value ParagraphSeparator \value LineSeparator - - \omitvalue null - \omitvalue replacement - \omitvalue byteOrderMark - \omitvalue byteOrderSwapped - \omitvalue nbsp */ /*! @@ -957,7 +949,7 @@ QString QChar::decomposition(uint ucs4) /*! Returns the tag defining the composition of the character. Returns - QChar::Single if no decomposition exists. + QChar::NoDecomposition if no decomposition exists. */ QChar::Decomposition QChar::decompositionTag() const { @@ -967,7 +959,7 @@ QChar::Decomposition QChar::decompositionTag() const /*! \overload Returns the tag defining the composition of the UCS-4-encoded character - specified by \a ucs4. Returns QChar::Single if no decomposition exists. + specified by \a ucs4. Returns QChar::NoDecomposition if no decomposition exists. */ QChar::Decomposition QChar::decompositionTag(uint ucs4) { @@ -1232,7 +1224,6 @@ ushort QChar::toCaseFolded(ushort ucs2) return ucs2 + qGetProp(ucs2)->caseFoldDiff; } - /*! \fn char QChar::toLatin1() const -- cgit v1.2.3 From 7fc3203062f27f582de84420fa0b519c58b5d1ff Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Thu, 21 Jul 2011 16:39:55 +0200 Subject: QAbstractConcatenable::convertFromAscii: make len the actual length Before, it was the length + 1, to include the ending \0 (for historical reasons) Having it the actual length is more intuitive and less error prone Also added QT_ASCII_CAST_WARN to QConcatenable::appendTo to show the warnig that convertion from ascii to qstring occurs. Change-Id: Ie7c8552b6b4e7ccb393cb09f5f0ca9b00336c714 Reviewed-by: thiago Reviewed-on: http://codereview.qt.nokia.com/1988 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qstringbuilder.cpp | 5 ++--- src/corelib/tools/qstringbuilder.h | 12 +++++------- 2 files changed, 7 insertions(+), 10 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/tools/qstringbuilder.cpp b/src/corelib/tools/qstringbuilder.cpp index 4c6848498b..7c1bde4ac7 100644 --- a/src/corelib/tools/qstringbuilder.cpp +++ b/src/corelib/tools/qstringbuilder.cpp @@ -108,13 +108,12 @@ QT_BEGIN_NAMESPACE */ /*! \internal - Note: The len contains the ending \0 */ void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out) { #ifndef QT_NO_TEXTCODEC if (QString::codecForCStrings && len) { - QString tmp = QString::fromAscii(a, len > 0 ? len - 1 : -1); + QString tmp = QString::fromAscii(a, len > 0 ? len : -1); memcpy(out, reinterpret_cast(tmp.constData()), sizeof(QChar) * tmp.size()); out += tmp.length(); return; @@ -126,7 +125,7 @@ void QAbstractConcatenable::convertFromAscii(const char *a, int len, QChar *&out while (*a) *out++ = QLatin1Char(*a++); } else { - for (int i = 0; i < len - 1; ++i) + for (int i = 0; i < len; ++i) *out++ = QLatin1Char(a[i]); } } diff --git a/src/corelib/tools/qstringbuilder.h b/src/corelib/tools/qstringbuilder.h index 63c487ef56..30b81c42f4 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -294,7 +294,7 @@ template struct QConcatenable : private QAbstractConcatenable #ifndef QT_NO_CAST_FROM_ASCII static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) { - QAbstractConcatenable::convertFromAscii(a, N, out); + QAbstractConcatenable::convertFromAscii(a, N - 1, out); } #endif static inline void appendTo(const char a[N], char *&out) @@ -313,7 +313,7 @@ template struct QConcatenable : private QAbstractConcaten #ifndef QT_NO_CAST_FROM_ASCII static inline void QT_ASCII_CAST_WARN appendTo(const char a[N], QChar *&out) { - QAbstractConcatenable::convertFromAscii(a, N, out); + QAbstractConcatenable::convertFromAscii(a, N - 1, out); } #endif static inline void appendTo(const char a[N], char *&out) @@ -349,10 +349,9 @@ template <> struct QConcatenable : private QAbstractConcatenable enum { ExactSize = false }; static int size(const QByteArray &ba) { return ba.size(); } #ifndef QT_NO_CAST_FROM_ASCII - static inline void appendTo(const QByteArray &ba, QChar *&out) + static inline QT_ASCII_CAST_WARN void appendTo(const QByteArray &ba, QChar *&out) { - // adding 1 because convertFromAscii expects the size including the null-termination - QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size() + 1, out); + QAbstractConcatenable::convertFromAscii(ba.constData(), ba.size(), out); } #endif static inline void appendTo(const QByteArray &ba, char *&out) @@ -373,8 +372,7 @@ template struct QConcatenable > : private QAbs #ifndef QT_NO_CAST_FROM_ASCII static inline QT_ASCII_CAST_WARN void appendTo(const type &a, QChar *&out) { - // adding 1 because convertFromAscii expects the size including the null-termination - QAbstractConcatenable::convertFromAscii(a.ptr->data, N + 1, out); + QAbstractConcatenable::convertFromAscii(a.ptr->data, N, out); } #endif static inline void appendTo(const type &ba, char *&out) -- cgit v1.2.3 From b949b17c3cb7b6752bc8daf2834415163792a76c Mon Sep 17 00:00:00 2001 From: Kim Motoyoshi Kalland Date: Thu, 21 Jul 2011 18:47:26 +0200 Subject: Changed QLibrary::resolve() to return a function pointer. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to the C++ standard, there is no guarantee that you can cast between function pointers and void pointers without data loss (section 5.2.10-6). Change-Id: I27f4d835e4c8ca8ecca0d76cfea9ce34491956bd Reviewed-on: http://codereview.qt.nokia.com/1995 Reviewed-by: Qt Sanity Bot Reviewed-by: João Abecasis --- src/corelib/global/qglobal.cpp | 7 +++++++ src/corelib/global/qglobal.h | 2 ++ src/corelib/plugin/qlibrary.cpp | 10 +++++----- src/corelib/plugin/qlibrary.h | 8 ++++---- src/corelib/plugin/qlibrary_p.h | 4 ++-- src/corelib/plugin/qlibrary_unix.cpp | 14 +++++++------- src/corelib/plugin/qlibrary_win.cpp | 8 ++++---- src/corelib/plugin/qsystemlibrary_p.h | 8 ++++---- src/corelib/tools/qharfbuzz.cpp | 2 +- 9 files changed, 36 insertions(+), 27 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/global/qglobal.cpp b/src/corelib/global/qglobal.cpp index a59cbf9382..452679c7d7 100644 --- a/src/corelib/global/qglobal.cpp +++ b/src/corelib/global/qglobal.cpp @@ -718,6 +718,13 @@ QT_BEGIN_NAMESPACE \sa QtMsgHandler, qInstallMsgHandler() */ +/*! \typedef QFunctionPointer + \relates + + This is a typedef for \c{void (*)()}, a pointer to a function that takes + no arguments and returns void. +*/ + /*! \macro qint64 Q_INT64_C(literal) \relates diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 63333b6233..6dfe805a92 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -1807,6 +1807,8 @@ Q_CORE_EXPORT void qt_message_output(QtMsgType, const char *buf); typedef void (*QtMsgHandler)(QtMsgType, const char *); Q_CORE_EXPORT QtMsgHandler qInstallMsgHandler(QtMsgHandler); +typedef void (*QFunctionPointer)(); + #if !defined(Q_UNIMPLEMENTED) # define Q_UNIMPLEMENTED() qWarning("%s:%d: %s: Unimplemented code.", __FILE__, __LINE__, Q_FUNC_INFO) #endif diff --git a/src/corelib/plugin/qlibrary.cpp b/src/corelib/plugin/qlibrary.cpp index 314ccd7861..45515f32e1 100644 --- a/src/corelib/plugin/qlibrary.cpp +++ b/src/corelib/plugin/qlibrary.cpp @@ -447,7 +447,7 @@ QLibraryPrivate::~QLibraryPrivate() } } -void *QLibraryPrivate::resolve(const char *symbol) +QFunctionPointer QLibraryPrivate::resolve(const char *symbol) { if (!pHnd) return 0; @@ -1129,7 +1129,7 @@ void QLibrary::setFileNameAndVersion(const QString &fileName, const QString &ver Note: In Symbian resolving with symbol names works only if the loaded library was built as STDDLL. Otherwise, the ordinals must be used. */ -void *QLibrary::resolve(const char *symbol) +QFunctionPointer QLibrary::resolve(const char *symbol) { if (!isLoaded() && !load()) return 0; @@ -1152,7 +1152,7 @@ void *QLibrary::resolve(const char *symbol) \sa resolve() */ -void *QLibrary::resolve(const QString &fileName, const char *symbol) +QFunctionPointer QLibrary::resolve(const QString &fileName, const char *symbol) { QLibrary library(fileName); return library.resolve(symbol); @@ -1175,7 +1175,7 @@ void *QLibrary::resolve(const QString &fileName, const char *symbol) \sa resolve() */ -void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) +QFunctionPointer QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) { QLibrary library(fileName, verNum); return library.resolve(symbol); @@ -1199,7 +1199,7 @@ void *QLibrary::resolve(const QString &fileName, int verNum, const char *symbol) \sa resolve() */ -void *QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol) +QFunctionPointer QLibrary::resolve(const QString &fileName, const QString &version, const char *symbol) { QLibrary library(fileName, version); return library.resolve(symbol); diff --git a/src/corelib/plugin/qlibrary.h b/src/corelib/plugin/qlibrary.h index 0154e949b3..e3f557dd7d 100644 --- a/src/corelib/plugin/qlibrary.h +++ b/src/corelib/plugin/qlibrary.h @@ -79,10 +79,10 @@ public: explicit QLibrary(const QString& fileName, const QString &version, QObject *parent = 0); ~QLibrary(); - void *resolve(const char *symbol); - static void *resolve(const QString &fileName, const char *symbol); - static void *resolve(const QString &fileName, int verNum, const char *symbol); - static void *resolve(const QString &fileName, const QString &version, const char *symbol); + QFunctionPointer resolve(const char *symbol); + static QFunctionPointer resolve(const QString &fileName, const char *symbol); + static QFunctionPointer resolve(const QString &fileName, int verNum, const char *symbol); + static QFunctionPointer resolve(const QString &fileName, const QString &version, const char *symbol); bool load(); bool unload(); diff --git a/src/corelib/plugin/qlibrary_p.h b/src/corelib/plugin/qlibrary_p.h index 44860f4b23..12d625050f 100644 --- a/src/corelib/plugin/qlibrary_p.h +++ b/src/corelib/plugin/qlibrary_p.h @@ -87,7 +87,7 @@ public: bool loadPlugin(); // loads and resolves instance bool unload(); void release(); - void *resolve(const char *); + QFunctionPointer resolve(const char *); static QLibraryPrivate *findOrCreate(const QString &fileName, const QString &version = QString()); @@ -108,7 +108,7 @@ private: bool load_sys(); bool unload_sys(); - void *resolve_sys(const char *); + QFunctionPointer resolve_sys(const char *); QAtomicInt libraryRefCount; QAtomicInt libraryUnloadCount; diff --git a/src/corelib/plugin/qlibrary_unix.cpp b/src/corelib/plugin/qlibrary_unix.cpp index 0a7e841519..d3b08e1acf 100644 --- a/src/corelib/plugin/qlibrary_unix.cpp +++ b/src/corelib/plugin/qlibrary_unix.cpp @@ -267,29 +267,29 @@ bool QLibraryPrivate::unload_sys() } #ifdef Q_OS_MAC -Q_CORE_EXPORT void *qt_mac_resolve_sys(void *handle, const char *symbol) +Q_CORE_EXPORT QFunctionPointer qt_mac_resolve_sys(void *handle, const char *symbol) { - return dlsym(handle, symbol); + return QFunctionPointer(dlsym(handle, symbol)); } #endif -void* QLibraryPrivate::resolve_sys(const char* symbol) +QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) { #if defined(QT_AOUT_UNDERSCORE) // older a.out systems add an underscore in front of symbols char* undrscr_symbol = new char[strlen(symbol)+2]; undrscr_symbol[0] = '_'; strcpy(undrscr_symbol+1, symbol); - void* address = dlsym(pHnd, undrscr_symbol); + QFunctionPointer address = QFunctionPointer(dlsym(pHnd, undrscr_symbol)); delete [] undrscr_symbol; #elif defined(QT_HPUX_LD) - void* address = 0; + QFunctionPointer address = 0; if (shl_findsym((shl_t*)&pHnd, symbol, TYPE_UNDEFINED, &address) < 0) address = 0; #elif defined (QT_NO_DYNAMIC_LIBRARY) - void *address = 0; + QFunctionPointer address = 0; #else - void* address = dlsym(pHnd, symbol); + QFunctionPointer address = QFunctionPointer(dlsym(pHnd, symbol)); #endif if (!address) { errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( diff --git a/src/corelib/plugin/qlibrary_win.cpp b/src/corelib/plugin/qlibrary_win.cpp index 667d9cca45..4eeb2fc441 100644 --- a/src/corelib/plugin/qlibrary_win.cpp +++ b/src/corelib/plugin/qlibrary_win.cpp @@ -113,12 +113,12 @@ bool QLibraryPrivate::unload_sys() return true; } -void* QLibraryPrivate::resolve_sys(const char* symbol) +QFunctionPointer QLibraryPrivate::resolve_sys(const char* symbol) { #ifdef Q_OS_WINCE - void* address = (void*)GetProcAddress(pHnd, (const wchar_t*)QString::fromLatin1(symbol).utf16()); + FARPROC address = GetProcAddress(pHnd, (const wchar_t*)QString::fromLatin1(symbol).utf16()); #else - void* address = (void*)GetProcAddress(pHnd, symbol); + FARPROC address = GetProcAddress(pHnd, symbol); #endif if (!address) { errorString = QLibrary::tr("Cannot resolve symbol \"%1\" in %2: %3").arg( @@ -126,6 +126,6 @@ void* QLibraryPrivate::resolve_sys(const char* symbol) } else { errorString.clear(); } - return address; + return QFunctionPointer(address); } QT_END_NAMESPACE diff --git a/src/corelib/plugin/qsystemlibrary_p.h b/src/corelib/plugin/qsystemlibrary_p.h index f20d0b6b9d..3298f05b8f 100644 --- a/src/corelib/plugin/qsystemlibrary_p.h +++ b/src/corelib/plugin/qsystemlibrary_p.h @@ -78,20 +78,20 @@ public: return (m_handle != 0); } - void *resolve(const char *symbol) + QFunctionPointer resolve(const char *symbol) { if (!m_didLoad) load(); if (!m_handle) return 0; #ifdef Q_OS_WINCE - return (void*)GetProcAddress(m_handle, (const wchar_t*)QString::fromLatin1(symbol).utf16()); + return QFunctionPointer(GetProcAddress(m_handle, (const wchar_t*)QString::fromLatin1(symbol).utf16())); #else - return (void*)GetProcAddress(m_handle, symbol); + return QFunctionPointer(GetProcAddress(m_handle, symbol)); #endif } - static void *resolve(const QString &libraryName, const char *symbol) + static QFunctionPointer resolve(const QString &libraryName, const char *symbol) { return QSystemLibrary(libraryName).resolve(symbol); } diff --git a/src/corelib/tools/qharfbuzz.cpp b/src/corelib/tools/qharfbuzz.cpp index 68f780d9fd..324cd481ed 100644 --- a/src/corelib/tools/qharfbuzz.cpp +++ b/src/corelib/tools/qharfbuzz.cpp @@ -102,7 +102,7 @@ HB_UChar16 HB_GetMirroredChar(HB_UChar16 ch) return QChar::mirroredChar(ch); } -void *HB_Library_Resolve(const char *library, int version, const char *symbol) +void (*HB_Library_Resolve(const char *library, int version, const char *symbol))() { #ifdef QT_NO_LIBRARY return 0; -- cgit v1.2.3 From cec00a2dda6f843cde8754141ff4ab7e209c6b99 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Mon, 25 Jul 2011 13:12:00 +0200 Subject: Add the missing function in bootstrap MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit (required for the metatype changes) Change-Id: I0e3c73e7828493b4f03ec6439ec80b1c8c2bf377 Reviewed-on: http://codereview.qt.nokia.com/2105 Reviewed-by: Qt Sanity Bot Reviewed-by: Jędrzej Nowacki --- src/corelib/arch/qatomic_bootstrap.h | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) (limited to 'src/corelib') diff --git a/src/corelib/arch/qatomic_bootstrap.h b/src/corelib/arch/qatomic_bootstrap.h index ecce758e71..74dc6cfbb2 100644 --- a/src/corelib/arch/qatomic_bootstrap.h +++ b/src/corelib/arch/qatomic_bootstrap.h @@ -75,13 +75,34 @@ inline bool QBasicAtomicInt::testAndSetRelease(int expectedValue, int newValue) return testAndSetOrdered(expectedValue, newValue); } -inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +inline bool QBasicAtomicInt::testAndSetRelaxed(int expectedValue, int newValue) +{ + return testAndSetOrdered(expectedValue, newValue); +} + +inline int QBasicAtomicInt::fetchAndAddOrdered(int valueToAdd) { int returnValue = _q_value; _q_value += valueToAdd; return returnValue; } +inline int QBasicAtomicInt::fetchAndAddAcquire(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelease(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + +inline int QBasicAtomicInt::fetchAndAddRelaxed(int valueToAdd) +{ + return fetchAndAddOrdered(valueToAdd); +} + + template Q_INLINE_TEMPLATE bool QBasicAtomicPointer::testAndSetOrdered(T *expectedValue, T *newValue) { -- cgit v1.2.3 From 6b82798ee73dc8aac6f6a6c4c12ff291d6d7e9e1 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 19 Jul 2011 15:53:32 +0200 Subject: Add QFreeList as an internal class This is a generic implementation of the lock-free free list found in qabstracteventdispatcher.cpp. Use next() to get the next free entry in the list, and release(id) when done with the id. This version is templated and allows having a payload which can be accessed using the id returned by next(). The payload is allocated and deallocated automatically by the free list, but *NOT* when calling next()/release(). Initialization should be done by code needing it after next() returns. Likewise, cleanup should happen before calling release(). It is possible to have use 'void' as the payload type, in which case the free list only contains indexes to the next free entry. Autotest included. Change-Id: Ifd12a961d47f3d76593c45061f72e55c9b80a43b Reviewed-on: http://codereview.qt.nokia.com/2160 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qfreelist.cpp | 62 +++++++++ src/corelib/tools/qfreelist_p.h | 294 ++++++++++++++++++++++++++++++++++++++++ src/corelib/tools/tools.pri | 2 + 3 files changed, 358 insertions(+) create mode 100644 src/corelib/tools/qfreelist.cpp create mode 100644 src/corelib/tools/qfreelist_p.h (limited to 'src/corelib') diff --git a/src/corelib/tools/qfreelist.cpp b/src/corelib/tools/qfreelist.cpp new file mode 100644 index 0000000000..63e37ec249 --- /dev/null +++ b/src/corelib/tools/qfreelist.cpp @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qfreelist_p.h" + +// default sizes and offsets (no need to define these when customizing) +enum { + Offset0 = 0x00000000, + Offset1 = 0x00008000, + Offset2 = 0x00080000, + Offset3 = 0x00800000, + + Size0 = Offset1 - Offset0, + Size1 = Offset2 - Offset1, + Size2 = Offset3 - Offset2, + Size3 = QFreeListDefaultConstants::MaxIndex - Offset3 +}; + +const int QFreeListDefaultConstants::Sizes[QFreeListDefaultConstants::BlockCount] = { + Size0, + Size1, + Size2, + Size3 +}; diff --git a/src/corelib/tools/qfreelist_p.h b/src/corelib/tools/qfreelist_p.h new file mode 100644 index 0000000000..74ba3b587e --- /dev/null +++ b/src/corelib/tools/qfreelist_p.h @@ -0,0 +1,294 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QFREELIST_P_H +#define QFREELIST_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include + +QT_BEGIN_HEADER + +QT_BEGIN_NAMESPACE + +QT_MODULE(Core) + +/*! \internal + + Element in a QFreeList. ConstReferenceType and ReferenceType are used as + the return values for QFreeList::at() and QFreeList::operator[](). Contains + the real data storage (_t) and the id of the next free element (next). + + Note: the t() functions should be used to access the data, not _t. +*/ +template +struct QFreeListElement +{ + typedef const T &ConstReferenceType; + typedef T &ReferenceType; + + T _t; + int next; + + inline ConstReferenceType t() const { return _t; } + inline ReferenceType t() { return _t; } +}; + +/*! \internal + + Element in a QFreeList without a paylout. ConstReferenceType and + ReferenceType are void, the t() functions return void and are empty. +*/ +template <> +struct QFreeListElement +{ + typedef void ConstReferenceType; + typedef void ReferenceType; + + int next; + + inline void t() const { } + inline void t() { } +}; + +/*! \internal + + Defines default constants used by QFreeList: + + - The initial value returned by QFreeList::next() is zero. + + - QFreeList allows for up to 16777216 elements in QFreeList and uses the top + 8 bits to store a serial counter for ABA protection. + + - QFreeList will make a maximum of 4 allocations (blocks), with each + successive block larger than the previous. + + - Sizes static int[] array to define the size of each block. + + It is possible to define your own constants struct/class and give this to + QFreeList to customize/tune the behavior. +*/ +struct Q_AUTOTEST_EXPORT QFreeListDefaultConstants +{ + // used by QFreeList, make sure to define all of when customizing + enum { + InitialNextValue = 0, + IndexMask = 0x00ffffff, + SerialMask = ~IndexMask & ~0x80000000, + SerialCounter = IndexMask + 1, + MaxIndex = IndexMask, + BlockCount = 4, + }; + + static const int Sizes[BlockCount]; +}; + +/*! \internal + + This is a generic implementation of a lock-free free list. Use next() to + get the next free entry in the list, and release(id) when done with the id. + + This version is templated and allows having a payload of type T which can + be accessed using the id returned by next(). The payload is allocated and + deallocated automatically by the free list, but *NOT* when calling + next()/release(). Initialization should be done by code needing it after + next() returns. Likewise, cleanup() should happen before calling release(). + It is possible to have use 'void' as the payload type, in which case the + free list only contains indexes to the next free entry. + + The ConstantsType type defaults to QFreeListDefaultConstants above. You can + define your custom ConstantsType, see above for details on what needs to be + available. +*/ +template +class QFreeList +{ + typedef T ValueType; + typedef QFreeListElement ElementType; + typedef typename ElementType::ConstReferenceType ConstReferenceType; + typedef typename ElementType::ReferenceType ReferenceType; + + // return which block the index \a x falls in, and modify \a x to be the index into that block + static inline int blockfor(int &x) + { + for (int i = 0; i < ConstantsType::BlockCount; ++i) { + int size = ConstantsType::Sizes[i]; + if (x < size) + return i; + x -= size; + } + Q_ASSERT(false); + return -1; + } + + // allocate a block of the given \a size, initialized starting with the given \a offset + static inline ElementType *allocate(int offset, int size) + { + // qDebug("QFreeList: allocating %d elements (%ld bytes) with offset %d", size, size * sizeof(ElementType), offset); + ElementType *v = new ElementType[size]; + for (int i = 0; i < size; ++i) + v[i].next = offset + i + 1; + return v; + } + + // take the current serial number from \a o, increment it, and store it in \a n + static inline int incrementserial(int o, int n) + { + return (n & ConstantsType::IndexMask) | ((o + ConstantsType::SerialCounter) & ConstantsType::SerialMask); + } + + // the blocks + QAtomicPointer _v[ConstantsType::BlockCount]; + // the next free id + QAtomicInt _next; + + // QFreeList is not copyable + Q_DISABLE_COPY(QFreeList) + +public: + inline QFreeList(); + inline ~QFreeList(); + + // returns the payload for the given index \a x + inline ConstReferenceType at(int x) const; + inline ReferenceType operator[](int x); + + /* + Return the next free id. Use this id to access the payload (see above). + Call release(id) when done using the id. + */ + inline int next(); + inline void release(int id); +}; + +template +inline QFreeList::QFreeList() + : _next(ConstantsType::InitialNextValue) +{ } + +template +inline QFreeList::~QFreeList() +{ + for (int i = 0; i < ConstantsType::BlockCount; ++i) + delete [] static_cast(_v[i]); +} + +template +inline typename QFreeList::ConstReferenceType QFreeList::at(int x) const +{ + const int block = blockfor(x); + return _v[block][x].t(); +} + +template +inline typename QFreeList::ReferenceType QFreeList::operator[](int x) +{ + const int block = blockfor(x); + return _v[block][x].t(); +} + +template +inline int QFreeList::next() +{ + int id, newid, at; + ElementType *v; + do { + id = _next; // .loadAqcuire(); + + at = id & ConstantsType::IndexMask; + const int block = blockfor(at); + v = _v[block]; + + if (!v) { + v = allocate((id & ConstantsType::IndexMask) - at, ConstantsType::Sizes[block]); + if (!_v[block].testAndSetRelease(0, v)) { + // race with another thread lost + delete [] v; + v = _v[block]; + Q_ASSERT(v != 0); + } + } + + newid = v[at].next | (id & ~ConstantsType::IndexMask); + } while (!_next.testAndSetRelease(id, newid)); + // qDebug("QFreeList::next(): returning %d (_next now %d, serial %d)", + // id & ConstantsType::IndexMask, + // newid & ConstantsType::IndexMask, + // (newid & ~ConstantsType::IndexMask) >> 24); + return id & ConstantsType::IndexMask; +} + +template +inline void QFreeList::release(int id) +{ + int at = id & ConstantsType::IndexMask; + const int block = blockfor(at); + ElementType *v = _v[block]; + + int x, newid; + do { + x = _next; // .loadAcquire(); + v[at].next = x & ConstantsType::IndexMask; + + newid = incrementserial(x, id); + } while (!_next.testAndSetRelease(x, newid)); + // qDebug("QFreeList::release(%d): _next now %d (was %d), serial %d", + // id & ConstantsType::IndexMask, + // newid & ConstantsType::IndexMask, + // x & ConstantsType::IndexMask, + // (newid & ~ConstantsType::IndexMask) >> 24); +} + +QT_END_NAMESPACE + +QT_END_HEADER + +#endif // QFREELIST_P_H diff --git a/src/corelib/tools/tools.pri b/src/corelib/tools/tools.pri index f5b38eb1c0..13b597d513 100644 --- a/src/corelib/tools/tools.pri +++ b/src/corelib/tools/tools.pri @@ -13,6 +13,7 @@ HEADERS += \ tools/qdatetime.h \ tools/qdatetime_p.h \ tools/qeasingcurve.h \ + tools/qfreelist_p.h \ tools/qhash.h \ tools/qline.h \ tools/qlinkedlist.h \ @@ -61,6 +62,7 @@ SOURCES += \ tools/qdatetime.cpp \ tools/qeasingcurve.cpp \ tools/qelapsedtimer.cpp \ + tools/qfreelist.cpp \ tools/qhash.cpp \ tools/qline.cpp \ tools/qlinkedlist.cpp \ -- cgit v1.2.3 From 33a55c5661299085c5e381f9aaf99b74ccc7b6b1 Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Tue, 19 Jul 2011 16:27:42 +0200 Subject: Use QFreeList for timer id allocation The timer id allocator doesn't need a paylod (hence T=void), but we want to tune the allocation 'strategy.' We allocate a maximum of 6 blocks (like before), but the first block is twice as large as before and is not static writable anymore. The initial value is 1 (0 is not a valid timer id), but otherwise the constants are the same as the defaults. Change-Id: Ied49ff4d7a6a8d69bc8c7bfa5475e4111446659f Reviewed-on: http://codereview.qt.nokia.com/2161 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/kernel/qabstracteventdispatcher.cpp | 210 +++++------------------- 1 file changed, 43 insertions(+), 167 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qabstracteventdispatcher.cpp b/src/corelib/kernel/qabstracteventdispatcher.cpp index 1b0707605c..10de2caf62 100644 --- a/src/corelib/kernel/qabstracteventdispatcher.cpp +++ b/src/corelib/kernel/qabstracteventdispatcher.cpp @@ -45,109 +45,10 @@ #include "qthread.h" #include #include +#include QT_BEGIN_NAMESPACE -// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers -static const int TimerIdMask = 0x00ffffff; -static const int TimerSerialMask = ~TimerIdMask & ~0x80000000; -static const int TimerSerialCounter = TimerIdMask + 1; -static const int MaxTimerId = TimerIdMask; - -static int FirstBucket[] = { - 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 -}; - -enum { - FirstBucketOffset = 0, - SecondBucketOffset = sizeof(FirstBucket) / sizeof(FirstBucket[0]), - ThirdBucketOffset = 0x100, - FourthBucketOffset = 0x1000, - FifthBucketOffset = 0x10000, - SixthBucketOffset = 0x100000 -}; - -enum { - FirstBucketSize = SecondBucketOffset, - SecondBucketSize = ThirdBucketOffset - SecondBucketOffset, - ThirdBucketSize = FourthBucketOffset - ThirdBucketOffset, - FourthBucketSize = FifthBucketOffset - FourthBucketOffset, - FifthBucketSize = SixthBucketOffset - FifthBucketOffset, - SixthBucketSize = MaxTimerId - SixthBucketOffset -}; - -static const int BucketSize[] = { - FirstBucketSize, SecondBucketSize, ThirdBucketSize, - FourthBucketSize, FifthBucketSize, SixthBucketSize -}; -enum { NumberOfBuckets = sizeof(BucketSize) / sizeof(BucketSize[0]) }; - -static const int BucketOffset[] = { - FirstBucketOffset, SecondBucketOffset, ThirdBucketOffset, - FourthBucketOffset, FifthBucketOffset, SixthBucketOffset -}; - -static QBasicAtomicPointer timerIds[] = - { Q_BASIC_ATOMIC_INITIALIZER(FirstBucket), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0), - Q_BASIC_ATOMIC_INITIALIZER(0) }; - -static void timerIdsDestructorFunction() -{ - // start at one, the first bucket is pre-allocated - for (int i = 1; i < NumberOfBuckets; ++i) - delete [] static_cast(timerIds[i]); -} -Q_DESTRUCTOR_FUNCTION(timerIdsDestructorFunction) - -static QBasicAtomicInt nextFreeTimerId = Q_BASIC_ATOMIC_INITIALIZER(1); - -// avoid the ABA-problem by using 7 of the top 8 bits of the timerId as a serial number -static inline int prepareNewValueWithSerialNumber(int oldId, int newId) -{ - return (newId & TimerIdMask) | ((oldId + TimerSerialCounter) & TimerSerialMask); -} - -namespace { - template struct QStaticAssertType; - template<> struct QStaticAssertType { enum { Value = 1 }; }; -} -#define q_static_assert(expr) (void)QStaticAssertType::Value - -static inline int bucketOffset(int timerId) -{ - q_static_assert(sizeof BucketSize == sizeof BucketOffset); - q_static_assert(sizeof(timerIds) / sizeof(timerIds[0]) == NumberOfBuckets); - - for (int i = 0; i < NumberOfBuckets; ++i) { - if (timerId < BucketSize[i]) - return i; - timerId -= BucketSize[i]; - } - qFatal("QAbstractEventDispatcher: INTERNAL ERROR, timer ID %d is too large", timerId); - return -1; -} - -static inline int bucketIndex(int bucket, int timerId) -{ - return timerId - BucketOffset[bucket]; -} - -static inline int *allocateBucket(int bucket) -{ - // allocate a new bucket - const int size = BucketSize[bucket]; - const int offset = BucketOffset[bucket]; - int *b = new int[size]; - for (int i = 0; i != size; ++i) - b[i] = offset + i + 1; - return b; -} - void QAbstractEventDispatcherPrivate::init() { Q_Q(QAbstractEventDispatcher); @@ -158,79 +59,54 @@ void QAbstractEventDispatcherPrivate::init() } } -// Timer IDs are implemented using a free-list; -// there's a vector initialized with: -// X[i] = i + 1 -// and nextFreeTimerId starts with 1. -// -// Allocating a timer ID involves taking the ID from -// X[nextFreeTimerId] -// updating nextFreeTimerId to this value and returning the old value -// -// When the timer ID is allocated, its cell in the vector is unused (it's a -// free list). As an added protection, we use the cell to store an invalid -// (negative) value that we can later check for integrity. -// -// (continues below). +// we allow for 2^24 = 8^8 = 16777216 simultaneously running timers +struct QtTimerIdFreeListConstants : public QFreeListDefaultConstants +{ + enum + { + InitialNextValue = 1, + BlockCount = 6, + }; + + static const int Sizes[BlockCount]; +}; + +enum { + Offset0 = 0x00000000, + Offset1 = 0x00000040, + Offset2 = 0x00000100, + Offset3 = 0x00001000, + Offset4 = 0x00010000, + Offset5 = 0x00100000, + + Size0 = Offset1 - Offset0, + Size1 = Offset2 - Offset1, + Size2 = Offset3 - Offset2, + Size3 = Offset4 - Offset3, + Size4 = Offset5 - Offset4, + Size5 = QtTimerIdFreeListConstants::MaxIndex - Offset5 +}; + +const int QtTimerIdFreeListConstants::Sizes[QtTimerIdFreeListConstants::BlockCount] = { + Size0, + Size1, + Size2, + Size3, + Size4, + Size5 +}; + +typedef QFreeList QtTimerIdFreeList; +Q_GLOBAL_STATIC(QtTimerIdFreeList, timerIdFreeList) + int QAbstractEventDispatcherPrivate::allocateTimerId() { - int timerId, newTimerId; - int at, *b; - do { - timerId = nextFreeTimerId; //.loadAcquire(); // ### FIXME Proper memory ordering semantics - - // which bucket are we looking in? - int which = timerId & TimerIdMask; - int bucket = bucketOffset(which); - at = bucketIndex(bucket, which); - b = timerIds[bucket]; - - if (!b) { - // allocate a new bucket - b = allocateBucket(bucket); - if (!timerIds[bucket].testAndSetRelease(0, b)) { - // another thread won the race to allocate the bucket - delete [] b; - b = timerIds[bucket]; - } - } - - newTimerId = prepareNewValueWithSerialNumber(timerId, b[at]); - } while (!nextFreeTimerId.testAndSetRelaxed(timerId, newTimerId)); - - b[at] = -timerId; - - return timerId; + return timerIdFreeList()->next(); } -// Releasing a timer ID requires putting the current ID back in the vector; -// we do it by setting: -// X[timerId] = nextFreeTimerId; -// then we update nextFreeTimerId to the timer we've just released -// -// The extra code in allocateTimerId and releaseTimerId are ABA prevention -// and bucket memory. The buckets are simply to make sure we allocate only -// the necessary number of timers. See above. -// -// ABA prevention simply adds a value to 7 of the top 8 bits when resetting -// nextFreeTimerId. void QAbstractEventDispatcherPrivate::releaseTimerId(int timerId) { - int which = timerId & TimerIdMask; - int bucket = bucketOffset(which); - int at = bucketIndex(bucket, which); - int *b = timerIds[bucket]; - - Q_ASSERT_X(timerId == -b[at], "QAbstractEventDispatcher::releaseTimerId", - "Internal error: timer ID not found"); - - int freeId, newTimerId; - do { - freeId = nextFreeTimerId;//.loadAcquire(); // ### FIXME Proper memory ordering semantics - b[at] = freeId & TimerIdMask; - - newTimerId = prepareNewValueWithSerialNumber(freeId, timerId); - } while (!nextFreeTimerId.testAndSetRelease(freeId, newTimerId)); + timerIdFreeList()->release(timerId); } /*! -- cgit v1.2.3 From d692b8663c062e3b7f146529d29194ca8724f214 Mon Sep 17 00:00:00 2001 From: Jason McDonald Date: Tue, 26 Jul 2011 16:11:03 +1000 Subject: Fix obsolete contact email Replace the old Trolltech contact email address with the current Qt contact email address. Task-number: QTBUG-20370 Change-Id: If5b9c3a044e1ee46264548eea456c704ced8e363 Reviewed-on: http://codereview.qt.nokia.com/2153 Reviewed-by: Qt Sanity Bot Reviewed-by: Rohan McGovern --- src/corelib/global/qglobal.h | 4 ++-- src/corelib/io/qfilesystemwatcher_inotify.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index 6dfe805a92..56022a7e6e 100644 --- a/src/corelib/global/qglobal.h +++ b/src/corelib/global/qglobal.h @@ -281,7 +281,7 @@ namespace QT_NAMESPACE {} # define Q_OS_VXWORKS #elif defined(__MAKEDEPEND__) #else -# error "Qt has not been ported to this OS - talk to qt-bugs@trolltech.com" +# error "Qt has not been ported to this OS - talk to qt-info@nokia.com" #endif #if defined(Q_OS_WIN32) || defined(Q_OS_WIN64) || defined(Q_OS_WINCE) @@ -803,7 +803,7 @@ namespace QT_NAMESPACE {} # define Q_CC_NOKIAX86 #else -# error "Qt has not been tested with this compiler - talk to qt-bugs@trolltech.com" +# error "Qt has not been tested with this compiler - talk to qt-info@nokia.com" #endif diff --git a/src/corelib/io/qfilesystemwatcher_inotify.cpp b/src/corelib/io/qfilesystemwatcher_inotify.cpp index 5c5223eb1c..ef302243da 100644 --- a/src/corelib/io/qfilesystemwatcher_inotify.cpp +++ b/src/corelib/io/qfilesystemwatcher_inotify.cpp @@ -131,7 +131,7 @@ # define __NR_inotify_rm_watch 286 # define __NR_inotify_init1 328 #else -# error "This architecture is not supported. Please talk to qt-bugs@trolltech.com" +# error "This architecture is not supported. Please talk to qt-info@nokia.com" #endif #if !defined(IN_CLOEXEC) && defined(O_CLOEXEC) && defined(__NR_inotify_init1) -- cgit v1.2.3 From 404126d578ee351ec42856e351412d20ff5faf0b Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Wed, 27 Jul 2011 19:01:15 +0200 Subject: Get rid of compiler warnings with MSVC Change-Id: Ibd027c502a5b8bcbfc6dae71c4f244f1080d4064 Reviewed-on: http://codereview.qt.nokia.com/2303 Reviewed-by: Qt Sanity Bot Reviewed-by: Oswald Buddenhagen --- src/corelib/tools/qbytearray.cpp | 21 +++++++++++---------- src/corelib/tools/qbytearray.h | 4 ++-- src/corelib/tools/qstring.cpp | 18 +++++++++--------- 3 files changed, 22 insertions(+), 21 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/tools/qbytearray.cpp b/src/corelib/tools/qbytearray.cpp index 9f21b72bfd..11ebd8a103 100644 --- a/src/corelib/tools/qbytearray.cpp +++ b/src/corelib/tools/qbytearray.cpp @@ -904,7 +904,7 @@ QByteArray &QByteArray::operator=(const char *str) x = const_cast(&shared_empty.ba); } else { int len = qstrlen(str); - if (d->ref != 1 || len > d->alloc || (len < d->size && len < d->alloc >> 1)) + if (d->ref != 1 || len > int(d->alloc) || (len < d->size && len < int(d->alloc) >> 1)) realloc(len); x = d; memcpy(x->data(), str, len + 1); // include null terminator @@ -1432,9 +1432,10 @@ void QByteArray::resize(int size) x->data()[size] = '\0'; d = x; } else { - if (d->ref != 1 || size > d->alloc || (!d->capacityReserved && size < d->size && size < d->alloc >> 1)) + if (d->ref != 1 || size > int(d->alloc) + || (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1)) realloc(qAllocMore(size, sizeof(Data))); - if (d->alloc >= size) { + if (int(d->alloc) >= size) { d->size = size; d->data()[size] = '\0'; } @@ -1563,7 +1564,7 @@ QByteArray &QByteArray::prepend(const char *str) QByteArray &QByteArray::prepend(const char *str, int len) { if (str) { - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(qAllocMore(d->size + len, sizeof(Data))); memmove(d->data()+len, d->data(), d->size); memcpy(d->data(), str, len); @@ -1581,7 +1582,7 @@ QByteArray &QByteArray::prepend(const char *str, int len) QByteArray &QByteArray::prepend(char ch) { - if (d->ref != 1 || d->size + 1 > d->alloc) + if (d->ref != 1 || d->size + 1 > int(d->alloc)) realloc(qAllocMore(d->size + 1, sizeof(Data))); memmove(d->data()+1, d->data(), d->size); d->data()[0] = ch; @@ -1619,7 +1620,7 @@ QByteArray &QByteArray::append(const QByteArray &ba) if ((d == &shared_null.ba || d == &shared_empty.ba) && !IS_RAW_DATA(ba.d)) { *this = ba; } else if (ba.d != &shared_null.ba) { - if (d->ref != 1 || d->size + ba.d->size > d->alloc) + if (d->ref != 1 || d->size + ba.d->size > int(d->alloc)) realloc(qAllocMore(d->size + ba.d->size, sizeof(Data))); memcpy(d->data() + d->size, ba.d->data(), ba.d->size); d->size += ba.d->size; @@ -1653,7 +1654,7 @@ QByteArray& QByteArray::append(const char *str) { if (str) { int len = qstrlen(str); - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(qAllocMore(d->size + len, sizeof(Data))); memcpy(d->data() + d->size, str, len + 1); // include null terminator d->size += len; @@ -1678,7 +1679,7 @@ QByteArray &QByteArray::append(const char *str, int len) if (len < 0) len = qstrlen(str); if (str && len) { - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(qAllocMore(d->size + len, sizeof(Data))); memcpy(d->data() + d->size, str, len); // include null terminator d->size += len; @@ -1695,7 +1696,7 @@ QByteArray &QByteArray::append(const char *str, int len) QByteArray& QByteArray::append(char ch) { - if (d->ref != 1 || d->size + 1 > d->alloc) + if (d->ref != 1 || d->size + 1 > int(d->alloc)) realloc(qAllocMore(d->size + 1, sizeof(Data))); d->data()[d->size++] = ch; d->data()[d->size] = '\0'; @@ -2204,7 +2205,7 @@ QByteArray QByteArray::repeated(int times) const QByteArray result; result.reserve(resultSize); - if (result.d->alloc != resultSize) + if (int(result.d->alloc) != resultSize) return QByteArray(); // not enough memory memcpy(result.d->data(), d->data(), d->size); diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index 4190ffa18a..5cf4c15179 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -439,10 +439,10 @@ inline int QByteArray::capacity() const { return d->alloc; } inline void QByteArray::reserve(int asize) -{ if (d->ref != 1 || asize > d->alloc) realloc(asize); d->capacityReserved = true; } +{ if (d->ref != 1 || asize > int(d->alloc)) realloc(asize); d->capacityReserved = true; } inline void QByteArray::squeeze() -{ if (d->size < d->alloc) realloc(d->size); d->capacityReserved = false; } +{ if (d->size < int(d->alloc)) realloc(d->size); d->capacityReserved = false; } class Q_CORE_EXPORT QByteRef { QByteArray &a; diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp index 9e238193a3..9ce5eead8c 100644 --- a/src/corelib/tools/qstring.cpp +++ b/src/corelib/tools/qstring.cpp @@ -1267,10 +1267,10 @@ void QString::resize(int size) QString::free(d); d = x; } else { - if (d->ref != 1 || size > d->alloc || - (!d->capacityReserved && size < d->size && size < d->alloc >> 1)) + if (d->ref != 1 || size > int(d->alloc) || + (!d->capacityReserved && size < d->size && size < int(d->alloc) >> 1)) realloc(grow(size)); - if (d->alloc >= size) { + if (int(d->alloc) >= size) { d->size = size; d->data()[size] = '\0'; } @@ -1560,7 +1560,7 @@ QString &QString::append(const QString &str) if (d == &shared_null.str) { operator=(str); } else { - if (d->ref != 1 || d->size + str.d->size > d->alloc) + if (d->ref != 1 || d->size + str.d->size > int(d->alloc)) realloc(grow(d->size + str.d->size)); memcpy(d->data() + d->size, str.d->data(), str.d->size * sizeof(QChar)); d->size += str.d->size; @@ -1580,7 +1580,7 @@ QString &QString::append(const QLatin1String &str) const uchar *s = (const uchar *)str.latin1(); if (s) { int len = qstrlen((char *)s); - if (d->ref != 1 || d->size + len > d->alloc) + if (d->ref != 1 || d->size + len > int(d->alloc)) realloc(grow(d->size + len)); ushort *i = d->data() + d->size; while ((*i++ = *s++)) @@ -1623,7 +1623,7 @@ QString &QString::append(const QLatin1String &str) */ QString &QString::append(QChar ch) { - if (d->ref != 1 || d->size + 1 > d->alloc) + if (d->ref != 1 || d->size + 1 > int(d->alloc)) realloc(grow(d->size + 1)); d->data()[d->size++] = ch.unicode(); d->data()[d->size] = '\0'; @@ -3550,8 +3550,8 @@ static QByteArray toLatin1_helper(const QChar *data, int length) const __m128i questionMark = _mm_set1_epi16('?'); // SSE has no compare instruction for unsigned comparison. // The variables must be shiffted + 0x8000 to be compared - const __m128i signedBitOffset = _mm_set1_epi16(0x8000); - const __m128i thresholdMask = _mm_set1_epi16(0xff + 0x8000); + const __m128i signedBitOffset = _mm_set1_epi16(short(0x8000)); + const __m128i thresholdMask = _mm_set1_epi16(short(0xff + 0x8000)); for (int i = 0; i < chunkCount; ++i) { __m128i chunk1 = _mm_loadu_si128((__m128i*)src); // load src += 8; @@ -6152,7 +6152,7 @@ QString QString::repeated(int times) const QString result; result.reserve(resultSize); - if (result.d->alloc != resultSize) + if (int(result.d->alloc) != resultSize) return QString(); // not enough memory memcpy(result.d->data(), d->data(), d->size * sizeof(ushort)); -- cgit v1.2.3 From 85f05924f48c95192787555f0bc025338286d3f5 Mon Sep 17 00:00:00 2001 From: Denis Dzyubenko Date: Mon, 25 Jul 2011 14:38:24 +0200 Subject: Added meta type info for Q[Explicitly]SharedDataPointer Change-Id: I1269630ae5154f7318e1c7ae9fa2014a15234bf4 Reviewed-on: http://codereview.qt.nokia.com/2110 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/tools/qshareddata.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/tools/qshareddata.h b/src/corelib/tools/qshareddata.h index 9b404bdf0c..811b186e8b 100644 --- a/src/corelib/tools/qshareddata.h +++ b/src/corelib/tools/qshareddata.h @@ -279,6 +279,9 @@ namespace std { QT_BEGIN_NAMESPACE #endif +template Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer, Q_MOVABLE_TYPE); +template Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer, Q_MOVABLE_TYPE); + QT_END_NAMESPACE QT_END_HEADER -- cgit v1.2.3 From 78cf553469bbfc0a5b4952d54ffe96566cae266c Mon Sep 17 00:00:00 2001 From: Aaron Kennedy Date: Fri, 29 Jul 2011 13:03:52 +1000 Subject: Flag meta objects generated by QtDBus QtDBus requires a QVariant argument to be passed to property reads and writes. For performance reasons QtDeclarative does not do this. By flagging the meta object as requiring this, QtDeclarative can do so only required. Task-number: QTBUG-15052 Change-Id: I032c946f079523f5f10217ed56642fb315265d9f Reviewed-on: http://codereview.qt.nokia.com/2365 Reviewed-by: Qt Sanity Bot Reviewed-by: Martin Jones --- src/corelib/kernel/qmetaobject_p.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qmetaobject_p.h b/src/corelib/kernel/qmetaobject_p.h index 63605ecadb..5da936aab0 100644 --- a/src/corelib/kernel/qmetaobject_p.h +++ b/src/corelib/kernel/qmetaobject_p.h @@ -101,7 +101,8 @@ enum MethodFlags { }; enum MetaObjectFlags { - DynamicMetaObject = 0x01 + DynamicMetaObject = 0x01, + RequiresVariantMetaObject = 0x02 }; class QMutex; -- cgit v1.2.3 From 86a237929e2b67ce333b635b760e78c628effb60 Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Sat, 2 Jul 2011 15:13:12 +0200 Subject: QMutex is now just a pointer And added a POD QBasicMutex. (QBasicMutex* can safely be static_cast'ed to QMutex*) The d pointer is not anymore always a QMutexPrivate. If d == 0x0: the mutex is unlocked If d == 0x1: the mutex is locked, uncontended On linux: if d == 0x3: the mutex is locked contended, waiting on a futex If d is a pointer, it is a recursive mutex. On non-linux platforms: When a thread tries to lock a mutex for which d == 0x1, it will try to assing it a QMutexPrivated (allocated from a freelist) in order to wait for it. Change-Id: Ie1431cd9402a576fdd9a693cfd747166eebf5622 Reviewed-by: Bradley T. Hughes Reviewed-on: http://codereview.qt.nokia.com/2116 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/kernel/qobject.cpp | 8 +- src/corelib/thread/qmutex.cpp | 435 ++++++++++++++++------------- src/corelib/thread/qmutex.h | 121 +++----- src/corelib/thread/qmutex_linux.cpp | 138 +++++++++ src/corelib/thread/qmutex_mac.cpp | 96 +++++++ src/corelib/thread/qmutex_p.h | 70 +++-- src/corelib/thread/qmutex_unix.cpp | 116 +------- src/corelib/thread/qmutex_win.cpp | 10 +- src/corelib/thread/qorderedmutexlocker_p.h | 12 +- src/corelib/thread/qwaitcondition_unix.cpp | 2 +- src/corelib/thread/qwaitcondition_win.cpp | 2 +- src/corelib/thread/thread.pri | 9 +- 12 files changed, 592 insertions(+), 427 deletions(-) create mode 100644 src/corelib/thread/qmutex_linux.cpp create mode 100644 src/corelib/thread/qmutex_mac.cpp (limited to 'src/corelib') diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index 27edbdacac..ab9314ce53 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -878,7 +878,7 @@ QObject::~QObject() if (c->next) c->next->prev = c->prev; } if (needToUnlock) - m->unlockInline(); + m->unlock(); connectionList.first = c->nextConnectionList; delete c; @@ -902,7 +902,7 @@ QObject::~QObject() bool needToUnlock = QOrderedMutexLocker::relock(signalSlotMutex, m); //the node has maybe been removed while the mutex was unlocked in relock? if (!node || node->sender != sender) { - m->unlockInline(); + m->unlock(); continue; } node->receiver = 0; @@ -912,7 +912,7 @@ QObject::~QObject() node = node->next; if (needToUnlock) - m->unlockInline(); + m->unlock(); } } @@ -3076,7 +3076,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, } if (needToUnlock) - receiverMutex->unlockInline(); + receiverMutex->unlock(); c->receiver = 0; diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 3e3bf8ff13..c90b44be6c 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -49,8 +49,25 @@ #include "qthread.h" #include "qmutex_p.h" +#ifndef Q_OS_LINUX +#include "private/qfreelist_p.h" +#endif + QT_BEGIN_NAMESPACE +/*! + \class QBasicMutex + \brief QMutex POD + \internal + + \ingroup thread + + - Can be used as global static object. + - Always non-recursive + - Do not use tryLock with timeout > 0, else you can have a leak (see the ~QMutex destructor) +*/ + + /*! \class QMutex \brief The QMutex class provides access serialization between threads. @@ -122,8 +139,12 @@ QT_BEGIN_NAMESPACE \sa lock(), unlock() */ QMutex::QMutex(RecursionMode mode) - : d(new QMutexPrivate(mode)) -{ } +{ + if (mode == Recursive) + d = new QRecursiveMutexPrivate; + else + d = 0; +} /*! Destroys the mutex. @@ -131,9 +152,18 @@ QMutex::QMutex(RecursionMode mode) \warning Destroying a locked mutex may result in undefined behavior. */ QMutex::~QMutex() -{ delete static_cast(d); } +{ + if (isRecursive()) + delete static_cast(d._q_value); + else if (d) { +#ifndef Q_OS_LINUX + if (d->possiblyUnlocked && tryLock()) { unlock(); return; } +#endif + qWarning("QMutex: destroying locked mutex"); + } +} -/*! +/*! \fn void QMutex::lock() Locks the mutex. If another thread has locked the mutex then this call will block until that thread has unlocked it. @@ -145,40 +175,8 @@ QMutex::~QMutex() \sa unlock() */ -void QMutex::lock() -{ - QMutexPrivate *d = static_cast(this->d); - Qt::HANDLE self; - - if (d->recursive) { - self = QThread::currentThreadId(); - if (d->owner == self) { - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter"); - return; - } - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - // didn't get the lock, wait for it - isLocked = d->wait(); - Q_ASSERT_X(isLocked, "QMutex::lock", - "Internal error, infinite wait has timed out."); - } - - d->owner = self; - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::lock", "Overflow in recursion counter"); - return; - } - - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - lockInternal(); - } -} - -/*! +/*!\fn bool QMutex::trylock() Attempts to lock the mutex. If the lock was obtained, this function returns true. If another thread has locked the mutex, this function returns false immediately. @@ -195,36 +193,9 @@ void QMutex::lock() \sa lock(), unlock() */ -bool QMutex::tryLock() -{ - QMutexPrivate *d = static_cast(this->d); - Qt::HANDLE self; - if (d->recursive) { - self = QThread::currentThreadId(); - if (d->owner == self) { - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return true; - } - - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - // some other thread has the mutex locked, or we tried to - // recursively lock an non-recursive mutex - return isLocked; - } - - d->owner = self; - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return isLocked; - } - - return d->contenders.testAndSetAcquire(0, 1); -} - -/*! \overload +/*! \fn bool QMutex::tryLock(int timeout) + \overload Attempts to lock the mutex. This function returns true if the lock was obtained; otherwise it returns false. If another thread has @@ -247,81 +218,30 @@ bool QMutex::tryLock() \sa lock(), unlock() */ -bool QMutex::tryLock(int timeout) -{ - QMutexPrivate *d = static_cast(this->d); - Qt::HANDLE self; - if (d->recursive) { - self = QThread::currentThreadId(); - if (d->owner == self) { - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return true; - } - bool isLocked = d->contenders.testAndSetAcquire(0, 1); - if (!isLocked) { - // didn't get the lock, wait for it - isLocked = d->wait(timeout); - if (!isLocked) - return false; - } - - d->owner = self; - ++d->count; - Q_ASSERT_X(d->count != 0, "QMutex::tryLock", "Overflow in recursion counter"); - return true; - } - - return (d->contenders.testAndSetAcquire(0, 1) - // didn't get the lock, wait for it - || d->wait(timeout)); -} - - -/*! +/*! \fn void QMutex::unlock() Unlocks the mutex. Attempting to unlock a mutex in a different thread to the one that locked it results in an error. Unlocking a mutex that is not locked results in undefined behavior. \sa lock() */ -void QMutex::unlock() -{ - QMutexPrivate *d = static_cast(this->d); - if (d->recursive) { - if (!--d->count) { - d->owner = 0; - if (!d->contenders.testAndSetRelease(1, 0)) - d->wakeUp(); - } - } else { - if (!d->contenders.testAndSetRelease(1, 0)) - d->wakeUp(); - } -} /*! - \fn bool QMutex::locked() - - Returns true if the mutex is locked by another thread; otherwise - returns false. - - It is generally a bad idea to use this function, because code - that uses it has a race condition. Use tryLock() and unlock() - instead. - - \oldcode - bool isLocked = mutex.locked(); - \newcode - bool isLocked = true; - if (mutex.tryLock()) { - mutex.unlock(); - isLocked = false; - } - \endcode + \fn void QMutex::isRecursive() + \since 5.0 + + Returns true if the mutex is recursive + */ +bool QBasicMutex::isRecursive() { + QMutexPrivate *d = this->d; + if (quintptr(d) <= 0x3) + return false; + return d->recursive; +} + /*! \class QMutexLocker @@ -418,96 +338,217 @@ void QMutex::unlock() \sa unlock() */ +#ifndef Q_OS_LINUX //linux implementation is in qmutex_linux.cpp /*! - \fn QMutex::QMutex(bool recursive) - - Use the constructor that takes a RecursionMode parameter instead. -*/ - -/*! - \internal helper for lockInline() + \internal helper for lock() */ -void QMutex::lockInternal() +bool QBasicMutex::lockInternal(int timeout) { - QMutexPrivate *d = static_cast(this->d); - - if (QThread::idealThreadCount() == 1) { - // don't spin on single cpu machines - bool isLocked = d->wait(); - Q_ASSERT_X(isLocked, "QMutex::lock", - "Internal error, infinite wait has timed out."); - Q_UNUSED(isLocked); - return; - } + while (!fastTryLock()) { + QMutexPrivate *d = this->d; + if (!d) // if d is 0, the mutex is unlocked + continue; - QElapsedTimer elapsedTimer; - elapsedTimer.start(); - do { - qint64 spinTime = elapsedTimer.nsecsElapsed(); - if (spinTime > d->maximumSpinTime) { - // didn't get the lock, wait for it, since we're not going to gain anything by spinning more - elapsedTimer.start(); - bool isLocked = d->wait(); - Q_ASSERT_X(isLocked, "QMutex::lock", - "Internal error, infinite wait has timed out."); - Q_UNUSED(isLocked); - - qint64 maximumSpinTime = d->maximumSpinTime; - qint64 averageWaitTime = d->averageWaitTime; - qint64 actualWaitTime = elapsedTimer.nsecsElapsed(); - if (actualWaitTime < (QMutexPrivate::MaximumSpinTimeThreshold * 3 / 2)) { - // measure the wait times - averageWaitTime = d->averageWaitTime = qMin((averageWaitTime + actualWaitTime) / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold)); + if (d == dummyLocked()) { + if (timeout == 0) + return false; + QMutexPrivate *newD = QMutexPrivate::allocate(); + if (!this->d.testAndSetOrdered(d, newD)) { + //Either the mutex is already unlocked, or another thread already set it. + newD->deref(); + continue; } + d = newD; + //the d->refCount is already 1 the deref will occurs when we unlock + } else if (d->recursive) { + return static_cast(d)->lock(timeout); + } + + if (timeout == 0 && !d->possiblyUnlocked) + return false; - // adjust the spin count when spinning does not benefit contention performance - if ((spinTime + actualWaitTime) - qint64(QMutexPrivate::MaximumSpinTimeThreshold) >= qint64(QMutexPrivate::MaximumSpinTimeThreshold)) { - // long waits, stop spinning - d->maximumSpinTime = 0; - } else { - // allow spinning if wait times decrease, but never spin more than the average wait time (otherwise we may perform worse) - d->maximumSpinTime = qBound(qint64(averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold)); + if (!d->ref()) + continue; //that QMutexPrivate was already released + + if (d != this->d) { + //Either the mutex is already unlocked, or relocked with another mutex + d->deref(); + continue; + } + + int old_waiters; + do { + old_waiters = d->waiters; + if (old_waiters == -QMutexPrivate::BigNumber) { + // we are unlocking, and the thread that unlocks is about to change d to 0 + // we try to aquire the mutex by changing to dummyLocked() + if (this->d.testAndSetAcquire(d, dummyLocked())) { + // Mutex aquired + Q_ASSERT(d->waiters == -QMutexPrivate::BigNumber || d->waiters == 0); + d->waiters = 0; + d->deref(); + return true; + } else { + Q_ASSERT(d != this->d); //else testAndSetAcquire should have succeeded + // Mutex is likely to bo 0, we should continue the outer-loop, + // set old_waiters to the magic value of BigNumber + old_waiters = QMutexPrivate::BigNumber; + break; + } + } + } while (!d->waiters.testAndSetRelaxed(old_waiters, old_waiters + 1)); + + if (d != this->d) { + // Mutex was unlocked. + if (old_waiters != QMutexPrivate::BigNumber) { + //we did not break the previous loop + Q_ASSERT(d->waiters >= 1); + d->waiters.deref(); } - return; + d->deref(); + continue; + } + + if (d->wait(timeout)) { + if (d->possiblyUnlocked && d->possiblyUnlocked.testAndSetRelaxed(true, false)) + d->deref(); + d->derefWaiters(1); + //we got the lock. (do not deref) + Q_ASSERT(d == this->d); + return true; + } else { + Q_ASSERT(timeout >= 0); + //timeout + d->derefWaiters(1); + //There may be a race in which the mutex is unlocked right after we timed out, + // and before we deref the waiters, so maybe the mutex is actually unlocked. + if (!d->possiblyUnlocked.testAndSetRelaxed(false, true)) + d->deref(); + return false; } - // be a good citizen... yielding lets something else run if there is something to run, but may also relieve memory pressure if not - QThread::yieldCurrentThread(); - } while (d->contenders != 0 || !d->contenders.testAndSetAcquire(0, 1)); - - // spinning is working, do not change the spin time (unless we are using much less time than allowed to spin) - qint64 maximumSpinTime = d->maximumSpinTime; - qint64 spinTime = elapsedTimer.nsecsElapsed(); - if (spinTime < maximumSpinTime / 2) { - // we are using much less time than we need, adjust the limit - d->maximumSpinTime = qBound(qint64(d->averageWaitTime * 3 / 2), maximumSpinTime / 2, qint64(QMutexPrivate::MaximumSpinTimeThreshold)); } + Q_ASSERT(this->d); + return true; } /*! \internal */ -void QMutex::unlockInternal() +void QBasicMutex::unlockInternal() { - static_cast(d)->wakeUp(); + QMutexPrivate *d = this->d; + Q_ASSERT(d); //we must be locked + Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed + + if (d->recursive) { + static_cast(d)->unlock(); + return; + } + + if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) { + //there is no one waiting on this mutex anymore, set the mutex as unlocked (d = 0) + if (this->d.testAndSetRelease(d, 0)) { + if (d->possiblyUnlocked && d->possiblyUnlocked.testAndSetRelaxed(true, false)) + d->deref(); + } + d->derefWaiters(0); + } else { + d->derefWaiters(0); + //there are thread waiting, transfer the lock. + d->wakeUp(); + } + d->deref(); } -/*! - \fn QMutex::lockInline() - \internal - inline version of QMutex::lock() -*/ +//The freelist managment +namespace { +struct FreeListConstants : QFreeListDefaultConstants { + enum { BlockCount = 4, MaxIndex=0xffff }; + static const int Sizes[BlockCount]; +}; +const int FreeListConstants::Sizes[FreeListConstants::BlockCount] = { + 16, + 128, + 1024, + FreeListConstants::MaxIndex - (16-128-1024) +}; + +typedef QFreeList FreeList; +Q_GLOBAL_STATIC(FreeList, freelist); +} + +QMutexPrivate *QMutexPrivate::allocate() +{ + int i = freelist()->next(); + QMutexPrivate *d = &(*freelist())[i]; + d->id = i; + Q_ASSERT(d->refCount == 0); + Q_ASSERT(!d->recursive); + Q_ASSERT(!d->possiblyUnlocked); + Q_ASSERT(d->waiters == 0); + d->refCount = 1; + return d; +} + +void QMutexPrivate::release() +{ + Q_ASSERT(!recursive); + Q_ASSERT(refCount == 0); + Q_ASSERT(!possiblyUnlocked); + Q_ASSERT(waiters == 0); + freelist()->release(id); +} + +// atomically substract "value" to the waiters, and remove the QMutexPrivate::BigNumber flag +void QMutexPrivate::derefWaiters(int value) +{ + int old_waiters; + int new_waiters; + do { + old_waiters = waiters; + new_waiters = old_waiters; + if (new_waiters < 0) { + new_waiters += QMutexPrivate::BigNumber; + } + new_waiters -= value; + } while (!waiters.testAndSetRelaxed(old_waiters, new_waiters)); +} +#endif /*! - \fn QMutex::unlockInline() \internal - inline version of QMutex::unlock() -*/ + */ +bool QRecursiveMutexPrivate::lock(int timeout) { + Qt::HANDLE self = QThread::currentThreadId(); + if (owner == self) { + ++count; + Q_ASSERT_X(count != 0, "QMutex::lock", "Overflow in recursion counter"); + return true; + } + bool success = true; + if (timeout == -1) { + mutex.lock(); + } else { + success = mutex.tryLock(timeout); + } + + if (success) + owner = self; + return success; +} /*! - \fn QMutex::tryLockInline() \internal - inline version of QMutex::tryLock() -*/ + */ +void QRecursiveMutexPrivate::unlock() +{ + if (count > 0) { + count--; + } else { + owner = 0; + mutex.unlock(); + } +} QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index cc667560db..a49b981d01 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -52,47 +52,64 @@ QT_BEGIN_NAMESPACE QT_MODULE(Core) -#ifndef QT_NO_THREAD +#if !defined(QT_NO_THREAD) && !defined(qdoc) -class QAtomicInt; -class QMutexData; +class QMutexPrivate; -class Q_CORE_EXPORT QMutex +class Q_CORE_EXPORT QBasicMutex { - friend class QWaitCondition; - friend class QWaitConditionPrivate; - public: - enum RecursionMode { NonRecursive, Recursive }; + inline void lock() { + if (!fastTryLock()) + lockInternal(); + } - explicit QMutex(RecursionMode mode = NonRecursive); - ~QMutex(); + inline void unlock() { + Q_ASSERT(d); //mutex must be locked + if (!d.testAndSetRelease(dummyLocked(), 0)) + unlockInternal(); + } + + bool tryLock(int timeout = 0) { + return fastTryLock() || lockInternal(timeout); + } - void lock(); //### Qt5: make inline; - inline void lockInline(); - bool tryLock(); //### Qt5: make inline; - bool tryLock(int timeout); - inline bool tryLockInline(); - void unlock(); //### Qt5: make inline; - inline void unlockInline(); + bool isRecursive(); private: - void lockInternal(); + inline bool fastTryLock() { + return d.testAndSetAcquire(0, dummyLocked()); + } + bool lockInternal(int timeout = -1); void unlockInternal(); - Q_DISABLE_COPY(QMutex) - QMutexData *d; + QBasicAtomicPointer d; + static inline QMutexPrivate *dummyLocked() { + return reinterpret_cast(quintptr(1)); + } + + friend class QMutex; + friend class QMutexPrivate; +}; + +class Q_CORE_EXPORT QMutex : public QBasicMutex { +public: + enum RecursionMode { NonRecursive, Recursive }; + explicit QMutex(RecursionMode mode = NonRecursive); + ~QMutex(); +private: + Q_DISABLE_COPY(QMutex) }; class Q_CORE_EXPORT QMutexLocker { public: - inline explicit QMutexLocker(QMutex *m) + inline explicit QMutexLocker(QBasicMutex *m) { Q_ASSERT_X((reinterpret_cast(m) & quintptr(1u)) == quintptr(0), "QMutexLocker", "QMutex pointer is misaligned"); if (m) { - m->lockInline(); + m->lock(); val = reinterpret_cast(m) | quintptr(1u); } else { val = 0; @@ -104,7 +121,7 @@ public: { if ((val & quintptr(1u)) == quintptr(1u)) { val &= ~quintptr(1u); - mutex()->unlockInline(); + mutex()->unlock(); } } @@ -112,7 +129,7 @@ public: { if (val) { if ((val & quintptr(1u)) == quintptr(0u)) { - mutex()->lockInline(); + mutex()->lock(); val |= quintptr(1u); } } @@ -138,54 +155,9 @@ private: quintptr val; }; -class QMutexData -{ - public: - QAtomicInt contenders; - const uint recursive : 1; - uint reserved : 31; - protected: - QMutexData(QMutex::RecursionMode mode); - ~QMutexData(); -}; - -#ifdef QT_NO_DEBUG -inline void QMutex::unlockInline() -{ - if (d->recursive) { - unlock(); - } else if (!d->contenders.testAndSetRelease(1, 0)) { - unlockInternal(); - } -} - -inline bool QMutex::tryLockInline() -{ - if (d->recursive) { - return tryLock(); - } else { - return d->contenders.testAndSetAcquire(0, 1); - } -} - -inline void QMutex::lockInline() -{ - if (d->recursive) { - lock(); - } else if(!tryLockInline()) { - lockInternal(); - } -} -#else // QT_NO_DEBUG -//in debug we do not use inline calls in order to allow debugging tools -// to hook the mutex locking functions. -inline void QMutex::unlockInline() { unlock(); } -inline bool QMutex::tryLockInline() { return tryLock(); } -inline void QMutex::lockInline() { lock(); } -#endif // QT_NO_DEBUG -#else // QT_NO_THREAD +#else // QT_NO_THREAD or qdoc class Q_CORE_EXPORT QMutex @@ -194,14 +166,11 @@ public: enum RecursionMode { NonRecursive, Recursive }; inline explicit QMutex(RecursionMode mode = NonRecursive) { Q_UNUSED(mode); } - inline ~QMutex() {} static inline void lock() {} - static inline void lockInline() {} static inline bool tryLock(int timeout = 0) { Q_UNUSED(timeout); return true; } - static inline bool tryLockInline() { return true; } static inline void unlock() {} - static inline void unlockInline() {} + static inline bool isRecursive() { return true; } private: Q_DISABLE_COPY(QMutex) @@ -221,7 +190,9 @@ private: Q_DISABLE_COPY(QMutexLocker) }; -#endif // QT_NO_THREAD +typedef QMutex QBasicMutex; + +#endif // QT_NO_THREAD or qdoc QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_linux.cpp b/src/corelib/thread/qmutex_linux.cpp new file mode 100644 index 0000000000..17015b8f84 --- /dev/null +++ b/src/corelib/thread/qmutex_linux.cpp @@ -0,0 +1,138 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qmutex.h" + +#ifndef QT_NO_THREAD +#include "qatomic.h" +#include "qmutex_p.h" +# include "qelapsedtimer.h" + +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +static inline int _q_futex(QMutexPrivate *volatile *addr, int op, int val, const struct timespec *timeout) +{ + volatile int *int_addr = reinterpret_cast(addr); +#if Q_BYTE_ORDER == Q_BIG_ENDIAN && QT_POINTER_SIZE == 8 + int_addr++; //We want a pointer to the 32 least significant bit of QMutex::d +#endif + int *addr2 = 0; + int val2 = 0; + return syscall(SYS_futex, int_addr, op, val, timeout, addr2, val2); +} + +static inline QMutexPrivate *dummyFutexValue() +{ + return reinterpret_cast(quintptr(3)); +} + + +QMutexPrivate::~QMutexPrivate() {} +QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) + : recursive(mode == QMutex::Recursive) {} + +bool QBasicMutex::lockInternal(int timeout) +{ + QElapsedTimer elapsedTimer; + if (timeout >= 1) + elapsedTimer.start(); + + while (!fastTryLock()) { + QMutexPrivate *d = this->d; + if (!d) // if d is 0, the mutex is unlocked + continue; + + if (quintptr(d) <= 0x3) { //d == dummyLocked() || d == dummyFutexValue() + if (timeout == 0) + return false; + while (this->d.fetchAndStoreAcquire(dummyFutexValue()) != 0) { + struct timespec ts, *pts = 0; + if (timeout >= 1) { + // recalculate the timeout + qint64 xtimeout = timeout * 1000 * 1000; + xtimeout -= elapsedTimer.nsecsElapsed(); + if (xtimeout <= 0) { + // timer expired after we returned + return false; + } + ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000; + ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000); + pts = &ts; + } + int r = _q_futex(&this->d._q_value, FUTEX_WAIT, quintptr(dummyFutexValue()), pts); + if (r != 0 && errno == ETIMEDOUT) + return false; + } + return true; + } + Q_ASSERT(d->recursive); + return static_cast(d)->lock(timeout); + } + Q_ASSERT(this->d); + return true; +} + +void QBasicMutex::unlockInternal() +{ + QMutexPrivate *d = this->d; + Q_ASSERT(d); //we must be locked + Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed + + if (d == dummyFutexValue()) { + this->d.fetchAndStoreRelease(0); + _q_futex(&this->d._q_value, FUTEX_WAKE, 1, 0); + return; + } + + Q_ASSERT(d->recursive); + static_cast(d)->unlock(); +} + + +QT_END_NAMESPACE + +#endif // QT_NO_THREAD diff --git a/src/corelib/thread/qmutex_mac.cpp b/src/corelib/thread/qmutex_mac.cpp new file mode 100644 index 0000000000..f63feebca4 --- /dev/null +++ b/src/corelib/thread/qmutex_mac.cpp @@ -0,0 +1,96 @@ +/**************************************************************************** +** +** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qplatformdefs.h" +#include "qmutex.h" + +#if !defined(QT_NO_THREAD) + +#include "qmutex_p.h" + +#include +#include + +#include + +QT_BEGIN_NAMESPACE + +QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) + : recursive(mode == QMutex::Recursive) +{ + kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); + if (r != KERN_SUCCESS) + qWarning("QMutex: failed to create semaphore, error %d", r); +} + +QMutexPrivate::~QMutexPrivate() +{ + kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore); + if (r != KERN_SUCCESS) + qWarning("QMutex: failed to destroy semaphore, error %d", r); +} + +bool QMutexPrivate::wait(int timeout) +{ + kern_return_t r; + if (timeout < 0) { + do { + r = semaphore_wait(mach_semaphore); + } while (r == KERN_ABORTED); + Q_ASSERT(r == KERN_SUCCESS); + } else { + mach_timespec_t ts; + ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; + ts.tv_sec = (timeout / 1000); + r = semaphore_timedwait(mach_semaphore, ts); + } + return (r == KERN_SUCCESS); +} + +void QMutexPrivate::wakeUp() +{ + semaphore_signal(mach_semaphore); +} + + +QT_END_NAMESPACE + +#endif //QT_NO_THREAD diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index a9923c47a4..00f071ebef 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -57,50 +57,80 @@ #include #include #include +#include #if defined(Q_OS_MAC) # include #endif -#if defined(Q_OS_SYMBIAN) -# include -#endif - QT_BEGIN_NAMESPACE -class QMutexPrivate : public QMutexData { +class QMutexPrivate { public: - QMutexPrivate(QMutex::RecursionMode mode); ~QMutexPrivate(); + QMutexPrivate(QMutex::RecursionMode mode = QMutex::NonRecursive); bool wait(int timeout = -1); void wakeUp(); - // 1ms = 1000000ns - enum { MaximumSpinTimeThreshold = 1000000 }; - volatile qint64 maximumSpinTime; - volatile qint64 averageWaitTime; - Qt::HANDLE owner; - uint count; +#if !defined(Q_OS_LINUX) + // Conrol the lifetime of the privates + QAtomicInt refCount; + int id; + + bool ref() { + Q_ASSERT(refCount >= 0); + int c; + do { + c = refCount; + if (c == 0) + return false; + } while (!refCount.testAndSetRelaxed(c, c + 1)); + Q_ASSERT(refCount >= 0); + return true; + } + void deref() { + Q_ASSERT(refCount >=0); + if (!refCount.deref()) + release(); + Q_ASSERT(refCount >=0); + } + void release(); + static QMutexPrivate *allocate(); + + QAtomicInt waiters; //number of thread waiting + QAtomicInt possiblyUnlocked; //bool saying that a timed wait timed out + enum { BigNumber = 0x100000 }; //Must be bigger than the possible number of waiters (number of threads) + void derefWaiters(int value); +#endif + + // handle recursive mutex + bool recursive; + //platform specific stuff #if defined(Q_OS_MAC) semaphore_t mach_semaphore; -#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) && !defined(Q_OS_SYMBIAN) - volatile bool wakeup; +#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) + bool wakeup; pthread_mutex_t mutex; pthread_cond_t cond; #elif defined(Q_OS_WIN32) || defined(Q_OS_WINCE) HANDLE event; -#elif defined(Q_OS_SYMBIAN) - RSemaphore lock; #endif }; -inline QMutexData::QMutexData(QMutex::RecursionMode mode) - : recursive(mode == QMutex::Recursive) -{} +class QRecursiveMutexPrivate : public QMutexPrivate +{ +public: + QRecursiveMutexPrivate() + : QMutexPrivate(QMutex::Recursive), owner(0), count(0) {} + Qt::HANDLE owner; + uint count; + QMutex mutex; -inline QMutexData::~QMutexData() {} + bool lock(int timeout); + void unlock(); +}; QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index 2a9d23c361..0bccad589d 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -46,142 +46,35 @@ #ifndef QT_NO_THREAD #include "qatomic.h" #include "qmutex_p.h" - #include #if defined(Q_OS_VXWORKS) && defined(wakeup) #undef wakeup #endif -#if defined(Q_OS_MAC) -# include -# include -#elif defined(Q_OS_LINUX) -# include -# include -# include -# include -#endif - QT_BEGIN_NAMESPACE -#if !defined(Q_OS_MAC) && !defined(Q_OS_LINUX) static void report_error(int code, const char *where, const char *what) { if (code != 0) qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code))); } -#endif - QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) + : recursive(mode == QMutex::Recursive), wakeup(false) { -#if defined(Q_OS_MAC) - kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); - if (r != KERN_SUCCESS) - qWarning("QMutex: failed to create semaphore, error %d", r); -#elif !defined(Q_OS_LINUX) - wakeup = false; report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); -#endif } QMutexPrivate::~QMutexPrivate() { -#if defined(Q_OS_MAC) - kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore); - if (r != KERN_SUCCESS) - qWarning("QMutex: failed to destroy semaphore, error %d", r); -#elif !defined(Q_OS_LINUX) report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy"); report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy"); -#endif } -#if defined(Q_OS_MAC) - bool QMutexPrivate::wait(int timeout) { - if (contenders.fetchAndAddAcquire(1) == 0) { - // lock acquired without waiting - return true; - } - kern_return_t r; - if (timeout < 0) { - do { - r = semaphore_wait(mach_semaphore); - } while (r == KERN_ABORTED); - if (r != KERN_SUCCESS) - qWarning("QMutex: infinite wait failed, error %d", r); - } else { - mach_timespec_t ts; - ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; - ts.tv_sec = (timeout / 1000); - r = semaphore_timedwait(mach_semaphore, ts); - } - contenders.deref(); - return r == KERN_SUCCESS; -} - -void QMutexPrivate::wakeUp() -{ - semaphore_signal(mach_semaphore); -} - -#elif defined(Q_OS_LINUX) - -static inline int _q_futex(volatile int *addr, int op, int val, const struct timespec *timeout, int *addr2, int val2) -{ - return syscall(SYS_futex, addr, op, val, timeout, addr2, val2); -} - -bool QMutexPrivate::wait(int timeout) -{ - struct timespec ts, *pts = 0; - QElapsedTimer timer; - if (timeout >= 0) { - ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; - ts.tv_sec = (timeout / 1000); - pts = &ts; - timer.start(); - } - while (contenders.fetchAndStoreAcquire(2) > 0) { - int r = _q_futex(&contenders._q_value, FUTEX_WAIT, 2, pts, 0, 0); - if (r != 0 && errno == ETIMEDOUT) - return false; - - if (pts) { - // recalculate the timeout - qint64 xtimeout = timeout * 1000 * 1000; - xtimeout -= timer.nsecsElapsed(); - if (xtimeout < 0) { - // timer expired after we returned - return false; - } - - ts.tv_sec = xtimeout / Q_INT64_C(1000) / 1000 / 1000; - ts.tv_nsec = xtimeout % (Q_INT64_C(1000) * 1000 * 1000); - } - } - return true; -} - -void QMutexPrivate::wakeUp() -{ - (void) contenders.fetchAndStoreRelease(0); - (void) _q_futex(&contenders._q_value, FUTEX_WAKE, 1, 0, 0, 0); -} - -#else // !Q_OS_MAC && !Q_OS_LINUX - -bool QMutexPrivate::wait(int timeout) -{ - if (contenders.fetchAndAddAcquire(1) == 0) { - // lock acquired without waiting - return true; - } report_error(pthread_mutex_lock(&mutex), "QMutex::lock", "mutex lock"); int errorCode = 0; while (!wakeup) { @@ -190,12 +83,10 @@ bool QMutexPrivate::wait(int timeout) } else { struct timeval tv; gettimeofday(&tv, 0); - timespec ti; ti.tv_nsec = (tv.tv_usec + (timeout % 1000) * 1000) * 1000; ti.tv_sec = tv.tv_sec + (timeout / 1000) + (ti.tv_nsec / 1000000000); ti.tv_nsec %= 1000000000; - errorCode = pthread_cond_timedwait(&cond, &mutex, &ti); } if (errorCode) { @@ -207,10 +98,10 @@ bool QMutexPrivate::wait(int timeout) report_error(errorCode, "QMutex::lock()", "cv wait"); } } + bool ret = wakeup; wakeup = false; report_error(pthread_mutex_unlock(&mutex), "QMutex::lock", "mutex unlock"); - contenders.deref(); - return errorCode == 0; + return ret; } void QMutexPrivate::wakeUp() @@ -221,7 +112,6 @@ void QMutexPrivate::wakeUp() report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); } -#endif // !Q_OS_MAC && !Q_OS_LINUX QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index 53ad8cfe89..f6670f6d1e 100644 --- a/src/corelib/thread/qmutex_win.cpp +++ b/src/corelib/thread/qmutex_win.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), averageWaitTime(0), owner(0), count(0) + : recursive(mode) { event = CreateEvent(0, FALSE, FALSE, 0); if (!event) @@ -60,13 +60,7 @@ QMutexPrivate::~QMutexPrivate() bool QMutexPrivate::wait(int timeout) { - if (contenders.fetchAndAddAcquire(1) == 0) { - // lock acquired without waiting - return true; - } - bool returnValue = (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0); - contenders.deref(); - return returnValue; + return (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0); } void QMutexPrivate::wakeUp() diff --git a/src/corelib/thread/qorderedmutexlocker_p.h b/src/corelib/thread/qorderedmutexlocker_p.h index 8f01c1c056..e65a601369 100644 --- a/src/corelib/thread/qorderedmutexlocker_p.h +++ b/src/corelib/thread/qorderedmutexlocker_p.h @@ -79,8 +79,8 @@ public: void relock() { if (!locked) { - if (mtx1) mtx1->lockInline(); - if (mtx2) mtx2->lockInline(); + if (mtx1) mtx1->lock(); + if (mtx2) mtx2->lock(); locked = true; } } @@ -88,8 +88,8 @@ public: void unlock() { if (locked) { - if (mtx1) mtx1->unlockInline(); - if (mtx2) mtx2->unlockInline(); + if (mtx1) mtx1->unlock(); + if (mtx2) mtx2->unlock(); locked = false; } } @@ -100,10 +100,10 @@ public: if (mtx1 == mtx2) return false; if (mtx1 < mtx2) { - mtx2->lockInline(); + mtx2->lock(); return true; } - if (!mtx2->tryLockInline()) { + if (!mtx2->tryLock()) { mtx1->unlock(); mtx2->lock(); mtx1->lock(); diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp index b946a9de24..dd85bf4023 100644 --- a/src/corelib/thread/qwaitcondition_unix.cpp +++ b/src/corelib/thread/qwaitcondition_unix.cpp @@ -146,7 +146,7 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time) { if (! mutex) return false; - if (mutex->d->recursive) { + if (mutex->isRecursive()) { qWarning("QWaitCondition: cannot wait on recursive mutexes"); return false; } diff --git a/src/corelib/thread/qwaitcondition_win.cpp b/src/corelib/thread/qwaitcondition_win.cpp index 8a8db97342..bf1ec5e5ba 100644 --- a/src/corelib/thread/qwaitcondition_win.cpp +++ b/src/corelib/thread/qwaitcondition_win.cpp @@ -164,7 +164,7 @@ bool QWaitCondition::wait(QMutex *mutex, unsigned long time) { if (!mutex) return false; - if (mutex->d->recursive) { + if (mutex->isRecursive()) { qWarning("QWaitCondition::wait: Cannot wait on recursive mutexes"); return false; } diff --git a/src/corelib/thread/thread.pri b/src/corelib/thread/thread.pri index 592ab1644b..309bf30d25 100644 --- a/src/corelib/thread/thread.pri +++ b/src/corelib/thread/thread.pri @@ -24,8 +24,7 @@ SOURCES += thread/qatomic.cpp \ thread/qthread.cpp \ thread/qthreadstorage.cpp -unix:!symbian:SOURCES += thread/qmutex_unix.cpp \ - thread/qthread_unix.cpp \ +unix:!symbian:SOURCES += thread/qthread_unix.cpp \ thread/qwaitcondition_unix.cpp symbian:SOURCES += thread/qmutex_symbian.cpp \ @@ -39,3 +38,9 @@ win32:SOURCES += thread/qmutex_win.cpp \ integrity:SOURCES += thread/qmutex_unix.cpp \ thread/qthread_unix.cpp \ thread/qwaitcondition_unix.cpp + +unix: { + macx-* { SOURCES += thread/qmutex_mac.cpp } + else:linux-* { SOURCES += thread/qmutex_linux.cpp } + else { SOURCES += thread/qmutex_unix.cpp } +} -- cgit v1.2.3 From ddf444d31a7cb961b79190131cb679fd7a6351fd Mon Sep 17 00:00:00 2001 From: Olivier Goffart Date: Tue, 26 Jul 2011 10:44:55 +0200 Subject: Simplify the mutexpool used in QObject. Since we now have QBasicMutex as a POD, we can simplify the mutexpool. This remove the call the the Q_GLOBAL_STATIC and some others tests that are taking CPU cycles when activating a signal. The QMutexPool class itself can't be simplified because its mutex are recursive mutexes, and the size is dynamic. also it is harder to get all the mutexes initialized to 0. Change-Id: Ie781655635907d2ad620eb189099cba14638414f Reviewed-by: Bradley T. Hughes Reviewed-on: http://codereview.qt.nokia.com/2171 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart --- src/corelib/kernel/qobject.cpp | 24 +++++------------------- 1 file changed, 5 insertions(+), 19 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index ab9314ce53..076744ee00 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -60,7 +60,6 @@ #include #include -#include #include @@ -95,35 +94,22 @@ static int *queuedConnectionTypes(const QList &typeNames) return types; } -static QBasicAtomicPointer signalSlotMutexes = Q_BASIC_ATOMIC_INITIALIZER(0); -static QBasicAtomicInt objectCount = Q_BASIC_ATOMIC_INITIALIZER(0); +static QBasicMutex _q_ObjectMutexPool[131]; /** \internal * mutex to be locked when accessing the connectionlists or the senders list */ static inline QMutex *signalSlotLock(const QObject *o) { - if (!signalSlotMutexes) { - QMutexPool *mp = new QMutexPool; - if (!signalSlotMutexes.testAndSetOrdered(0, mp)) { - delete mp; - } - } - return signalSlotMutexes->get(o); + return static_cast(&_q_ObjectMutexPool[ + uint(quintptr(o)) % sizeof(_q_ObjectMutexPool)/sizeof(QBasicMutex)]); } extern "C" Q_CORE_EXPORT void qt_addObject(QObject *) -{ - objectCount.ref(); -} +{} extern "C" Q_CORE_EXPORT void qt_removeObject(QObject *) -{ - if(!objectCount.deref()) { - QMutexPool *old = signalSlotMutexes.fetchAndStoreAcquire(0); - delete old; - } -} +{} struct QConnectionSenderSwitcher { QObject *receiver; -- cgit v1.2.3 From 2c3382d30574a56b640c46aab7c407d63435d3bb Mon Sep 17 00:00:00 2001 From: "Bradley T. Hughes" Date: Fri, 29 Jul 2011 12:26:43 +0200 Subject: Fix compilation with namespaced builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add QT_BEGIN_NAMESPACE and QT_END_NAMESPACE to src/corelib/tools/qfreelist.cpp Change-Id: Ie01e74a3c2d9cd4de1f52a546d13398e1409c86b Reviewed-on: http://codereview.qt.nokia.com/2390 Reviewed-by: Qt Sanity Bot Reviewed-by: Olivier Goffart Reviewed-by: João Abecasis --- src/corelib/tools/qfreelist.cpp | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/corelib') diff --git a/src/corelib/tools/qfreelist.cpp b/src/corelib/tools/qfreelist.cpp index 63e37ec249..bbbdb25e49 100644 --- a/src/corelib/tools/qfreelist.cpp +++ b/src/corelib/tools/qfreelist.cpp @@ -41,6 +41,8 @@ #include "qfreelist_p.h" +QT_BEGIN_NAMESPACE + // default sizes and offsets (no need to define these when customizing) enum { Offset0 = 0x00000000, @@ -60,3 +62,6 @@ const int QFreeListDefaultConstants::Sizes[QFreeListDefaultConstants::BlockCount Size2, Size3 }; + +QT_END_NAMESPACE + -- cgit v1.2.3 From 6f4212e5936b96a8be0eacddbfc4dd7ca5abd776 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Tue, 2 Aug 2011 15:58:48 +0200 Subject: Fix QString/QByteArray literals for MSVC2010 (compilation of tests). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Specify return type of QByteArrayLiteral/QStringLiteral lambdas. - Define QT_UNICODE_LITERAL instead of QT_UNICODE_MARKER. Change-Id: I8a53506887d2736b093798220b088f645f05e415 Reviewed-on: http://codereview.qt.nokia.com/2514 Reviewed-by: Qt Sanity Bot Reviewed-by: João Abecasis --- src/corelib/tools/qbytearray.h | 2 +- src/corelib/tools/qstring.h | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 9 deletions(-) (limited to 'src/corelib') diff --git a/src/corelib/tools/qbytearray.h b/src/corelib/tools/qbytearray.h index 5cf4c15179..b70dba4d55 100644 --- a/src/corelib/tools/qbytearray.h +++ b/src/corelib/tools/qbytearray.h @@ -146,7 +146,7 @@ template struct QConstByteArrayDataPtr #if defined(Q_COMPILER_LAMBDA) -# define QByteArrayLiteral(str) ([]() { \ +# define QByteArrayLiteral(str) ([]() -> QConstByteArrayDataPtr { \ enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData qbytearray_literal = \ { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index 4471da4b09..209994de16 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -102,7 +102,8 @@ template struct QConstStringData const QStringData str; const char16_t data[N + 1]; }; -#define QT_QSTRING_UNICODE_MARKER u"" + +#define QT_UNICODE_LITERAL_II(str) u"" str #elif defined(Q_OS_WIN) || (defined(__SIZEOF_WCHAR_T__) && __SIZEOF_WCHAR_T__ == 2) || defined(WCHAR_MAX) && (WCHAR_MAX - 0 < 65536) // wchar_t is 2 bytes @@ -111,7 +112,12 @@ template struct QConstStringData const QStringData str; const wchar_t data[N + 1]; }; -#define QT_QSTRING_UNICODE_MARKER L"" + +#if defined(Q_CC_MSVC) +# define QT_UNICODE_LITERAL_II(str) L##str +#else +# define QT_UNICODE_LITERAL_II(str) L"" str +#endif #else template struct QConstStringData @@ -121,12 +127,13 @@ template struct QConstStringData }; #endif -#if defined(QT_QSTRING_UNICODE_MARKER) +#if defined(QT_UNICODE_LITERAL_II) +# define QT_UNICODE_LITERAL(str) QT_UNICODE_LITERAL_II(str) # if defined(Q_COMPILER_LAMBDA) -# define QStringLiteral(str) ([]() { \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 - 1 }; \ +# define QStringLiteral(str) ([]() -> QConstStringDataPtr { \ + enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \ QConstStringDataPtr holder = { &qstring_literal }; \ return holder; }()) @@ -137,9 +144,9 @@ template struct QConstStringData # define QStringLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 - 1 }; \ + enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ static const QConstStringData qstring_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_QSTRING_UNICODE_MARKER str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, QT_UNICODE_LITERAL(str) }; \ QConstStringDataPtr holder = { &qstring_literal }; \ holder; }) # endif -- cgit v1.2.3