diff options
Diffstat (limited to 'src/corelib/thread')
25 files changed, 231 insertions, 117 deletions
diff --git a/src/corelib/thread/qbasicatomic.h b/src/corelib/thread/qbasicatomic.h index 3c16cf5b9c..c29b80d3d0 100644 --- a/src/corelib/thread/qbasicatomic.h +++ b/src/corelib/thread/qbasicatomic.h @@ -39,11 +39,13 @@ #if defined(QT_BOOTSTRAPPED) # include <QtCore/qatomic_bootstrap.h> -// The following two are used for testing only. -// Note that we don't check the compiler support -- you had better -// know what you're doing if you set them -#elif defined(QT_ATOMIC_FORCE_CXX11) +// If C++11 atomics are supported, use them! +#elif defined(Q_COMPILER_ATOMICS) && defined(Q_COMPILER_CONSTEXPR) && !defined(QT_ATOMIC_FORCE_NO_CXX11) # include <QtCore/qatomic_cxx11.h> + +// The following is used for testing only. +// Note that we don't check the compiler support -- you had better +// know what you're doing if you set it #elif defined(QT_ATOMIC_FORCE_GCC) # include <QtCore/qatomic_gcc.h> @@ -64,8 +66,6 @@ # include <QtCore/qatomic_x86.h> // Fallback compiler dependent implementation -#elif defined(Q_COMPILER_ATOMICS) && defined(Q_COMPILER_CONSTEXPR) -# include <QtCore/qatomic_cxx11.h> #elif defined(Q_CC_GNU) # include <QtCore/qatomic_gcc.h> diff --git a/src/corelib/thread/qexception.cpp b/src/corelib/thread/qexception.cpp index acc3663936..cecd69c273 100644 --- a/src/corelib/thread/qexception.cpp +++ b/src/corelib/thread/qexception.cpp @@ -107,6 +107,16 @@ QT_BEGIN_NAMESPACE \internal */ +QException::~QException() +#ifdef Q_COMPILER_NOEXCEPT + noexcept +#else + throw() +#endif +{ + // must stay empty until ### Qt 6 +} + void QException::raise() const { QException e = *this; @@ -118,6 +128,16 @@ QException *QException::clone() const return new QException(*this); } +QUnhandledException::~QUnhandledException() +#ifdef Q_COMPILER_NOEXCEPT + noexcept +#else + throw() +#endif +{ + // must stay empty until ### Qt 6 +} + void QUnhandledException::raise() const { QUnhandledException e = *this; @@ -145,7 +165,7 @@ public: }; ExceptionHolder::ExceptionHolder(QException *exception) -: base(new Base(exception)) {} +: base(exception ? new Base(exception) : Q_NULLPTR) {} ExceptionHolder::ExceptionHolder(const ExceptionHolder &other) : base(other.base) @@ -161,6 +181,8 @@ ExceptionHolder::~ExceptionHolder() QException *ExceptionHolder::exception() const { + if (!base) + return Q_NULLPTR; return base->exception; } diff --git a/src/corelib/thread/qexception.h b/src/corelib/thread/qexception.h index 55fc441020..dc988f9020 100644 --- a/src/corelib/thread/qexception.h +++ b/src/corelib/thread/qexception.h @@ -53,6 +53,13 @@ QT_BEGIN_NAMESPACE class Q_CORE_EXPORT QException : public std::exception { public: + ~QException() +#ifdef Q_COMPILER_NOEXCEPT + noexcept +#else + throw() +#endif + ; virtual void raise() const; virtual QException *clone() const; }; @@ -60,6 +67,13 @@ public: class Q_CORE_EXPORT QUnhandledException : public QException { public: + ~QUnhandledException() +#ifdef Q_COMPILER_NOEXCEPT + noexcept +#else + throw() +#endif + ; void raise() const Q_DECL_OVERRIDE; QUnhandledException *clone() const Q_DECL_OVERRIDE; }; @@ -70,9 +84,9 @@ class Base; class Q_CORE_EXPORT ExceptionHolder { public: - ExceptionHolder(QException *exception = 0); + ExceptionHolder(QException *exception = Q_NULLPTR); ExceptionHolder(const ExceptionHolder &other); - void operator=(const ExceptionHolder &other); + void operator=(const ExceptionHolder &other); // ### Qt6: copy-assign operator shouldn't return void. Remove this method and the copy-ctor, they are unneeded. ~ExceptionHolder(); QException *exception() const; QExplicitlySharedDataPointer<Base> base; diff --git a/src/corelib/thread/qfuture.qdoc b/src/corelib/thread/qfuture.qdoc index be4cee2bd6..ed0b26e121 100644 --- a/src/corelib/thread/qfuture.qdoc +++ b/src/corelib/thread/qfuture.qdoc @@ -352,6 +352,7 @@ /*! \class QFuture::const_iterator \reentrant \since 4.4 + \inmodule QtCore \brief The QFuture::const_iterator class provides an STL-style const iterator for QFuture. diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h index 01eb043a5e..8c1f7e7d82 100644 --- a/src/corelib/thread/qfutureinterface.h +++ b/src/corelib/thread/qfutureinterface.h @@ -299,7 +299,7 @@ public: void reportResult(const void *, int) { } void reportResults(const QVector<void> &, int) { } - void reportFinished(const void * = 0) { QFutureInterfaceBase::reportFinished(); } + void reportFinished(const void * = Q_NULLPTR) { QFutureInterfaceBase::reportFinished(); } }; QT_END_NAMESPACE diff --git a/src/corelib/thread/qfuturewatcher.cpp b/src/corelib/thread/qfuturewatcher.cpp index 3056216f6e..43eff83116 100644 --- a/src/corelib/thread/qfuturewatcher.cpp +++ b/src/corelib/thread/qfuturewatcher.cpp @@ -248,7 +248,7 @@ bool QFutureWatcherBase::isStarted() const /*! \fn bool QFutureWatcher::isFinished() const Returns \c true if the asynchronous computation represented by the future() - has finished; otherwise returns \c false. + has finished, or if no future has been set; otherwise returns \c false. */ bool QFutureWatcherBase::isFinished() const { @@ -304,15 +304,6 @@ void QFutureWatcherBase::waitForFinished() futureInterface().waitForFinished(); } -/*! \fn void QFutureWatcher::setPendingResultsLimit(int limit) - - The setPendingResultsLimit() provides throttling control. When the number - of pending resultReadyAt() or resultsReadyAt() signals exceeds the - \a limit, the computation represented by the future will be throttled - automatically. The computation will resume once the number of pending - signals drops below the \a limit. -*/ - bool QFutureWatcherBase::event(QEvent *event) { Q_D(QFutureWatcherBase); @@ -342,6 +333,14 @@ bool QFutureWatcherBase::event(QEvent *event) return QObject::event(event); } +/*! \fn void QFutureWatcher::setPendingResultsLimit(int limit) + + The setPendingResultsLimit() provides throttling control. When the number + of pending resultReadyAt() or resultsReadyAt() signals exceeds the + \a limit, the computation represented by the future will be throttled + automatically. The computation will resume once the number of pending + signals drops below the \a limit. +*/ void QFutureWatcherBase::setPendingResultsLimit(int limit) { Q_D(QFutureWatcherBase); @@ -379,7 +378,8 @@ void QFutureWatcherBase::disconnectNotify(const QMetaMethod &signal) */ QFutureWatcherBasePrivate::QFutureWatcherBasePrivate() : maximumPendingResultsReady(QThread::idealThreadCount() * 2), - resultAtConnected(0) + resultAtConnected(0), + finished(true) /* the initial m_future is a canceledResult(), with Finished set */ { } /*! @@ -400,7 +400,7 @@ void QFutureWatcherBase::disconnectOutputInterface(bool pendingAssignment) d->pendingResultsReady.store(0); qDeleteAll(d->pendingCallOutEvents); d->pendingCallOutEvents.clear(); - d->finished = false; + d->finished = false; /* May soon be amended, during connectOutputInterface() */ } futureInterface().d->disconnectOutputInterface(d_func()); diff --git a/src/corelib/thread/qfuturewatcher.h b/src/corelib/thread/qfuturewatcher.h index 63558d4a0f..42a22d9063 100644 --- a/src/corelib/thread/qfuturewatcher.h +++ b/src/corelib/thread/qfuturewatcher.h @@ -52,7 +52,7 @@ class Q_CORE_EXPORT QFutureWatcherBase : public QObject Q_DECLARE_PRIVATE(QFutureWatcherBase) public: - explicit QFutureWatcherBase(QObject *parent = 0); + explicit QFutureWatcherBase(QObject *parent = Q_NULLPTR); // de-inline dtor int progressValue() const; @@ -179,7 +179,7 @@ template <> class QFutureWatcher<void> : public QFutureWatcherBase { public: - explicit QFutureWatcher(QObject *_parent = 0) + explicit QFutureWatcher(QObject *_parent = Q_NULLPTR) : QFutureWatcherBase(_parent) { } ~QFutureWatcher() diff --git a/src/corelib/thread/qgenericatomic.h b/src/corelib/thread/qgenericatomic.h index a9a790c14c..d3e7d51efd 100644 --- a/src/corelib/thread/qgenericatomic.h +++ b/src/corelib/thread/qgenericatomic.h @@ -46,13 +46,6 @@ QT_END_NAMESPACE #pragma qt_sync_stop_processing #endif -#ifdef Q_CC_GNU -// lowercase is fine, we'll undef it below -#define always_inline __attribute__((always_inline, gnu_inline)) -#else -#define always_inline -#endif - template<int> struct QAtomicOpsSupport { enum { IsSupported = 0 }; }; template<> struct QAtomicOpsSupport<4> { enum { IsSupported = 1 }; }; @@ -84,19 +77,19 @@ template <typename BaseClass> struct QGenericAtomicOps { } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T load(const T &_q_value) Q_DECL_NOTHROW { return _q_value; } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE void store(T &_q_value, X newValue) Q_DECL_NOTHROW { _q_value = newValue; } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T loadAcquire(const T &_q_value) Q_DECL_NOTHROW { T tmp = *static_cast<const volatile T *>(&_q_value); @@ -104,7 +97,7 @@ template <typename BaseClass> struct QGenericAtomicOps return tmp; } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE void storeRelease(T &_q_value, X newValue) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); @@ -115,13 +108,13 @@ template <typename BaseClass> struct QGenericAtomicOps { return BaseClass::isFetchAndAddNative(); } static inline Q_DECL_CONSTEXPR bool isReferenceCountingWaitFree() Q_DECL_NOTHROW { return BaseClass::isFetchAndAddWaitFree(); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE bool ref(T &_q_value) Q_DECL_NOTHROW { return BaseClass::fetchAndAddRelaxed(_q_value, 1) != T(-1); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE bool deref(T &_q_value) Q_DECL_NOTHROW { return BaseClass::fetchAndAddRelaxed(_q_value, -1) != 1; @@ -138,7 +131,7 @@ template <typename BaseClass> struct QGenericAtomicOps bool testAndSetRelaxed(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW; #endif - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW { bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue); @@ -146,21 +139,21 @@ template <typename BaseClass> struct QGenericAtomicOps return tmp; } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE bool testAndSetRelease(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue); } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue); } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE bool testAndSetAcquire(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW { bool tmp = BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue); @@ -168,14 +161,14 @@ template <typename BaseClass> struct QGenericAtomicOps return tmp; } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE bool testAndSetRelease(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::testAndSetRelaxed(_q_value, expectedValue, newValue, currentValue); } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE bool testAndSetOrdered(T &_q_value, X expectedValue, X newValue, X *currentValue) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); @@ -185,7 +178,7 @@ template <typename BaseClass> struct QGenericAtomicOps static inline Q_DECL_CONSTEXPR bool isFetchAndStoreNative() Q_DECL_NOTHROW { return false; } static inline Q_DECL_CONSTEXPR bool isFetchAndStoreWaitFree() Q_DECL_NOTHROW { return false; } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE T fetchAndStoreRelaxed(T &_q_value, X newValue) Q_DECL_NOTHROW { // implement fetchAndStore on top of testAndSet @@ -196,7 +189,7 @@ template <typename BaseClass> struct QGenericAtomicOps } } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE T fetchAndStoreAcquire(T &_q_value, X newValue) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndStoreRelaxed(_q_value, newValue); @@ -204,14 +197,14 @@ template <typename BaseClass> struct QGenericAtomicOps return tmp; } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE T fetchAndStoreRelease(T &_q_value, X newValue) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndStoreRelaxed(_q_value, newValue); } - template <typename T, typename X> static inline always_inline + template <typename T, typename X> static Q_ALWAYS_INLINE T fetchAndStoreOrdered(T &_q_value, X newValue) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); @@ -220,7 +213,7 @@ template <typename BaseClass> struct QGenericAtomicOps static inline Q_DECL_CONSTEXPR bool isFetchAndAddNative() Q_DECL_NOTHROW { return false; } static inline Q_DECL_CONSTEXPR bool isFetchAndAddWaitFree() Q_DECL_NOTHROW { return false; } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndAddRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW { // implement fetchAndAdd on top of testAndSet @@ -231,7 +224,7 @@ template <typename BaseClass> struct QGenericAtomicOps } } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndAddAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd); @@ -239,28 +232,28 @@ template <typename BaseClass> struct QGenericAtomicOps return tmp; } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndAddRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndAddOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT valueToAdd) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::fetchAndAddRelaxed(_q_value, valueToAdd); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndSubRelaxed(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW { // implement fetchAndSub on top of fetchAndAdd return fetchAndAddRelaxed(_q_value, -operand); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndSubAcquire(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndSubRelaxed(_q_value, operand); @@ -268,21 +261,21 @@ template <typename BaseClass> struct QGenericAtomicOps return tmp; } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndSubRelease(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndSubRelaxed(_q_value, operand); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndSubOrdered(T &_q_value, typename QAtomicAdditiveType<T>::AdditiveT operand) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::fetchAndSubRelaxed(_q_value, operand); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndAndRelaxed(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { // implement fetchAndAnd on top of testAndSet @@ -293,7 +286,7 @@ template <typename BaseClass> struct QGenericAtomicOps } } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndAndAcquire(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndAndRelaxed(_q_value, operand); @@ -301,21 +294,21 @@ template <typename BaseClass> struct QGenericAtomicOps return tmp; } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndAndRelease(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndAndRelaxed(_q_value, operand); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndAndOrdered(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::fetchAndAndRelaxed(_q_value, operand); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndOrRelaxed(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { // implement fetchAndOr on top of testAndSet @@ -326,7 +319,7 @@ template <typename BaseClass> struct QGenericAtomicOps } } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndOrAcquire(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndOrRelaxed(_q_value, operand); @@ -334,21 +327,21 @@ template <typename BaseClass> struct QGenericAtomicOps return tmp; } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndOrRelease(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndOrRelaxed(_q_value, operand); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndOrOrdered(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); return BaseClass::fetchAndOrRelaxed(_q_value, operand); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndXorRelaxed(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { // implement fetchAndXor on top of testAndSet @@ -359,7 +352,7 @@ template <typename BaseClass> struct QGenericAtomicOps } } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndXorAcquire(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { T tmp = BaseClass::fetchAndXorRelaxed(_q_value, operand); @@ -367,14 +360,14 @@ template <typename BaseClass> struct QGenericAtomicOps return tmp; } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndXorRelease(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::releaseMemoryFence(_q_value); return BaseClass::fetchAndXorRelaxed(_q_value, operand); } - template <typename T> static inline always_inline + template <typename T> static Q_ALWAYS_INLINE T fetchAndXorOrdered(T &_q_value, typename QtPrivate::QEnableIf<QTypeInfo<T>::isIntegral, T>::Type operand) Q_DECL_NOTHROW { BaseClass::orderedMemoryFence(_q_value); @@ -382,7 +375,5 @@ template <typename BaseClass> struct QGenericAtomicOps } }; -#undef always_inline - QT_END_NAMESPACE #endif // QGENERICATOMIC_H diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 742a572bef..fa3bb080ae 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -139,6 +139,11 @@ public: lock calls unlock(). A non-blocking alternative to lock() is tryLock(). + QMutex is optimized to be fast in the non-contended case. A non-recursive + QMutex will not allocate memory if there is no contention on that mutex. + It is constructed and destroyed with almost no overhead, + which means it is fine to have many mutexes as part of other classes. + \sa QMutexLocker, QReadWriteLock, QSemaphore, QWaitCondition */ @@ -165,6 +170,8 @@ public: a thread may only lock a mutex once. The default is QMutex::NonRecursive. + Recursive mutexes are slower and take more memory than non-recursive ones. + \sa lock(), unlock() */ QMutex::QMutex(RecursionMode mode) diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index 63c488747f..0c5a73b4df 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -73,16 +73,16 @@ public: private: inline bool fastTryLock() Q_DECL_NOTHROW { - return d_ptr.testAndSetAcquire(0, dummyLocked()); + return d_ptr.testAndSetAcquire(Q_NULLPTR, dummyLocked()); } inline bool fastTryUnlock() Q_DECL_NOTHROW { - return d_ptr.testAndSetRelease(dummyLocked(), 0); + return d_ptr.testAndSetRelease(dummyLocked(), Q_NULLPTR); } inline bool fastTryLock(QMutexData *¤t) Q_DECL_NOTHROW { - return d_ptr.testAndSetAcquire(0, dummyLocked(), current); + return d_ptr.testAndSetAcquire(Q_NULLPTR, dummyLocked(), current); } inline bool fastTryUnlock(QMutexData *¤t) Q_DECL_NOTHROW { - return d_ptr.testAndSetRelease(dummyLocked(), 0, current); + return d_ptr.testAndSetRelease(dummyLocked(), Q_NULLPTR, current); } void lockInternal() QT_MUTEX_LOCK_NOEXCEPT; diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index c4130fdba5..c24ea58868 100644 --- a/src/corelib/thread/qmutex_win.cpp +++ b/src/corelib/thread/qmutex_win.cpp @@ -55,10 +55,10 @@ QMutexPrivate::~QMutexPrivate() bool QMutexPrivate::wait(int timeout) { -#ifndef Q_OS_WINRT - return (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0); -#else +#ifndef Q_OS_WINCE return (WaitForSingleObjectEx(event, timeout < 0 ? INFINITE : timeout, FALSE) == WAIT_OBJECT_0); +#else + return (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0); #endif } diff --git a/src/corelib/thread/qorderedmutexlocker_p.h b/src/corelib/thread/qorderedmutexlocker_p.h index c73a790820..54887342e7 100644 --- a/src/corelib/thread/qorderedmutexlocker_p.h +++ b/src/corelib/thread/qorderedmutexlocker_p.h @@ -47,6 +47,8 @@ #include <QtCore/qmutex.h> +#include <functional> + QT_BEGIN_NAMESPACE /* @@ -57,8 +59,8 @@ class QOrderedMutexLocker { public: QOrderedMutexLocker(QMutex *m1, QMutex *m2) - : mtx1((m1 == m2) ? m1 : (m1 < m2 ? m1 : m2)), - mtx2((m1 == m2) ? 0 : (m1 < m2 ? m2 : m1)), + : mtx1((m1 == m2) ? m1 : (std::less<QMutex *>()(m1, m2) ? m1 : m2)), + mtx2((m1 == m2) ? 0 : (std::less<QMutex *>()(m1, m2) ? m2 : m1)), locked(false) { relock(); diff --git a/src/corelib/thread/qresultstore.h b/src/corelib/thread/qresultstore.h index fbcb8ad3cd..7ecaa231b2 100644 --- a/src/corelib/thread/qresultstore.h +++ b/src/corelib/thread/qresultstore.h @@ -61,8 +61,8 @@ class ResultItem public: ResultItem(const void *_result, int _count) : m_count(_count), result(_result) { } // contruct with vector of results ResultItem(const void *_result) : m_count(0), result(_result) { } // construct with result - ResultItem() : m_count(0), result(0) { } - bool isValid() const { return result != 0; } + ResultItem() : m_count(0), result(Q_NULLPTR) { } + bool isValid() const { return result != Q_NULLPTR; } bool isVector() const { return m_count != 0; } int count() const { return (m_count == 0) ? 1 : m_count; } int m_count; // result is either a pointer to a result or to a vector of results, diff --git a/src/corelib/thread/qrunnable.cpp b/src/corelib/thread/qrunnable.cpp index 64a2613d27..04aa39a81e 100644 --- a/src/corelib/thread/qrunnable.cpp +++ b/src/corelib/thread/qrunnable.cpp @@ -31,6 +31,15 @@ ** ****************************************************************************/ +#include "qrunnable.h" + +QT_BEGIN_NAMESPACE + +QRunnable::~QRunnable() +{ + // Must be empty until ### Qt 6 +} + /*! \class QRunnable \inmodule QtCore @@ -98,3 +107,5 @@ \sa autoDelete(), QThreadPool */ + +QT_END_NAMESPACE diff --git a/src/corelib/thread/qrunnable.h b/src/corelib/thread/qrunnable.h index f00c58d51d..28d14a46c0 100644 --- a/src/corelib/thread/qrunnable.h +++ b/src/corelib/thread/qrunnable.h @@ -38,20 +38,21 @@ QT_BEGIN_NAMESPACE - -class QRunnable +class Q_CORE_EXPORT QRunnable { int ref; friend class QThreadPool; friend class QThreadPoolPrivate; friend class QThreadPoolThread; - +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + Q_DISABLE_COPY(QRunnable) +#endif public: virtual void run() = 0; QRunnable() : ref(0) { } - virtual ~QRunnable() { } + virtual ~QRunnable(); bool autoDelete() const { return ref != -1; } void setAutoDelete(bool _autoDelete) { ref = _autoDelete ? 0 : -1; } diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp index dc231a00f8..590479d68c 100644 --- a/src/corelib/thread/qthread.cpp +++ b/src/corelib/thread/qthread.cpp @@ -38,7 +38,6 @@ #include "qabstracteventdispatcher.h" #include <qeventloop.h> -#include <qhash.h> #include "qthread_p.h" #include "private/qcoreapplication_p.h" @@ -51,7 +50,8 @@ QT_BEGIN_NAMESPACE QThreadData::QThreadData(int initialRefCount) : _ref(initialRefCount), loopLevel(0), thread(0), threadId(0), - eventDispatcher(0), quitNow(false), canWait(true), isAdopted(false) + eventDispatcher(0), + quitNow(false), canWait(true), isAdopted(false), requiresCoreApplication(true) { // fprintf(stderr, "QThreadData %p created\n", this); } @@ -868,4 +868,28 @@ bool QThread::isInterruptionRequested() const return d->interruptionRequested; } +/*! + \class QDaemonThread + \since 5.5 + \brief The QDaemonThread provides a class to manage threads that outlive QCoreApplication + \internal + + Note: don't try to deliver events from the started() signal. +*/ +static void setThreadDoesNotRequireCoreApplication() +{ + QThreadData::current()->requiresCoreApplication = false; +} + +QDaemonThread::QDaemonThread(QObject *parent) + : QThread(parent) +{ + // QThread::started() is emitted from the thread we start + connect(this, &QThread::started, setThreadDoesNotRequireCoreApplication); +} + +QDaemonThread::~QDaemonThread() +{ +} + QT_END_NAMESPACE diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h index bfc469583d..d333980bf4 100644 --- a/src/corelib/thread/qthread.h +++ b/src/corelib/thread/qthread.h @@ -55,7 +55,7 @@ public: static int idealThreadCount() Q_DECL_NOTHROW; static void yieldCurrentThread(); - explicit QThread(QObject *parent = 0); + explicit QThread(QObject *parent = Q_NULLPTR); ~QThread(); enum Priority { @@ -116,7 +116,7 @@ protected: static void setTerminationEnabled(bool enabled = true); protected: - QThread(QThreadPrivate &dd, QObject *parent = 0); + QThread(QThreadPrivate &dd, QObject *parent = Q_NULLPTR); private: Q_DECLARE_PRIVATE(QThread) diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h index 8331816729..a0d354acdc 100644 --- a/src/corelib/thread/qthread_p.h +++ b/src/corelib/thread/qthread_p.h @@ -135,6 +135,13 @@ private: #ifndef QT_NO_THREAD +class Q_CORE_EXPORT QDaemonThread : public QThread +{ +public: + QDaemonThread(QObject *parent = 0); + ~QDaemonThread(); +}; + class QThreadPrivate : public QObjectPrivate { Q_DECLARE_PUBLIC(QThread) @@ -224,7 +231,7 @@ public: QThreadData(int initialRefCount = 1); ~QThreadData(); - static QThreadData *current(bool createIfNecessary = true); + static Q_AUTOTEST_EXPORT QThreadData *current(bool createIfNecessary = true); static void clearCurrentThreadData(); static QThreadData *get2(QThread *thread) { Q_ASSERT_X(thread != 0, "QThread", "internal error"); return thread->d_func()->data; } @@ -278,6 +285,7 @@ public: bool quitNow; bool canWait; bool isAdopted; + bool requiresCoreApplication; }; class QScopedLoopLevelCounter diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp index 5698a61326..af4ce7c59e 100644 --- a/src/corelib/thread/qthread_unix.cpp +++ b/src/corelib/thread/qthread_unix.cpp @@ -36,9 +36,13 @@ #include "qplatformdefs.h" #include <private/qcoreapplication_p.h> +#include <private/qcore_unix_p.h> #if defined(Q_OS_BLACKBERRY) # include <private/qeventdispatcher_blackberry_p.h> +#elif defined(Q_OS_OSX) +# include <private/qeventdispatcher_cf_p.h> +# include <private/qeventdispatcher_unix_p.h> #else # if !defined(QT_NO_GLIB) # include "../kernel/qeventdispatcher_glib_p.h" @@ -75,9 +79,6 @@ # define old_qDebug qDebug # undef qDebug # endif -#ifdef Q_OS_MACX -# include <CoreServices/CoreServices.h> -#endif // Q_OS_MACX # ifdef old_qDebug # undef qDebug @@ -251,14 +252,21 @@ void QThreadPrivate::createEventDispatcher(QThreadData *data) { #if defined(Q_OS_BLACKBERRY) data->eventDispatcher.storeRelease(new QEventDispatcherBlackberry); -#else -#if !defined(QT_NO_GLIB) +# elif defined(Q_OS_OSX) + bool ok = false; + int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok); + if (ok && value > 0) + data->eventDispatcher.storeRelease(new QEventDispatcherCoreFoundation); + else + data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); +# elif !defined(QT_NO_GLIB) if (qEnvironmentVariableIsEmpty("QT_NO_GLIB") && qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB") && QEventDispatcherGlib::versionSupported()) data->eventDispatcher.storeRelease(new QEventDispatcherGlib); else -#endif + data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); +#else data->eventDispatcher.storeRelease(new QEventDispatcherUNIX); #endif @@ -313,14 +321,15 @@ void *QThreadPrivate::start(void *arg) createEventDispatcher(data); #if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX)) - // sets the name of the current thread. - QString objectName = thr->objectName(); - - if (Q_LIKELY(objectName.isEmpty())) - setCurrentThreadName(thr->d_func()->thread_id, thr->metaObject()->className()); - else - setCurrentThreadName(thr->d_func()->thread_id, objectName.toLocal8Bit()); + { + // sets the name of the current thread. + QString objectName = thr->objectName(); + if (Q_LIKELY(objectName.isEmpty())) + setCurrentThreadName(thr->d_func()->thread_id, thr->metaObject()->className()); + else + setCurrentThreadName(thr->d_func()->thread_id, objectName.toLocal8Bit()); + } #endif emit thr->started(QThread::QPrivateSignal()); diff --git a/src/corelib/thread/qthread_win.cpp b/src/corelib/thread/qthread_win.cpp index a4b853d62e..32e8a52a28 100644 --- a/src/corelib/thread/qthread_win.cpp +++ b/src/corelib/thread/qthread_win.cpp @@ -32,7 +32,7 @@ ****************************************************************************/ //#define WINVER 0x0500 -#if !defined Q_OS_WINRT && (_WIN32_WINNT < 0x0400) +#if !defined(WINAPI_FAMILY) && (_WIN32_WINNT < 0x0400) #define _WIN32_WINNT 0x0400 #endif @@ -69,6 +69,30 @@ #ifndef QT_NO_THREAD QT_BEGIN_NAMESPACE +#ifdef Q_OS_WINRT +inline DWORD qWinRTTlsAlloc() { + return FlsAlloc(0); +} + +inline bool qWinRTTlsFree(DWORD dwTlsIndex) { + return FlsFree(dwTlsIndex); +} + +inline LPVOID qWinRTTlsGetValue(DWORD dwTlsIndex) { + return FlsGetValue(dwTlsIndex); +} + +inline bool qWinRTTlsSetValue(DWORD dwTlsIndex, LPVOID lpTlsValue) { + return FlsSetValue(dwTlsIndex, lpTlsValue); +} + +#define TlsAlloc qWinRTTlsAlloc +#define TlsFree qWinRTTlsFree +#define TlsSetValue qWinRTTlsSetValue +#define TlsGetValue qWinRTTlsGetValue + +#endif // Q_OS_WINRT + void qt_watch_adopted_thread(const HANDLE adoptedThreadHandle, QThread *qthread); DWORD WINAPI qt_adopted_thread_watcher_function(LPVOID); @@ -118,7 +142,7 @@ QThreadData *QThreadData::current(bool createIfNecessary) } threadData->deref(); threadData->isAdopted = true; - threadData->threadId = reinterpret_cast<Qt::HANDLE>(GetCurrentThreadId()); + threadData->threadId = reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId())); if (!QCoreApplicationPrivate::theMainThread) { QCoreApplicationPrivate::theMainThread = threadData->thread.load(); @@ -340,7 +364,7 @@ unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(voi qt_create_tls(); TlsSetValue(qt_current_thread_data_tls_index, data); - data->threadId = reinterpret_cast<Qt::HANDLE>(GetCurrentThreadId()); + data->threadId = reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId())); QThread::setTerminationEnabled(false); @@ -413,7 +437,7 @@ void QThreadPrivate::finish(void *arg, bool lockAnyway) Qt::HANDLE QThread::currentThreadId() Q_DECL_NOTHROW { - return reinterpret_cast<Qt::HANDLE>(GetCurrentThreadId()); + return reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId())); } int QThread::idealThreadCount() Q_DECL_NOTHROW diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp index b6b3be8d92..e4a5368281 100644 --- a/src/corelib/thread/qthreadpool.cpp +++ b/src/corelib/thread/qthreadpool.cpp @@ -204,8 +204,8 @@ void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority) ++runnable->ref; // put it on the queue - QList<QPair<QRunnable *, int> >::const_iterator begin = queue.constBegin(); - QList<QPair<QRunnable *, int> >::const_iterator it = queue.constEnd(); + QVector<QPair<QRunnable *, int> >::const_iterator begin = queue.constBegin(); + QVector<QPair<QRunnable *, int> >::const_iterator it = queue.constEnd(); if (it != begin && priority > (*(it - 1)).second) it = std::upper_bound(begin, --it, priority); queue.insert(it - begin, qMakePair(runnable, priority)); @@ -299,7 +299,7 @@ bool QThreadPoolPrivate::waitForDone(int msecs) void QThreadPoolPrivate::clear() { QMutexLocker locker(&mutex); - for (QList<QPair<QRunnable *, int> >::const_iterator it = queue.constBegin(); + for (QVector<QPair<QRunnable *, int> >::const_iterator it = queue.constBegin(); it != queue.constEnd(); ++it) { QRunnable* r = it->first; if (r->autoDelete() && !--r->ref) @@ -319,8 +319,8 @@ bool QThreadPoolPrivate::stealRunnable(QRunnable *runnable) return false; { QMutexLocker locker(&mutex); - QList<QPair<QRunnable *, int> >::iterator it = queue.begin(); - QList<QPair<QRunnable *, int> >::iterator end = queue.end(); + QVector<QPair<QRunnable *, int> >::iterator it = queue.begin(); + QVector<QPair<QRunnable *, int> >::iterator end = queue.end(); while (it != end) { if (it->first == runnable) { diff --git a/src/corelib/thread/qthreadpool.h b/src/corelib/thread/qthreadpool.h index b1ca808a99..95b41a0417 100644 --- a/src/corelib/thread/qthreadpool.h +++ b/src/corelib/thread/qthreadpool.h @@ -55,7 +55,7 @@ class Q_CORE_EXPORT QThreadPool : public QObject friend class QFutureInterfaceBase; public: - QThreadPool(QObject *parent = 0); + QThreadPool(QObject *parent = Q_NULLPTR); ~QThreadPool(); static QThreadPool *globalInstance(); diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h index 34728ed3e2..b03eefcc94 100644 --- a/src/corelib/thread/qthreadpool_p.h +++ b/src/corelib/thread/qthreadpool_p.h @@ -83,7 +83,7 @@ public: QSet<QThreadPoolThread *> allThreads; QQueue<QThreadPoolThread *> waitingThreads; QQueue<QThreadPoolThread *> expiredThreads; - QList<QPair<QRunnable *, int> > queue; + QVector<QPair<QRunnable *, int> > queue; QWaitCondition noActiveThreads; bool isExiting; diff --git a/src/corelib/thread/qwaitcondition_unix.cpp b/src/corelib/thread/qwaitcondition_unix.cpp index fd6af7db39..89bf523263 100644 --- a/src/corelib/thread/qwaitcondition_unix.cpp +++ b/src/corelib/thread/qwaitcondition_unix.cpp @@ -77,7 +77,7 @@ void qt_initialize_pthread_cond(pthread_cond_t *cond, const char *where) #if defined(Q_OS_ANDROID) if (local_condattr_setclock && QElapsedTimer::clockType() == QElapsedTimer::MonotonicClock) local_condattr_setclock(&condattr, CLOCK_MONOTONIC); -#elif !defined(Q_OS_MAC) && !defined(Q_OS_HAIKU) +#elif !defined(Q_OS_MAC) if (QElapsedTimer::clockType() == QElapsedTimer::MonotonicClock) pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC); #endif diff --git a/src/corelib/thread/qwaitcondition_win.cpp b/src/corelib/thread/qwaitcondition_win.cpp index ef8330570e..3ea34461d3 100644 --- a/src/corelib/thread/qwaitcondition_win.cpp +++ b/src/corelib/thread/qwaitcondition_win.cpp @@ -109,10 +109,10 @@ bool QWaitConditionPrivate::wait(QWaitConditionEvent *wce, unsigned long time) { // wait for the event bool ret = false; -#ifndef Q_OS_WINRT - switch (WaitForSingleObject(wce->event, time)) { -#else +#ifndef Q_OS_WINCE switch (WaitForSingleObjectEx(wce->event, time, FALSE)) { +#else + switch (WaitForSingleObject(wce->event, time)) { #endif default: break; |