diff options
Diffstat (limited to 'src')
69 files changed, 1462 insertions, 797 deletions
diff --git a/src/3rdparty/harfbuzz/src/harfbuzz-external.h b/src/3rdparty/harfbuzz/src/harfbuzz-external.h index 5fff35fe50..1f7ae1c902 100644 --- a/src/3rdparty/harfbuzz/src/harfbuzz-external.h +++ b/src/3rdparty/harfbuzz/src/harfbuzz-external.h @@ -144,7 +144,7 @@ HB_CharCategory HB_GetUnicodeCharCategory(HB_UChar32 ch); int HB_GetUnicodeCharCombiningClass(HB_UChar32 ch); HB_UChar16 HB_GetMirroredChar(HB_UChar16 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))(); HB_END_HEADER diff --git a/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp b/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp index f0048b75ef..2c261639ad 100644 --- a/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp +++ b/src/3rdparty/harfbuzz/tests/linebreaking/harfbuzz-qt.cpp @@ -79,7 +79,7 @@ void HB_GetGraphemeAndLineBreakClass(HB_UChar32 ch, HB_GraphemeClass *grapheme, *lineBreak = (HB_LineBreakClass) prop->line_break_class; } -void *HB_Library_Resolve(const char *library, int version, const char *symbol) +void (*HB_Library_Resolve(const char *library, int version, const char *symbol))() { return QLibrary::resolve(library, version, symbol); } 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 <typename T> Q_INLINE_TEMPLATE bool QBasicAtomicPointer<T>::testAndSetOrdered(T *expectedValue, T *newValue) { 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 <QtGlobal> + + 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 <QtGlobal> diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h index e4084ed91f..2f6f33efca 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) @@ -794,7 +794,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 @@ -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/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) 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 <private/qthread_p.h> #include <private/qcoreapplication_p.h> +#include <private/qfreelist_p.h> 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<int> 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<int *>(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<bool> struct QStaticAssertType; - template<> struct QStaticAssertType<true> { enum { Value = 1 }; }; -} -#define q_static_assert(expr) (void)QStaticAssertType<expr>::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<void, QtTimerIdFreeListConstants> 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); } /*! 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); } } } 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; diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp index a282ae007c..7652ec4871 100644 --- a/src/corelib/kernel/qobject.cpp +++ b/src/corelib/kernel/qobject.cpp @@ -60,7 +60,6 @@ #include <qsharedpointer.h> #include <private/qorderedmutexlocker_p.h> -#include <private/qmutexpool_p.h> #include <new> @@ -95,35 +94,22 @@ static int *queuedConnectionTypes(const QList<QByteArray> &typeNames) return types; } -static QBasicAtomicPointer<QMutexPool> 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<QMutex *>(&_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; @@ -879,7 +865,7 @@ QObject::~QObject() if (c->next) c->next->prev = c->prev; } if (needToUnlock) - m->unlockInline(); + m->unlock(); connectionList.first = c->nextConnectionList; delete c; @@ -903,7 +889,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; @@ -913,7 +899,7 @@ QObject::~QObject() node = node->next; if (needToUnlock) - m->unlockInline(); + m->unlock(); } } @@ -3077,7 +3063,7 @@ bool QMetaObjectPrivate::disconnectHelper(QObjectPrivate::Connection *c, } if (needToUnlock) - receiverMutex->unlockInline(); + receiverMutex->unlock(); c->receiver = 0; 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 4f66bc26a0..c6804955d9 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/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,9 +49,26 @@ #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<QMutexPrivate *>(d); } +{ + if (isRecursive()) + delete static_cast<QRecursiveMutexPrivate *>(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<QMutexPrivate *>(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<QMutexPrivate *>(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<QMutexPrivate *>(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<QMutexPrivate *>(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<QMutexPrivate *>(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<QRecursiveMutexPrivate *>(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<QMutexPrivate *>(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<QRecursiveMutexPrivate *>(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<QMutexPrivate, FreeListConstants> 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<QMutexPrivate> d; + static inline QMutexPrivate *dummyLocked() { + return reinterpret_cast<QMutexPrivate *>(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<quintptr>(m) & quintptr(1u)) == quintptr(0), "QMutexLocker", "QMutex pointer is misaligned"); if (m) { - m->lockInline(); + m->lock(); val = reinterpret_cast<quintptr>(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 <linux/futex.h> +#include <sys/syscall.h> +#include <unistd.h> +#include <errno.h> + +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<volatile int *>(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<QMutexPrivate *>(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<QRecursiveMutexPrivate *>(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<QRecursiveMutexPrivate *>(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 <mach/mach.h> +#include <mach/task.h> + +#include <errno.h> + +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 <QtCore/qglobal.h> #include <QtCore/qnamespace.h> #include <QtCore/qmutex.h> +#include <QtCore/qatomic.h> #if defined(Q_OS_MAC) # include <mach/semaphore.h> #endif -#if defined(Q_OS_SYMBIAN) -# include <e32std.h> -#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 e692e19525..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 <errno.h> #if defined(Q_OS_VXWORKS) && defined(wakeup) #undef wakeup #endif -#if defined(Q_OS_MAC) -# include <mach/mach.h> -# include <mach/task.h> -#elif defined(Q_OS_LINUX) -# include <linux/futex.h> -# include <sys/syscall.h> -# include <unistd.h> -# include <QtCore/qelapsedtimer.h> -#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 = timeout / Q_INT64_C(1000) / 1000 / 1000; - ts.tv_nsec = timeout % (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 } +} 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<Data *>(&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 dbac302d05..b70dba4d55 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<int n> struct QConstByteArrayData +template<int N> struct QConstByteArrayData { const QByteArrayData ba; - const char data[n]; + const char data[N + 1]; }; template<int N> struct QConstByteArrayDataPtr @@ -146,10 +146,10 @@ template<int N> struct QConstByteArrayDataPtr #if defined(Q_COMPILER_LAMBDA) -# define QByteArrayLiteral(str) ([]() { \ - enum { Size = sizeof(str) }; \ +# define QByteArrayLiteral(str) ([]() -> QConstByteArrayDataPtr<sizeof(str) - 1> { \ + enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData<Size> qbytearray_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \ return holder; }()) @@ -160,9 +160,9 @@ template<int N> struct QConstByteArrayDataPtr # define QByteArrayLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(str) }; \ + enum { Size = sizeof(str) - 1 }; \ static const QConstByteArrayData<Size> qbytearray_literal = \ - { { Q_REFCOUNT_INITIALIZER(-1), Size -1, 0, 0, { 0 } }, str }; \ + { { Q_REFCOUNT_INITIALIZER(-1), Size, 0, 0, { 0 } }, str }; \ QConstByteArrayDataPtr<Size> holder = { &qbytearray_literal }; \ holder; }) #endif @@ -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/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 diff --git a/src/corelib/tools/qfreelist.cpp b/src/corelib/tools/qfreelist.cpp new file mode 100644 index 0000000000..bbbdb25e49 --- /dev/null +++ b/src/corelib/tools/qfreelist.cpp @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** 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" + +QT_BEGIN_NAMESPACE + +// 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 +}; + +QT_END_NAMESPACE + 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 <QtCore/qatomic.h> + +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 <typename T> +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<void> +{ + 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 <typename T, typename ConstantsType = QFreeListDefaultConstants> +class QFreeList +{ + typedef T ValueType; + typedef QFreeListElement<T> 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<ElementType> _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 <typename T, typename ConstantsType> +inline QFreeList<T, ConstantsType>::QFreeList() + : _next(ConstantsType::InitialNextValue) +{ } + +template <typename T, typename ConstantsType> +inline QFreeList<T, ConstantsType>::~QFreeList() +{ + for (int i = 0; i < ConstantsType::BlockCount; ++i) + delete [] static_cast<ElementType *>(_v[i]); +} + +template <typename T, typename ConstantsType> +inline typename QFreeList<T, ConstantsType>::ConstReferenceType QFreeList<T, ConstantsType>::at(int x) const +{ + const int block = blockfor(x); + return _v[block][x].t(); +} + +template <typename T, typename ConstantsType> +inline typename QFreeList<T, ConstantsType>::ReferenceType QFreeList<T, ConstantsType>::operator[](int x) +{ + const int block = blockfor(x); + return _v[block][x].t(); +} + +template <typename T, typename ConstantsType> +inline int QFreeList<T, ConstantsType>::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 <typename T, typename ConstantsType> +inline void QFreeList<T, ConstantsType>::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/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; 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<typename T> Q_DECLARE_TYPEINFO_BODY(QSharedDataPointer<T>, Q_MOVABLE_TYPE); +template<typename T> Q_DECLARE_TYPEINFO_BODY(QExplicitlySharedDataPointer<T>, Q_MOVABLE_TYPE); + QT_END_NAMESPACE QT_END_HEADER 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)); diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h index af3e3f3ff9..209994de16 100644 --- a/src/corelib/tools/qstring.h +++ b/src/corelib/tools/qstring.h @@ -97,36 +97,43 @@ template<int N> struct QConstStringDataPtr }; #if defined(Q_COMPILER_UNICODE_STRINGS) -template<int n> struct QConstStringData +template<int N> struct QConstStringData { const QStringData str; - const char16_t data[n]; + 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 -template<int n> struct QConstStringData +template<int N> struct QConstStringData { const QStringData str; - const wchar_t data[n]; + 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<int n> struct QConstStringData +template<int N> struct QConstStringData { const QStringData str; - const ushort data[n]; + const ushort data[N + 1]; }; #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 }; \ +# define QStringLiteral(str) ([]() -> QConstStringDataPtr<sizeof(QT_UNICODE_LITERAL(str))/2 - 1> { \ + enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ static const QConstStringData<Size> 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_UNICODE_LITERAL(str) }; \ QConstStringDataPtr<Size> holder = { &qstring_literal }; \ return holder; }()) @@ -137,9 +144,9 @@ template<int n> struct QConstStringData # define QStringLiteral(str) \ __extension__ ({ \ - enum { Size = sizeof(QT_QSTRING_UNICODE_MARKER str)/2 }; \ + enum { Size = sizeof(QT_UNICODE_LITERAL(str))/2 - 1 }; \ static const QConstStringData<Size> 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_UNICODE_LITERAL(str) }; \ QConstStringDataPtr<Size> holder = { &qstring_literal }; \ holder; }) # endif 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<const char *>(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 6d998b62aa..30b81c42f4 100644 --- a/src/corelib/tools/qstringbuilder.h +++ b/src/corelib/tools/qstringbuilder.h @@ -294,7 +294,7 @@ template <int N> struct QConcatenable<char[N]> : 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 <int N> struct QConcatenable<const char[N]> : 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<QByteArray> : 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) @@ -364,6 +363,26 @@ template <> struct QConcatenable<QByteArray> : private QAbstractConcatenable } }; +template <int N> struct QConcatenable<QConstByteArrayDataPtr<N> > : private QAbstractConcatenable +{ + typedef QConstByteArrayDataPtr<N> 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) + { + QAbstractConcatenable::convertFromAscii(a.ptr->data, N, out); + } +#endif + static inline void appendTo(const type &ba, char *&out) + { + const char *a = ba.ptr->data; + while (*a) + *out++ = *a++; + } +}; + namespace QtStringBuilder { template <typename A, typename B> struct ConvertToTypeHelper { typedef A ConvertTo; }; 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 \ diff --git a/src/dbus/qdbus_symbols.cpp b/src/dbus/qdbus_symbols.cpp index fed18350bb..8e74b8b922 100644 --- a/src/dbus/qdbus_symbols.cpp +++ b/src/dbus/qdbus_symbols.cpp @@ -48,7 +48,7 @@ QT_BEGIN_NAMESPACE -void *qdbus_resolve_me(const char *name); +void (*qdbus_resolve_me(const char *name))(); #if !defined QT_LINKED_LIBDBUS @@ -95,20 +95,19 @@ bool qdbus_loadLibDBus() return false; } -void *qdbus_resolve_conditionally(const char *name) +void (*qdbus_resolve_conditionally(const char *name))() { if (qdbus_loadLibDBus()) return qdbus_libdbus->resolve(name); return 0; } -void *qdbus_resolve_me(const char *name) +void (*qdbus_resolve_me(const char *name))() { - void *ptr = 0; if (!qdbus_loadLibDBus()) qFatal("Cannot find libdbus-1 in your system to resolve symbol '%s'.", name); - ptr = qdbus_libdbus->resolve(name); + QFunctionPointer ptr = qdbus_libdbus->resolve(name); if (!ptr) qFatal("Cannot resolve '%s' in your libdbus-1.", name); diff --git a/src/dbus/qdbus_symbols_p.h b/src/dbus/qdbus_symbols_p.h index a59c08a8ab..8178e2ecf3 100644 --- a/src/dbus/qdbus_symbols_p.h +++ b/src/dbus/qdbus_symbols_p.h @@ -63,8 +63,8 @@ QT_BEGIN_NAMESPACE #if !defined QT_LINKED_LIBDBUS -void *qdbus_resolve_conditionally(const char *name); // doesn't print a warning -void *qdbus_resolve_me(const char *name); // prints a warning +void (*qdbus_resolve_conditionally(const char *name))(); // doesn't print a warning +void (*qdbus_resolve_me(const char *name))(); // prints a warning bool qdbus_loadLibDBus(); # define DEFINEFUNC(ret, func, args, argcall, funcret) \ diff --git a/src/dbus/qdbusmetaobject.cpp b/src/dbus/qdbusmetaobject.cpp index d12642d632..8daf2300b7 100644 --- a/src/dbus/qdbusmetaobject.cpp +++ b/src/dbus/qdbusmetaobject.cpp @@ -125,6 +125,11 @@ private: MethodScriptable = 0x40 }; + enum MetaObjectFlags { + DynamicMetaObject = 0x01, + RequiresVariantMetaObject = 0x02 + }; + QMap<QByteArray, Method> methods; QMap<QByteArray, Property> properties; @@ -152,6 +157,8 @@ struct QDBusMetaObjectPrivate int methodCount, methodData; int propertyCount, propertyData; int enumeratorCount, enumeratorData; + int constructorCount, constructorData; // since revision 2 + int flags; // since revision 3 // this is specific for QDBusMetaObject: int propertyDBusData; @@ -416,7 +423,7 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) idata.resize(sizeof(QDBusMetaObjectPrivate) / sizeof(int)); QDBusMetaObjectPrivate *header = reinterpret_cast<QDBusMetaObjectPrivate *>(idata.data()); - header->revision = 1; + header->revision = 3; header->className = 0; header->classInfoCount = 0; header->classInfoData = 0; @@ -426,6 +433,9 @@ void QDBusMetaObjectGenerator::write(QDBusMetaObject *obj) header->propertyData = header->methodData + header->methodCount * 5; header->enumeratorCount = 0; header->enumeratorData = 0; + header->constructorCount = 0; + header->constructorData = 0; + header->flags = RequiresVariantMetaObject; header->propertyDBusData = header->propertyData + header->propertyCount * 3; header->methodDBusData = header->propertyDBusData + header->propertyCount * intsPerProperty; diff --git a/src/gui/image/qbmphandler.cpp b/src/gui/image/qbmphandler.cpp index 7848bc96f3..d854b1765b 100644 --- a/src/gui/image/qbmphandler.cpp +++ b/src/gui/image/qbmphandler.cpp @@ -97,8 +97,10 @@ static QDataStream &operator<<(QDataStream &s, const BMP_FILEHDR &bf) const int BMP_OLD = 12; // old Windows/OS2 BMP size -const int BMP_WIN = 40; // new Windows BMP size +const int BMP_WIN = 40; // Windows BMP v3 size const int BMP_OS2 = 64; // new OS/2 BMP size +const int BMP_WIN4 = 108; // Windows BMP v4 size +const int BMP_WIN5 = 124; // Windows BMP v5 size const int BMP_RGB = 0; // no compression const int BMP_RLE8 = 1; // run-length encoded, 8 bits @@ -109,7 +111,7 @@ const int BMP_BITFIELDS = 3; // RGB values encoded in dat static QDataStream &operator>>(QDataStream &s, BMP_INFOHDR &bi) { s >> bi.biSize; - if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2) { + if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2 || bi.biSize == BMP_WIN4 || bi.biSize == BMP_WIN5) { s >> bi.biWidth >> bi.biHeight >> bi.biPlanes >> bi.biBitCount; s >> bi.biCompression >> bi.biSizeImage; s >> bi.biXPelsPerMeter >> bi.biYPelsPerMeter; @@ -255,7 +257,57 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int image.setDotsPerMeterY(bi.biYPelsPerMeter); if (!d->isSequential()) - d->seek(startpos + BMP_FILEHDR_SIZE + bi.biSize); // goto start of colormap + d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap + + if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) { + Q_ASSERT(ncols == 0); + + if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) + return false; + if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask)) + return false; + if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask)) + return false; + + // Read BMP v4+ header + if (bi.biSize >= BMP_WIN4) { + int alpha_mask = 0; + int CSType = 0; + int gamma_red = 0; + int gamma_green = 0; + int gamma_blue = 0; + int endpoints[9]; + + if (d->read((char *)&alpha_mask, sizeof(alpha_mask)) != sizeof(alpha_mask)) + return false; + if (d->read((char *)&CSType, sizeof(CSType)) != sizeof(CSType)) + return false; + if (d->read((char *)&endpoints, sizeof(endpoints)) != sizeof(endpoints)) + return false; + if (d->read((char *)&gamma_red, sizeof(gamma_red)) != sizeof(gamma_red)) + return false; + if (d->read((char *)&gamma_green, sizeof(gamma_green)) != sizeof(gamma_green)) + return false; + if (d->read((char *)&gamma_blue, sizeof(gamma_blue)) != sizeof(gamma_blue)) + return false; + + if (bi.biSize == BMP_WIN5) { + qint32 intent = 0; + qint32 profileData = 0; + qint32 profileSize = 0; + qint32 reserved = 0; + + if (d->read((char *)&intent, sizeof(intent)) != sizeof(intent)) + return false; + if (d->read((char *)&profileData, sizeof(profileData)) != sizeof(profileData)) + return false; + if (d->read((char *)&profileSize, sizeof(profileSize)) != sizeof(profileSize)) + return false; + if (d->read((char *)&reserved, sizeof(reserved)) != sizeof(reserved) || reserved != 0) + return false; + } + } + } if (ncols > 0) { // read color table uchar rgb[4]; @@ -268,12 +320,6 @@ static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int return false; } } else if (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32)) { - if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask)) - return false; - if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask)) - return false; - if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask)) - return false; red_shift = calc_shift(red_mask); red_scale = 256 / ((red_mask >> red_shift) + 1); green_shift = calc_shift(green_mask); diff --git a/src/gui/image/qtiffhandler.cpp b/src/gui/image/qtiffhandler.cpp index c753b83294..4dc9775d46 100644 --- a/src/gui/image/qtiffhandler.cpp +++ b/src/gui/image/qtiffhandler.cpp @@ -236,14 +236,14 @@ bool QTiffHandler::read(QImage *image) } } else { // create the color table - uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16))); - if (!redTable || !greenTable || !blueTable) { + uint16 *redTable = 0; + uint16 *greenTable = 0; + uint16 *blueTable = 0; + if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { TIFFClose(tiff); return false; } - if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) { + if (!redTable || !greenTable || !blueTable) { TIFFClose(tiff); return false; } @@ -500,6 +500,9 @@ bool QTiffHandler::write(const QImage &image) uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16))); if (!redTable || !greenTable || !blueTable) { + qFree(redTable); + qFree(greenTable); + qFree(blueTable); TIFFClose(tiff); return false; } diff --git a/src/gui/math3d/qmatrix4x4.cpp b/src/gui/math3d/qmatrix4x4.cpp index 837bd519b8..cef92af66b 100644 --- a/src/gui/math3d/qmatrix4x4.cpp +++ b/src/gui/math3d/qmatrix4x4.cpp @@ -55,6 +55,20 @@ QT_BEGIN_NAMESPACE \since 4.6 \ingroup painting-3D + The QMatrix4x4 class in general is treated as a row-major matrix, in that the + constructors and operator() functions take data in row-major format, as is + familiar in C-style usage. + + Internally the data is stored as column-major format, so as to be optimal for + passing to OpenGL functions, which expect column-major data. + + When using these functions be aware that they return data in \bold{column-major} + format: + \list + \o data() + \o constData() + \endlist + \sa QVector3D, QGenericMatrix */ @@ -1725,6 +1739,7 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const \fn const qreal *QMatrix4x4::data() const Returns a constant pointer to the raw data of this matrix. + This raw data is stored in column-major format. \sa constData() */ @@ -1733,6 +1748,7 @@ QRectF QMatrix4x4::mapRect(const QRectF& rect) const \fn const qreal *QMatrix4x4::constData() const Returns a constant pointer to the raw data of this matrix. + This raw data is stored in column-major format. \sa data() */ diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp index 908fdf1183..566b4d5f61 100644 --- a/src/gui/painting/qpaintengine_raster.cpp +++ b/src/gui/painting/qpaintengine_raster.cpp @@ -3005,7 +3005,7 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem) ensureState(); QFontEngine *fontEngine = textItem->fontEngine(); - if (!supportsTransformations(fontEngine)) { + if (shouldDrawCachedGlyphs(fontEngine->fontDef.pixelSize, state()->matrix)) { drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions, fontEngine); } else { @@ -3355,10 +3355,7 @@ bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransfo #endif return true; - if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64) - return true; - - return false; + return !shouldDrawCachedGlyphs(pixelSize, m); } /*! diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp index 9427dd5105..5ef6900cc8 100644 --- a/src/gui/painting/qpaintengineex.cpp +++ b/src/gui/painting/qpaintengineex.cpp @@ -53,6 +53,10 @@ QT_BEGIN_NAMESPACE +#if !defined(QT_MAX_CACHED_GLYPH_SIZE) +# define QT_MAX_CACHED_GLYPH_SIZE 64 +#endif + /******************************************************************************* * * class QVectorPath @@ -1096,4 +1100,10 @@ bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform & return false; } +bool QPaintEngineEx::shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const +{ + return (pixelSize * pixelSize * qAbs(m.determinant())) < + QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE; +} + QT_END_NAMESPACE diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h index 604a43133f..d9ab506c94 100644 --- a/src/gui/painting/qpaintengineex_p.h +++ b/src/gui/painting/qpaintengineex_p.h @@ -228,6 +228,7 @@ public: }; virtual uint flags() const {return 0;} virtual bool supportsTransformations(qreal pixelSize, const QTransform &m) const; + virtual bool shouldDrawCachedGlyphs(qreal pixelSize, const QTransform &m) const; protected: QPaintEngineEx(QPaintEngineExPrivate &data); diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 6ae410cada..c53e841cf4 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -155,6 +155,7 @@ public: struct FaceId { FaceId() : index(0), encoding(0) {} QByteArray filename; + QByteArray uuid; int index; int encoding; }; @@ -303,7 +304,7 @@ inline bool operator ==(const QFontEngine::FaceId &f1, const QFontEngine::FaceId inline uint qHash(const QFontEngine::FaceId &f) { - return qHash((f.index << 16) + f.encoding) + qHash(f.filename); + return qHash((f.index << 16) + f.encoding) + qHash(f.filename + f.uuid); } diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index 4c65ad5de0..26b6a8aad7 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -139,7 +139,7 @@ QRawFont::QRawFont() \note The referenced file must contain a TrueType or OpenType font. */ QRawFont::QRawFont(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) : d(new QRawFontPrivate) { @@ -154,7 +154,7 @@ QRawFont::QRawFont(const QString &fileName, \note The data must contain a TrueType or OpenType font. */ QRawFont::QRawFont(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) : d(new QRawFontPrivate) { @@ -204,7 +204,7 @@ bool QRawFont::isValid() const \sa loadFromData() */ void QRawFont::loadFromFile(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { QFile file(fileName); @@ -222,7 +222,7 @@ void QRawFont::loadFromFile(const QString &fileName, \sa loadFromFile() */ void QRawFont::loadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { detach(); diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h index e94bd99b8c..f7d7494f0b 100644 --- a/src/gui/text/qrawfont.h +++ b/src/gui/text/qrawfont.h @@ -70,10 +70,10 @@ public: QRawFont(); QRawFont(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); QRawFont(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting); QRawFont(const QRawFont &other); ~QRawFont(); @@ -117,11 +117,11 @@ public: qreal unitsPerEm() const; void loadFromFile(const QString &fileName, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference); void loadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference); bool supportsCharacter(quint32 ucs4) const; diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp index db60459176..1666df3fdf 100644 --- a/src/gui/text/qrawfont_ft.cpp +++ b/src/gui/text/qrawfont_ft.cpp @@ -45,6 +45,7 @@ #include "qrawfont_p.h" #include "qfontengine_ft_p.h" +#include "quuid.h" #if defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG) # include "qfontengine_x11_p.h" @@ -87,6 +88,7 @@ public: FaceId faceId; faceId.filename = ""; faceId.index = 0; + faceId.uuid = QUuid::createUuid().toByteArray(); return init(faceId, true, Format_None, fontData); } @@ -98,7 +100,7 @@ void QRawFontPrivate::platformCleanUp() // Font engine handles all resources } -void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { Q_ASSERT(fontEngine == 0); diff --git a/src/gui/text/qrawfont_p.h b/src/gui/text/qrawfont_p.h index 56ea6a031d..4a4ed56223 100644 --- a/src/gui/text/qrawfont_p.h +++ b/src/gui/text/qrawfont_p.h @@ -99,7 +99,7 @@ public: void cleanUp(); void platformCleanUp(); void platformLoadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference); static QRawFontPrivate *get(const QRawFont &font) { return font.d.data(); } diff --git a/src/gui/text/qrawfont_qpa.cpp b/src/gui/text/qrawfont_qpa.cpp index b80b64cbaf..47815baf06 100644 --- a/src/gui/text/qrawfont_qpa.cpp +++ b/src/gui/text/qrawfont_qpa.cpp @@ -53,7 +53,7 @@ void QRawFontPrivate::platformCleanUp() { } -void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize, +void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference) { Q_ASSERT(fontEngine == 0); diff --git a/src/gui/text/qtextcontrol.cpp b/src/gui/text/qtextcontrol.cpp index 3d7e597f23..689fd4379b 100644 --- a/src/gui/text/qtextcontrol.cpp +++ b/src/gui/text/qtextcontrol.cpp @@ -1817,6 +1817,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) bool isGettingInput = !e->commitString().isEmpty() || e->preeditString() != cursor.block().layout()->preeditAreaText() || e->replacementLength() > 0; + bool forceSelectionChanged = false; cursor.beginEditBlock(); if (isGettingInput) { @@ -1840,6 +1841,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) cursor.setPosition(blockStart + a.length, QTextCursor::KeepAnchor); q->ensureCursorVisible(); repaintOldAndNewSelection(oldCursor); + forceSelectionChanged = true; } } @@ -1874,6 +1876,7 @@ void QTextControlPrivate::inputMethodEvent(QInputMethodEvent *e) cursor_d->setX(); if (oldPreeditCursor != preeditCursor) emit q->microFocusChanged(); + selectionChanged(forceSelectionChanged); } QVariant QTextControl::inputMethodQuery(Qt::InputMethodQuery property) const diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index 5cc3d73fb9..0d3aa0b585 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1632,7 +1632,7 @@ bool QTextEngine::isRightToLeft() const int QTextEngine::findItem(int strPos) const { itemize(); - int left = 0; + int left = 1; int right = layoutData->items.size()-1; while(left <= right) { int middle = ((right-left)/2)+left; diff --git a/src/gui/util/qvalidator.cpp b/src/gui/util/qvalidator.cpp index b32bea8b7a..43251a8829 100644 --- a/src/gui/util/qvalidator.cpp +++ b/src/gui/util/qvalidator.cpp @@ -131,6 +131,69 @@ QT_BEGIN_NAMESPACE \omitvalue Valid */ + +/*! + \fn void QIntValidator::topChanged(int top) + + This signal is emitted after the top property changed. + + \sa QIntValidator::top(), QIntValidator::setTop(), QIntValidator::bottom(), QIntValidator::setBottom() + \internal +*/ + +/*! + \fn void QIntValidator::bottomChanged(int bottom) + + This signal is emitted after the bottom property changed. + + \sa QIntValidator::top(), QIntValidator::setTop(), QIntValidator::bottom(), QIntValidator::setBottom() + \internal +*/ + +/*! + \fn void QDoubleValidator::topChanged(int top) + + This signal is emitted after the top property changed. + + \sa QDoubleValidator::top(), QDoubleValidator::setTop(), QDoubleValidator::bottom(), QDoubleValidator::setBottom() + \internal +*/ + +/*! + \fn void QDoubleValidator::bottomChanged(int bottom) + + This signal is emitted after the bottom property changed. + + \sa QDoubleValidator::top(), QDoubleValidator::setTop(), QDoubleValidator::bottom(), QDoubleValidator::setBottom() + \internal +*/ + +/*! + \fn void QDoubleValidator::decimalsChanged(int decimals) + + This signal is emitted after the decimals property changed. + + \internal +*/ + +/*! + \fn void QDoubleValidator::notationChanged(QDoubleValidator::Notation notation) + + This signal is emitted after the notation property changed. + + QDoubleValidator::Notation is not a registered metatype, so for queued connections, + you will have to register it with Q_DECLARE_METATYPE() and qRegisterMetaType(). + + \internal +*/ + +/*! + \fn void QRegExpValidator::regExpChanged(const QRegExp ®Exp) + + This signal is emitted after the regExp property changed. + \internal +*/ + class QValidatorPrivate : public QObjectPrivate{ Q_DECLARE_PUBLIC(QValidator) public: @@ -436,8 +499,15 @@ void QIntValidator::fixup(QString &input) const void QIntValidator::setRange(int bottom, int top) { - b = bottom; - t = top; + if (b != bottom) { + b = bottom; + emit bottomChanged(b); + } + + if (t != top) { + t = top; + emit topChanged(t); + } } @@ -710,9 +780,20 @@ QValidator::State QDoubleValidatorPrivate::validateWithLocale(QString &input, QL void QDoubleValidator::setRange(double minimum, double maximum, int decimals) { - b = minimum; - t = maximum; - dec = decimals; + if (b != minimum) { + b = minimum; + emit bottomChanged(b); + } + + if (t != maximum) { + t = maximum; + emit topChanged(t); + } + + if (dec != decimals) { + dec = decimals; + emit decimalsChanged(dec); + } } /*! @@ -771,7 +852,10 @@ void QDoubleValidator::setDecimals(int decimals) void QDoubleValidator::setNotation(Notation newNotation) { Q_D(QDoubleValidator); - d->notation = newNotation; + if (d->notation != newNotation) { + d->notation = newNotation; + emit notationChanged(d->notation); + } } QDoubleValidator::Notation QDoubleValidator::notation() const @@ -915,7 +999,10 @@ QValidator::State QRegExpValidator::validate(QString &input, int& pos) const void QRegExpValidator::setRegExp(const QRegExp& rx) { - r = rx; + if (r != rx) { + r = rx; + emit regExpChanged(r); + } } #endif diff --git a/src/gui/util/qvalidator.h b/src/gui/util/qvalidator.h index 70f656e6a8..cb0436cc3e 100644 --- a/src/gui/util/qvalidator.h +++ b/src/gui/util/qvalidator.h @@ -96,8 +96,8 @@ private: class Q_GUI_EXPORT QIntValidator : public QValidator { Q_OBJECT - Q_PROPERTY(int bottom READ bottom WRITE setBottom) - Q_PROPERTY(int top READ top WRITE setTop) + Q_PROPERTY(int bottom READ bottom WRITE setBottom NOTIFY bottomChanged) + Q_PROPERTY(int top READ top WRITE setTop NOTIFY topChanged) public: explicit QIntValidator(QObject * parent = 0); @@ -113,7 +113,9 @@ public: int bottom() const { return b; } int top() const { return t; } - +Q_SIGNALS: + void bottomChanged(int bottom); + void topChanged(int top); #ifdef QT3_SUPPORT public: QT3_SUPPORT_CONSTRUCTOR QIntValidator(QObject * parent, const char *name); @@ -134,11 +136,11 @@ class QDoubleValidatorPrivate; class Q_GUI_EXPORT QDoubleValidator : public QValidator { Q_OBJECT - Q_PROPERTY(double bottom READ bottom WRITE setBottom) - Q_PROPERTY(double top READ top WRITE setTop) - Q_PROPERTY(int decimals READ decimals WRITE setDecimals) + Q_PROPERTY(double bottom READ bottom WRITE setBottom NOTIFY bottomChanged) + Q_PROPERTY(double top READ top WRITE setTop NOTIFY topChanged) + Q_PROPERTY(int decimals READ decimals WRITE setDecimals NOTIFY decimalsChanged) Q_ENUMS(Notation) - Q_PROPERTY(Notation notation READ notation WRITE setNotation) + Q_PROPERTY(Notation notation READ notation WRITE setNotation NOTIFY notationChanged) public: explicit QDoubleValidator(QObject * parent = 0); @@ -149,7 +151,6 @@ public: StandardNotation, ScientificNotation }; - QValidator::State validate(QString &, int &) const; virtual void setRange(double bottom, double top, int decimals = 0); @@ -163,6 +164,12 @@ public: int decimals() const { return dec; } Notation notation() const; +Q_SIGNALS: + void bottomChanged(double bottom); + void topChanged(double top); + void decimalsChanged(int decimals); + void notationChanged(QDoubleValidator::Notation notation); + #ifdef QT3_SUPPORT public: QT3_SUPPORT_CONSTRUCTOR QDoubleValidator(QObject * parent, const char *name); @@ -182,7 +189,7 @@ private: class Q_GUI_EXPORT QRegExpValidator : public QValidator { Q_OBJECT - Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp) + Q_PROPERTY(QRegExp regExp READ regExp WRITE setRegExp NOTIFY regExpChanged) public: explicit QRegExpValidator(QObject *parent = 0); @@ -194,6 +201,8 @@ public: void setRegExp(const QRegExp& rx); const QRegExp& regExp() const { return r; } // ### make inline for 5.0 +Q_SIGNALS: + void regExpChanged(const QRegExp& regExp); #ifdef QT3_SUPPORT public: QT3_SUPPORT_CONSTRUCTOR QRegExpValidator(QObject *parent, const char *name); diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp index ab103ba836..58b9002222 100644 --- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp +++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp @@ -97,10 +97,6 @@ extern Q_GUI_EXPORT bool qt_cleartype_enabled; extern bool qt_applefontsmoothing_enabled; #endif -#if !defined(QT_MAX_CACHED_GLYPH_SIZE) -# define QT_MAX_CACHED_GLYPH_SIZE 64 -#endif - Q_GUI_EXPORT QImage qt_imageForBrush(int brushStyle, bool invert); ////////////////////////////////// Private Methods ////////////////////////////////////////// @@ -1441,8 +1437,7 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem) // don't try to cache huge fonts or vastly transformed fonts QFontEngine *fontEngine = textItem->fontEngine(); const qreal pixelSize = fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(det) < QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE || - det < 0.25f || det > 4.f) { + if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) { QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0 ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat) : d->glyphCacheType; @@ -1500,8 +1495,7 @@ void QGL2PaintEngineEx::drawTextItem(const QPointF &p, const QTextItem &textItem // don't try to cache huge fonts or vastly transformed fonts const qreal pixelSize = ti.fontEngine->fontDef.pixelSize; - if (pixelSize * pixelSize * qAbs(det) >= QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE || - det < 0.25f || det > 4.f) + if (shouldDrawCachedGlyphs(pixelSize, s->matrix) || det < 0.25f || det > 4.f) drawCached = false; QFontEngineGlyphCache::Type glyphType = ti.fontEngine->glyphFormat >= 0 diff --git a/src/opengl/qgl_x11.cpp b/src/opengl/qgl_x11.cpp index 1fd9e373ed..c35488da02 100644 --- a/src/opengl/qgl_x11.cpp +++ b/src/opengl/qgl_x11.cpp @@ -347,13 +347,13 @@ static void find_trans_colors() QGLFormat UNIX/GLX-specific code *****************************************************************************/ -void* qglx_getProcAddress(const char* procName) +void (*qglx_getProcAddress(const char* procName))() { // On systems where the GL driver is pluggable (like Mesa), we have to use // the glXGetProcAddressARB extension to resolve other function pointers as // the symbols wont be in the GL library, but rather in a plugin loaded by // the GL library. - typedef void* (*qt_glXGetProcAddressARB)(const char *); + typedef void (*(*qt_glXGetProcAddressARB)(const char *))(); static qt_glXGetProcAddressARB glXGetProcAddressARB = 0; static bool triedResolvingGlxGetProcAddress = false; if (!triedResolvingGlxGetProcAddress) { @@ -378,7 +378,7 @@ void* qglx_getProcAddress(const char* procName) } } - void *procAddress = 0; + void (*procAddress)() = 0; if (glXGetProcAddressARB) procAddress = glXGetProcAddressARB(procName); @@ -387,7 +387,7 @@ void* qglx_getProcAddress(const char* procName) if (!procAddress) { void *handle = dlopen(NULL, RTLD_LAZY); if (handle) { - procAddress = dlsym(handle, procName); + procAddress = (void (*)())dlsym(handle, procName); dlclose(handle); } } diff --git a/src/opengl/qglpixelbuffer_x11.cpp b/src/opengl/qglpixelbuffer_x11.cpp index 9e8beba311..fcd7b521bb 100644 --- a/src/opengl/qglpixelbuffer_x11.cpp +++ b/src/opengl/qglpixelbuffer_x11.cpp @@ -93,7 +93,7 @@ static _glXMakeContextCurrent qt_glXMakeContextCurrent = 0; #define glXGetFBConfigAttrib qt_glXGetFBConfigAttrib #define glXMakeContextCurrent qt_glXMakeContextCurrent -extern void* qglx_getProcAddress(const char* procName); // in qgl_x11.cpp +extern void (*qglx_getProcAddress(const char* procName))(); // in qgl_x11.cpp static bool qt_resolve_pbuffer_extensions() { diff --git a/src/plugins/platforms/xlib/qxlibstatic.cpp b/src/plugins/platforms/xlib/qxlibstatic.cpp index ee4c463b94..3ba0eb4c32 100644 --- a/src/plugins/platforms/xlib/qxlibstatic.cpp +++ b/src/plugins/platforms/xlib/qxlibstatic.cpp @@ -218,8 +218,8 @@ static const char * x11_atomnames = { \c XFIXES_MAJOR - it is a part of soname and may differ from the Xfixes version. */ -static void* qt_load_library_runtime(const char *library, int vernum, - int highestVernum, const char *symbol) +static QFunctionPointer qt_load_library_runtime(const char *library, int vernum, + int highestVernum, const char *symbol) { QList<int> versions; // we try to load in the following order: @@ -234,7 +234,7 @@ static void* qt_load_library_runtime(const char *library, int vernum, Q_FOREACH(int version, versions) { QLatin1String libName(library); QLibrary xfixesLib(libName, version); - void *ptr = xfixesLib.resolve(symbol); + QFunctionPointer ptr = xfixesLib.resolve(symbol); if (ptr) return ptr; } diff --git a/src/sql/models/qsqlrelationaltablemodel.cpp b/src/sql/models/qsqlrelationaltablemodel.cpp index f6c401842f..5b0406f4b0 100644 --- a/src/sql/models/qsqlrelationaltablemodel.cpp +++ b/src/sql/models/qsqlrelationaltablemodel.cpp @@ -119,6 +119,8 @@ QT_BEGIN_NAMESPACE returns false. */ +class QRelatedTableModel; + struct QRelation { public: @@ -135,7 +137,7 @@ struct QRelation bool isValid(); QSqlRelation rel; - QSqlTableModel *model; + QRelatedTableModel *model; QHash<QString, QVariant> dictionary;//maps keys to display values private: @@ -143,6 +145,15 @@ struct QRelation bool m_dictInitialized; }; +class QRelatedTableModel : public QSqlTableModel +{ +public: + QRelatedTableModel(QRelation *rel, QObject *parent = 0, QSqlDatabase db = QSqlDatabase()); + bool select(); +private: + bool firstSelect; + QRelation *relation; +}; /* A QRelation must be initialized before it is considered valid. Note: population of the model and dictionary are kept separate @@ -162,7 +173,7 @@ void QRelation::populateModel() Q_ASSERT(m_parent != NULL); if (!model) { - model = new QSqlTableModel(m_parent, m_parent->database()); + model = new QRelatedTableModel(this, m_parent, m_parent->database()); model->setTable(rel.tableName()); model->select(); } @@ -219,6 +230,27 @@ bool QRelation::isValid() return (rel.isValid() && m_parent != NULL); } + + +QRelatedTableModel::QRelatedTableModel(QRelation *rel, QObject *parent, QSqlDatabase db) : + QSqlTableModel(parent, db), firstSelect(true), relation(rel) +{ +} + +bool QRelatedTableModel::select() +{ + if (firstSelect) { + firstSelect = false; + return QSqlTableModel::select(); + } + relation->clearDictionary(); + bool res = QSqlTableModel::select(); + if (res) + relation->populateDictionary(); + return res; +} + + class QSqlRelationalTableModelPrivate: public QSqlTableModelPrivate { Q_DECLARE_PUBLIC(QSqlRelationalTableModel) diff --git a/src/testlib/testlib.pro b/src/testlib/testlib.pro index 435036e0c8..a017d33b4a 100644 --- a/src/testlib/testlib.pro +++ b/src/testlib/testlib.pro @@ -88,7 +88,7 @@ qpa:mac: { load(qt_module_config) -HEADERS += $$QT_SOURCE_TREE/src/testlib/qttestlibversion.h +HEADERS += $$QT_SOURCE_TREE/src/testlib/qttestversion.h QMAKE_TARGET_PRODUCT = QTestLib QMAKE_TARGET_DESCRIPTION = Qt \ diff --git a/src/widgets/platforms/mac/qrawfont_mac.cpp b/src/widgets/platforms/mac/qrawfont_mac.cpp index df68eb7e7a..40c719a1af 100644 --- a/src/widgets/platforms/mac/qrawfont_mac.cpp +++ b/src/widgets/platforms/mac/qrawfont_mac.cpp @@ -55,7 +55,7 @@ void QRawFontPrivate::platformCleanUp() extern int qt_defaultDpi(); void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { // Mac OS X ignores it diff --git a/src/widgets/platforms/win/qrawfont_win.cpp b/src/widgets/platforms/win/qrawfont_win.cpp index 6c62673b54..d8aa557975 100644 --- a/src/widgets/platforms/win/qrawfont_win.cpp +++ b/src/widgets/platforms/win/qrawfont_win.cpp @@ -529,7 +529,8 @@ void QRawFontPrivate::platformCleanUp() { if (fontHandle != NULL) { if (ptrRemoveFontMemResourceEx == NULL) { - void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + QFunctionPointer func = + QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); ptrRemoveFontMemResourceEx = reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func); } @@ -545,7 +546,7 @@ void QRawFontPrivate::platformCleanUp() } void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData, - int pixelSize, + qreal pixelSize, QFont::HintingPreference hintingPreference) { QByteArray fontData(_fontData); @@ -572,7 +573,8 @@ void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData, } if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) { - void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); + QFunctionPointer func = + QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx"); ptrRemoveFontMemResourceEx = reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func); diff --git a/src/widgets/platforms/x11/qkeymapper_x11.cpp b/src/widgets/platforms/x11/qkeymapper_x11.cpp index e243716f6a..455840f8b2 100644 --- a/src/widgets/platforms/x11/qkeymapper_x11.cpp +++ b/src/widgets/platforms/x11/qkeymapper_x11.cpp @@ -513,7 +513,7 @@ void QKeyMapperPrivate::clearMappings() // ### ??? // if (keyboardLayoutName.isEmpty()) - // qWarning("Qt: unable to determine keyboard layout, please talk to qt-bugs@trolltech.com"); ? + // qWarning("Qt: unable to determine keyboard layout, please talk to qt-info@nokia.com"); ? keyboardInputLocale = q_getKeyboardLocale(layoutName, variantName); keyboardInputDirection = keyboardInputLocale.textDirection(); diff --git a/src/widgets/widgets/qtabwidget.h b/src/widgets/widgets/qtabwidget.h index 447560f332..899b7a5dba 100644 --- a/src/widgets/widgets/qtabwidget.h +++ b/src/widgets/widgets/qtabwidget.h @@ -148,6 +148,8 @@ public: void clear(); + QTabBar* tabBar() const; + public Q_SLOTS: void setCurrentIndex(int index); void setCurrentWidget(QWidget *widget); @@ -165,7 +167,6 @@ protected: void keyPressEvent(QKeyEvent *); void paintEvent(QPaintEvent *); void setTabBar(QTabBar *); - QTabBar* tabBar() const; void changeEvent(QEvent *); bool event(QEvent *); void initStyleOption(QStyleOptionTabWidgetFrame *option) const; diff --git a/src/winmain/winmain.pro b/src/winmain/winmain.pro index b353e8e382..6630d86326 100644 --- a/src/winmain/winmain.pro +++ b/src/winmain/winmain.pro @@ -1,7 +1,6 @@ # Additional Qt project file for qtmain lib on Windows TEMPLATE = lib TARGET = qtmain -DESTDIR = $$QMAKE_LIBDIR_QT QT = CONFIG += staticlib warn_on @@ -17,5 +16,6 @@ win32 { !win32:error("$$_FILE_ is intended only for Windows!") load(qt_module_config) +DESTDIR = $$QMAKE_LIBDIR_QT wince*:QMAKE_POST_LINK = |