summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/thread')
-rw-r--r--src/corelib/thread/qatomic.cpp82
-rw-r--r--src/corelib/thread/qatomic.h5
-rw-r--r--src/corelib/thread/qfuture_impl.h12
-rw-r--r--src/corelib/thread/qfutureinterface.cpp60
-rw-r--r--src/corelib/thread/qfutureinterface.h4
-rw-r--r--src/corelib/thread/qfutureinterface_p.h5
-rw-r--r--src/corelib/thread/qfuturesynchronizer.h4
-rw-r--r--src/corelib/thread/qlocking_p.h7
-rw-r--r--src/corelib/thread/qmutex.cpp4
-rw-r--r--src/corelib/thread/qmutex.h8
-rw-r--r--src/corelib/thread/qmutex_p.h9
-rw-r--r--src/corelib/thread/qmutex_win.cpp30
-rw-r--r--src/corelib/thread/qpromise.h1
-rw-r--r--src/corelib/thread/qpromise.qdoc2
-rw-r--r--src/corelib/thread/qresultstore.h10
-rw-r--r--src/corelib/thread/qsemaphore.cpp5
-rw-r--r--src/corelib/thread/qthread.cpp10
-rw-r--r--src/corelib/thread/qthread.h4
-rw-r--r--src/corelib/thread/qthread_unix.cpp3
-rw-r--r--src/corelib/thread/qthreadpool.cpp34
-rw-r--r--src/corelib/thread/qthreadpool_p.h2
-rw-r--r--src/corelib/thread/qthreadstorage.cpp6
-rw-r--r--src/corelib/thread/qwaitcondition.qdoc6
-rw-r--r--src/corelib/thread/qwaitcondition_p.h7
-rw-r--r--src/corelib/thread/qwaitcondition_win.cpp4
25 files changed, 216 insertions, 108 deletions
diff --git a/src/corelib/thread/qatomic.cpp b/src/corelib/thread/qatomic.cpp
index 0184774b44..210218d72d 100644
--- a/src/corelib/thread/qatomic.cpp
+++ b/src/corelib/thread/qatomic.cpp
@@ -397,14 +397,21 @@
Atomic test-and-set.
+ \note If you use this function in a loop, consider using the overload with the
+ additional \c{T &currentValue} argument instead, which avoids the extra load() on
+ failure.
+
If the current value of this QAtomicInteger is the \a expectedValue,
the test-and-set functions assign the \a newValue to this
QAtomicInteger and return true. If the values are \e not the same,
this function does nothing and returns \c false.
+//![memory-order-relaxed]
This function uses \e relaxed \l {QAtomicInteger#Memory
ordering}{memory ordering} semantics, leaving the compiler and
processor to freely reorder memory accesses.
+//![memory-order-relaxed]
+
*/
/*!
@@ -412,15 +419,21 @@
Atomic test-and-set.
+ \note If you use this function in a loop, consider using the overload with the
+ additional \c{T &currentValue} argument instead, which avoids the extra load() on
+ failure.
+
If the current value of this QAtomicInteger is the \a expectedValue,
the test-and-set functions assign the \a newValue to this
QAtomicInteger and return true. If the values are \e not the same,
this function does nothing and returns \c false.
+//![memory-order-acquire]
This function uses \e acquire \l {QAtomicInteger#Memory
ordering}{memory ordering} semantics, which ensures that memory
access following the atomic operation (in program order) may not
be re-ordered before the atomic operation.
+//![memory-order-acquire]
*/
/*!
@@ -428,15 +441,21 @@
Atomic test-and-set.
+ \note If you use this function in a loop, consider using the overload with the
+ additional \c{T &currentValue} argument instead, which avoids the extra load() on
+ failure.
+
If the current value of this QAtomicInteger is the \a expectedValue,
the test-and-set functions assign the \a newValue to this
QAtomicInteger and return true. If the values are \e not the same,
this function does nothing and returns \c false.
+//![memory-order-release]
This function uses \e release \l {QAtomicInteger#Memory
ordering}{memory ordering} semantics, which ensures that memory
access before the atomic operation (in program order) may not be
re-ordered after the atomic operation.
+//![memory-order-release]
*/
/*!
@@ -444,15 +463,78 @@
Atomic test-and-set.
+ \note If you use this function in a loop, consider using the overload with the
+ additional \c{T &currentValue} argument instead, which avoids the extra load() on
+ failure.
+
If the current value of this QAtomicInteger is the \a expectedValue,
the test-and-set functions assign the \a newValue to this
QAtomicInteger and return true. If the values are \e not the same,
this function does nothing and returns \c false.
+//![memory-order-ordered]
This function uses \e ordered \l {QAtomicInteger#Memory
ordering}{memory ordering} semantics, which ensures that memory
access before and after the atomic operation (in program order)
may not be re-ordered.
+//![memory-order-ordered]
+
+*/
+
+/*!
+ \fn template <typename T> bool QAtomicInteger<T>::testAndSetRelaxed(T expectedValue, T newValue, T &currentValue)
+ \since 5.3
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInteger is the \a expectedValue, the
+ test-and-set functions assign the \a newValue to this QAtomicInteger and
+ return \c true. If the values are \e not the same, the functions load the
+ current value of this QAtomicInteger into \a currentValue and return \c false.
+
+ \include qatomic.cpp memory-order-relaxed
+*/
+
+/*!
+ \fn template <typename T> bool QAtomicInteger<T>::testAndSetAcquire(T expectedValue, T newValue, T &currentValue)
+ \since 5.3
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInteger is the \a expectedValue, the
+ test-and-set functions assign the \a newValue to this QAtomicInteger and
+ return \c true. If the values are \e not the same, the functions load the
+ current value of this QAtomicInteger into \a currentValue and return \c false.
+
+ \include qatomic.cpp memory-order-acquire
+*/
+
+/*!
+ \fn template <typename T> bool QAtomicInteger<T>::testAndSetRelease(T expectedValue, T newValue, T &currentValue)
+ \since 5.3
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInteger is the \a expectedValue, the
+ test-and-set functions assign the \a newValue to this QAtomicInteger and
+ return \c true. If the values are \e not the same, the functions loads the
+ current value of this QAtomicInteger into \a currentValue and return \c false.
+
+ \include qatomic.cpp memory-order-release
+*/
+
+/*!
+ \fn template <typename T> bool QAtomicInteger<T>::testAndSetOrdered(T expectedValue, T newValue, T &currentValue)
+ \since 5.3
+
+ Atomic test-and-set.
+
+ If the current value of this QAtomicInteger is the \a expectedValue, the
+ test-and-set functions assign the \a newValue to this QAtomicInteger and
+ return \c true. If the values are \e not the same, it loads the current
+ value of this QAtomicInteger into \a currentValue and return \c false.
+
+ \include qatomic.cpp memory-order-ordered
*/
/*!
diff --git a/src/corelib/thread/qatomic.h b/src/corelib/thread/qatomic.h
index a4c9c23fbe..b11e3f1bdf 100644
--- a/src/corelib/thread/qatomic.h
+++ b/src/corelib/thread/qatomic.h
@@ -70,6 +70,11 @@ public:
bool testAndSetRelease(T expectedValue, T newValue);
bool testAndSetOrdered(T expectedValue, T newValue);
+ bool testAndSetRelaxed(T expectedValue, T newValue, T &currentValue);
+ bool testAndSetAcquire(T expectedValue, T newValue, T &currentValue);
+ bool testAndSetRelease(T expectedValue, T newValue, T &currentValue);
+ bool testAndSetOrdered(T expectedValue, T newValue, T &currentValue);
+
static constexpr bool isFetchAndStoreNative();
static constexpr bool isFetchAndStoreWaitFree();
diff --git a/src/corelib/thread/qfuture_impl.h b/src/corelib/thread/qfuture_impl.h
index 8e96b943ef..80aa3e8d7a 100644
--- a/src/corelib/thread/qfuture_impl.h
+++ b/src/corelib/thread/qfuture_impl.h
@@ -590,14 +590,14 @@ void Continuation<Function, ResultType, ParentResultType>::create(F &&func,
{
Q_ASSERT(f);
- auto continuation = [func = std::forward<F>(func), promise = QPromise(fi),
+ auto continuation = [func = std::forward<F>(func), fi,
context = QPointer<QObject>(context)](
const QFutureInterfaceBase &parentData) mutable {
Q_ASSERT(context);
const auto parent = QFutureInterface<ParentResultType>(parentData).future();
QMetaObject::invokeMethod(
context,
- [func = std::forward<F>(func), promise = std::move(promise), parent]() mutable {
+ [func = std::forward<F>(func), promise = QPromise(fi), parent]() mutable {
SyncContinuation<Function, ResultType, ParentResultType> continuationJob(
std::forward<Function>(func), parent, std::move(promise));
continuationJob.execute();
@@ -689,13 +689,13 @@ void FailureHandler<Function, ResultType>::create(F &&function, QFuture<ResultTy
Q_ASSERT(future);
auto failureContinuation =
- [function = std::forward<F>(function), promise = QPromise(fi),
+ [function = std::forward<F>(function), fi,
context = QPointer<QObject>(context)](const QFutureInterfaceBase &parentData) mutable {
Q_ASSERT(context);
const auto parent = QFutureInterface<ResultType>(parentData).future();
QMetaObject::invokeMethod(context,
[function = std::forward<F>(function),
- promise = std::move(promise), parent]() mutable {
+ promise = QPromise(fi), parent]() mutable {
FailureHandler<Function, ResultType> failureHandler(
std::forward<Function>(function), parent, std::move(promise));
failureHandler.run();
@@ -788,13 +788,13 @@ public:
QObject *context)
{
Q_ASSERT(future);
- auto canceledContinuation = [promise = QPromise(fi), handler = std::forward<F>(handler),
+ auto canceledContinuation = [fi, handler = std::forward<F>(handler),
context = QPointer<QObject>(context)](
const QFutureInterfaceBase &parentData) mutable {
Q_ASSERT(context);
auto parentFuture = QFutureInterface<ResultType>(parentData).future();
QMetaObject::invokeMethod(context,
- [promise = std::move(promise), parentFuture,
+ [promise = QPromise(fi), parentFuture,
handler = std::forward<F>(handler)]() mutable {
run(std::forward<F>(handler), parentFuture, std::move(promise));
});
diff --git a/src/corelib/thread/qfutureinterface.cpp b/src/corelib/thread/qfutureinterface.cpp
index a82b7af873..ed46052fa7 100644
--- a/src/corelib/thread/qfutureinterface.cpp
+++ b/src/corelib/thread/qfutureinterface.cpp
@@ -105,6 +105,13 @@ void QFutureInterfaceBase::cancel(QFutureInterfaceBase::CancelMode mode)
break;
}
+ // Cancel the continuations chain
+ QFutureInterfaceBasePrivate *next = d->continuationData;
+ while (next) {
+ next->continuationState = QFutureInterfaceBasePrivate::Canceled;
+ next = next->continuationData;
+ }
+
d->waitCondition.wakeAll();
d->pausedWaitCondition.wakeAll();
@@ -719,7 +726,7 @@ void QFutureInterfaceBasePrivate::sendCallOut(const QFutureCallOutEvent &callOut
if (outputConnections.isEmpty())
return;
- for (int i = 0; i < outputConnections.count(); ++i)
+ for (int i = 0; i < outputConnections.size(); ++i)
outputConnections.at(i)->postCallOutEvent(callOutEvent);
}
@@ -729,7 +736,7 @@ void QFutureInterfaceBasePrivate::sendCallOuts(const QFutureCallOutEvent &callOu
if (outputConnections.isEmpty())
return;
- for (int i = 0; i < outputConnections.count(); ++i) {
+ for (int i = 0; i < outputConnections.size(); ++i) {
QFutureCallOutInterface *interface = outputConnections.at(i);
interface->postCallOutEvent(callOutEvent1);
interface->postCallOutEvent(callOutEvent2);
@@ -816,45 +823,56 @@ void QFutureInterfaceBase::setContinuation(std::function<void(const QFutureInter
{
QMutexLocker lock(&d->continuationMutex);
- if (continuationFutureData)
- continuationFutureData->parentData = d;
-
// If the state is ready, run continuation immediately,
// otherwise save it for later.
if (isFinished()) {
lock.unlock();
func(*this);
- } else {
+ lock.relock();
+ }
+ // Unless the continuation has been cleaned earlier, we have to
+ // store the move-only continuation, to guarantee that the associated
+ // future's data stays alive.
+ if (d->continuationState != QFutureInterfaceBasePrivate::Cleaned) {
d->continuation = std::move(func);
+ d->continuationData = continuationFutureData;
}
}
+void QFutureInterfaceBase::cleanContinuation()
+{
+ if (!d)
+ return;
+
+ QMutexLocker lock(&d->continuationMutex);
+ d->continuation = nullptr;
+ d->continuationState = QFutureInterfaceBasePrivate::Cleaned;
+ d->continuationData = nullptr;
+}
+
void QFutureInterfaceBase::runContinuation() const
{
QMutexLocker lock(&d->continuationMutex);
if (d->continuation) {
- auto fn = std::exchange(d->continuation, nullptr);
+ // Save the continuation in a local function, to avoid calling
+ // a null std::function below, in case cleanContinuation() is
+ // called from some other thread right after unlock() below.
+ auto fn = std::move(d->continuation);
lock.unlock();
fn(*this);
+
+ lock.relock();
+ // Unless the continuation has been cleaned earlier, we have to
+ // store the move-only continuation, to guarantee that the associated
+ // future's data stays alive.
+ if (d->continuationState != QFutureInterfaceBasePrivate::Cleaned)
+ d->continuation = std::move(fn);
}
}
bool QFutureInterfaceBase::isChainCanceled() const
{
- if (isCanceled())
- return true;
-
- auto parent = d->parentData;
- while (parent) {
- // If the future is in Canceled state because it had an exception, we want to
- // continue checking the chain of parents for cancellation, otherwise if the exception
- // is handled inside the chain, it won't be interrupted even though cancellation has
- // been requested.
- if ((parent->state.loadRelaxed() & Canceled) && !parent->hasException)
- return true;
- parent = parent->parentData;
- }
- return false;
+ return isCanceled() || d->continuationState == QFutureInterfaceBasePrivate::Canceled;
}
void QFutureInterfaceBase::setLaunchAsync(bool value)
diff --git a/src/corelib/thread/qfutureinterface.h b/src/corelib/thread/qfutureinterface.h
index 820faa9ec2..418f19866d 100644
--- a/src/corelib/thread/qfutureinterface.h
+++ b/src/corelib/thread/qfutureinterface.h
@@ -183,9 +183,7 @@ protected:
void setContinuation(std::function<void(const QFutureInterfaceBase &)> func);
void setContinuation(std::function<void(const QFutureInterfaceBase &)> func,
QFutureInterfaceBasePrivate *continuationFutureData);
-#if QT_CORE_REMOVED_SINCE(6, 4)
void cleanContinuation();
-#endif
void runContinuation() const;
void setLaunchAsync(bool value);
@@ -349,7 +347,7 @@ inline bool QFutureInterface<T>::reportResults(const QList<T> &_results, int beg
if (store.filterMode()) {
this->reportResultsReady(resultCountBefore, store.count());
} else {
- this->reportResultsReady(insertIndex, insertIndex + _results.count());
+ this->reportResultsReady(insertIndex, insertIndex + _results.size());
}
return true;
}
diff --git a/src/corelib/thread/qfutureinterface_p.h b/src/corelib/thread/qfutureinterface_p.h
index ec3517bab3..6258e61de7 100644
--- a/src/corelib/thread/qfutureinterface_p.h
+++ b/src/corelib/thread/qfutureinterface_p.h
@@ -141,7 +141,10 @@ public:
QThreadPool *m_pool = nullptr;
// Wrapper for continuation
std::function<void(const QFutureInterfaceBase &)> continuation;
- QFutureInterfaceBasePrivate *parentData = nullptr;
+ QFutureInterfaceBasePrivate *continuationData = nullptr;
+
+ enum ContinuationState : quint8 { Default, Canceled, Cleaned };
+ std::atomic<ContinuationState> continuationState { Default };
RefCount refCount = 1;
QAtomicInt state; // reads and writes can happen unprotected, both must be atomic
diff --git a/src/corelib/thread/qfuturesynchronizer.h b/src/corelib/thread/qfuturesynchronizer.h
index 8b85e20038..2cf2ca1b76 100644
--- a/src/corelib/thread/qfuturesynchronizer.h
+++ b/src/corelib/thread/qfuturesynchronizer.h
@@ -38,12 +38,12 @@ public:
void waitForFinished()
{
if (m_cancelOnWait) {
- for (int i = 0; i < m_futures.count(); ++i) {
+ for (int i = 0; i < m_futures.size(); ++i) {
m_futures[i].cancel();
}
}
- for (int i = 0; i < m_futures.count(); ++i) {
+ for (int i = 0; i < m_futures.size(); ++i) {
m_futures[i].waitForFinished();
}
}
diff --git a/src/corelib/thread/qlocking_p.h b/src/corelib/thread/qlocking_p.h
index 0c205fff66..9fa7e70da9 100644
--- a/src/corelib/thread/qlocking_p.h
+++ b/src/corelib/thread/qlocking_p.h
@@ -8,10 +8,9 @@
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. It exists for the convenience
-// of qmutex.cpp, qmutex_unix.cpp, and qmutex_win.cpp. This header
-// file may change from version to version without notice, or even be
-// removed.
+// This file is not part of the Qt API. It exists for the convenience of
+// qmutex.cpp and qmutex_unix.cpp. This header file may change from version to
+// version without notice, or even be removed.
//
// We mean it.
//
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
index fb15606ec0..7b4aac9532 100644
--- a/src/corelib/thread/qmutex.cpp
+++ b/src/corelib/thread/qmutex.cpp
@@ -865,12 +865,10 @@ void QMutexPrivate::derefWaiters(int value) noexcept
QT_END_NAMESPACE
-#if defined(Q_OS_LINUX) && defined(QT_ALWAYS_USE_FUTEX)
+#if defined(QT_ALWAYS_USE_FUTEX)
// nothing
#elif defined(Q_OS_MAC)
# include "qmutex_mac.cpp"
-#elif defined(Q_OS_WIN)
-# include "qmutex_win.cpp"
#else
# include "qmutex_unix.cpp"
#endif
diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h
index 036fde729b..ce7b5275ac 100644
--- a/src/corelib/thread/qmutex.h
+++ b/src/corelib/thread/qmutex.h
@@ -9,10 +9,8 @@
#include <QtCore/qtsan_impl.h>
#include <new>
-#if __has_include(<chrono>)
-# include <chrono>
-# include <limits>
-#endif
+#include <chrono>
+#include <limits>
class tst_QMutex;
@@ -31,7 +29,6 @@ class QMutex;
class QRecursiveMutex;
class QMutexPrivate;
-#if __has_include(<chrono>)
namespace QtPrivate
{
template<class Rep, class Period>
@@ -57,7 +54,6 @@ namespace QtPrivate
return ms < maxInt ? int(ms) : maxInt;
}
}
-#endif
class Q_CORE_EXPORT QBasicMutex
{
diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h
index 9985a068c5..e5932d0a66 100644
--- a/src/corelib/thread/qmutex_p.h
+++ b/src/corelib/thread/qmutex_p.h
@@ -10,10 +10,9 @@
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. It exists for the convenience
-// of qmutex.cpp, qmutex_unix.cpp, and qmutex_win.cpp. This header
-// file may change from version to version without notice, or even be
-// removed.
+// This file is not part of the Qt API. It exists for the convenience of
+// qmutex.cpp and qmutex_unix.cpp. This header file may change from version to
+// version without notice, or even be removed.
//
// We mean it.
//
@@ -90,8 +89,6 @@ public:
bool wakeup;
pthread_mutex_t mutex;
pthread_cond_t cond;
-#elif defined(Q_OS_WIN)
- Qt::HANDLE event;
#endif
};
diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp
deleted file mode 100644
index 8c7741c113..0000000000
--- a/src/corelib/thread/qmutex_win.cpp
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (C) 2016 The Qt Company Ltd.
-// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
-
-#include "qmutex.h"
-#include <qatomic.h>
-#include "qmutex_p.h"
-#include <qt_windows.h>
-
-QT_BEGIN_NAMESPACE
-
-QMutexPrivate::QMutexPrivate()
-{
- event = CreateEvent(0, FALSE, FALSE, 0);
-
- if (!event)
- qWarning("QMutexPrivate::QMutexPrivate: Cannot create event");
-}
-
-QMutexPrivate::~QMutexPrivate()
-{ CloseHandle(event); }
-
-bool QMutexPrivate::wait(int timeout)
-{
- return (WaitForSingleObjectEx(event, timeout < 0 ? INFINITE : timeout, FALSE) == WAIT_OBJECT_0);
-}
-
-void QMutexPrivate::wakeUp() noexcept
-{ SetEvent(event); }
-
-QT_END_NAMESPACE
diff --git a/src/corelib/thread/qpromise.h b/src/corelib/thread/qpromise.h
index d0f6e6ae66..43c30582be 100644
--- a/src/corelib/thread/qpromise.h
+++ b/src/corelib/thread/qpromise.h
@@ -41,6 +41,7 @@ public:
d.cancelAndFinish(); // cancel and finalize the state
d.runContinuation();
}
+ d.cleanContinuation();
}
// Core QPromise APIs
diff --git a/src/corelib/thread/qpromise.qdoc b/src/corelib/thread/qpromise.qdoc
index 09907c4e0e..a3af927e8d 100644
--- a/src/corelib/thread/qpromise.qdoc
+++ b/src/corelib/thread/qpromise.qdoc
@@ -38,6 +38,8 @@
\snippet snippet_qpromise.cpp multithread_init
\codeline
\snippet snippet_qpromise.cpp multithread_main
+ \codeline
+ \snippet snippet_qpromise.cpp multithread_cleanup
\sa QFuture
*/
diff --git a/src/corelib/thread/qresultstore.h b/src/corelib/thread/qresultstore.h
index f633ed7801..af559b7a96 100644
--- a/src/corelib/thread/qresultstore.h
+++ b/src/corelib/thread/qresultstore.h
@@ -71,7 +71,7 @@ public:
template <typename T>
T *pointer()
{
- const T *p = qAsConst(*this).pointer<T>();
+ const T *p = std::as_const(*this).pointer<T>();
return const_cast<T *>(p);
}
@@ -164,23 +164,23 @@ public:
if (containsValidResultItem(index)) // reject if already present
return -1;
- return addResults(index, new QList<T>(*results), results->count(), results->count());
+ return addResults(index, new QList<T>(*results), results->size(), results->size());
}
template<typename T>
int addResults(int index, const QList<T> *results, int totalCount)
{
// reject if results are empty, and nothing is filtered away
- if ((m_filterMode == false || results->count() == totalCount) && results->empty())
+ if ((m_filterMode == false || results->size() == totalCount) && results->empty())
return -1;
if (containsValidResultItem(index)) // reject if already present
return -1;
- if (m_filterMode == true && results->count() != totalCount && 0 == results->count())
+ if (m_filterMode == true && results->size() != totalCount && 0 == results->size())
return addResults(index, nullptr, 0, totalCount);
- return addResults(index, new QList<T>(*results), results->count(), totalCount);
+ return addResults(index, new QList<T>(*results), results->size(), totalCount);
}
int addCanceledResult(int index)
diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp
index 664085eb2b..803aa30bef 100644
--- a/src/corelib/thread/qsemaphore.cpp
+++ b/src/corelib/thread/qsemaphore.cpp
@@ -161,7 +161,7 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValu
if constexpr (futexHasWaiterCount) {
Q_ASSERT(n > 1);
ptr = futexHigh32(&u);
- curValue >>= 32;
+ curValue = quint64(curValue) >> 32;
}
}
@@ -213,7 +213,8 @@ template <bool IsTimed> bool futexSemaphoreTryAcquire(QBasicAtomicInteger<quintp
if constexpr (futexHasWaiterCount) {
// We don't use the fetched value from above so futexWait() fails if
// it changed after the testAndSetOrdered above.
- if (((curValue >> 32) & 0x7fffffffU) == 0x7fffffffU) {
+ quint32 waiterCount = (quint64(curValue) >> 32) & 0x7fffffffU;
+ if (waiterCount == 0x7fffffffU) {
qCritical() << "Waiter count overflow in QSemaphore";
return false;
}
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index e294fe2fe0..e2f2707520 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -979,6 +979,16 @@ bool QThread::isRunning() const
return d->running;
}
+void QThread::requestInterruption()
+{
+
+}
+
+bool QThread::isInterruptionRequested() const
+{
+ return false;
+}
+
// No threads: so we can just use static variables
Q_CONSTINIT static QThreadData *data = nullptr;
diff --git a/src/corelib/thread/qthread.h b/src/corelib/thread/qthread.h
index 4cea76cf77..d856d8daa8 100644
--- a/src/corelib/thread/qthread.h
+++ b/src/corelib/thread/qthread.h
@@ -155,12 +155,12 @@ inline Qt::HANDLE QThread::currentThreadId() noexcept
Qt::HANDLE tid; // typedef to void*
static_assert(sizeof(tid) == sizeof(void*));
// See https://akkadia.org/drepper/tls.pdf for x86 ABI
-#if defined(Q_PROCESSOR_X86_32) && defined(Q_OS_LINUX) && defined(__GLIBC__) // x86 32-bit always uses GS
+#if defined(Q_PROCESSOR_X86_32) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD)) // x86 32-bit always uses GS
__asm__("movl %%gs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_DARWIN64)
// 64bit macOS uses GS, see https://github.com/apple/darwin-xnu/blob/master/libsyscall/os/tsd.h
__asm__("movq %%gs:0, %0" : "=r" (tid) : : );
-#elif defined(Q_PROCESSOR_X86_64) && (defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD)
+#elif defined(Q_PROCESSOR_X86_64) && ((defined(Q_OS_LINUX) && defined(__GLIBC__)) || defined(Q_OS_FREEBSD))
// x86_64 Linux, BSD uses FS
__asm__("movq %%fs:%c1, %0" : "=r" (tid) : "i" (2 * sizeof(void*)) : );
#elif defined(Q_PROCESSOR_X86_64) && defined(Q_OS_WIN)
diff --git a/src/corelib/thread/qthread_unix.cpp b/src/corelib/thread/qthread_unix.cpp
index d7e5135199..777aa362b2 100644
--- a/src/corelib/thread/qthread_unix.cpp
+++ b/src/corelib/thread/qthread_unix.cpp
@@ -137,8 +137,7 @@ static void set_thread_data(QThreadData *data)
static void clear_thread_data()
{
- currentThreadData = nullptr;
- pthread_setspecific(current_thread_data_key, nullptr);
+ set_thread_data(nullptr);
}
template <typename T>
diff --git a/src/corelib/thread/qthreadpool.cpp b/src/corelib/thread/qthreadpool.cpp
index b1078dab18..51783321b9 100644
--- a/src/corelib/thread/qthreadpool.cpp
+++ b/src/corelib/thread/qthreadpool.cpp
@@ -188,7 +188,7 @@ inline bool comparePriority(int priority, const QueuePage *p)
void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority)
{
Q_ASSERT(runnable != nullptr);
- for (QueuePage *page : qAsConst(queue)) {
+ for (QueuePage *page : std::as_const(queue)) {
if (page->priority() == priority && !page->isFull()) {
page->push(runnable);
return;
@@ -200,9 +200,9 @@ void QThreadPoolPrivate::enqueueTask(QRunnable *runnable, int priority)
int QThreadPoolPrivate::activeThreadCount() const
{
- return (allThreads.count()
- - expiredThreads.count()
- - waitingThreads.count()
+ return (allThreads.size()
+ - expiredThreads.size()
+ - waitingThreads.size()
+ reservedThreads);
}
@@ -269,7 +269,7 @@ void QThreadPoolPrivate::reset()
mutex.unlock();
- for (QThreadPoolThread *thread : qAsConst(allThreadsCopy)) {
+ for (QThreadPoolThread *thread : std::as_const(allThreadsCopy)) {
if (thread->isRunning()) {
thread->runnableReady.wakeAll();
thread->wait();
@@ -348,7 +348,7 @@ bool QThreadPool::tryTake(QRunnable *runnable)
return false;
QMutexLocker locker(&d->mutex);
- for (QueuePage *page : qAsConst(d->queue)) {
+ for (QueuePage *page : std::as_const(d->queue)) {
if (page->tryTake(runnable)) {
if (page->isFinished()) {
d->queue.removeOne(page);
@@ -475,6 +475,21 @@ QThreadPool *QThreadPool::globalInstance()
}
/*!
+ Returns the QThreadPool instance for Qt Gui.
+ \internal
+*/
+QThreadPool *QThreadPoolPrivate::qtGuiInstance()
+{
+ Q_CONSTINIT static QPointer<QThreadPool> guiInstance;
+ Q_CONSTINIT static QBasicMutex theMutex;
+
+ const QMutexLocker locker(&theMutex);
+ if (guiInstance.isNull() && !QCoreApplication::closingDown())
+ guiInstance = new QThreadPool();
+ return guiInstance;
+}
+
+/*!
Reserves a thread and uses it to run \a runnable, unless this thread will
make the current thread count exceed maxThreadCount(). In that case,
\a runnable is added to a run queue instead. The \a priority argument can
@@ -590,12 +605,14 @@ bool QThreadPool::tryStart(std::function<void()> functionToRun)
int QThreadPool::expiryTimeout() const
{
Q_D(const QThreadPool);
+ QMutexLocker locker(&d->mutex);
return d->expiryTimeout;
}
void QThreadPool::setExpiryTimeout(int expiryTimeout)
{
Q_D(QThreadPool);
+ QMutexLocker locker(&d->mutex);
if (d->expiryTimeout == expiryTimeout)
return;
d->expiryTimeout = expiryTimeout;
@@ -616,6 +633,7 @@ void QThreadPool::setExpiryTimeout(int expiryTimeout)
int QThreadPool::maxThreadCount() const
{
Q_D(const QThreadPool);
+ QMutexLocker locker(&d->mutex);
return d->requestedMaxThreadCount;
}
@@ -685,12 +703,14 @@ void QThreadPool::reserveThread()
void QThreadPool::setStackSize(uint stackSize)
{
Q_D(QThreadPool);
+ QMutexLocker locker(&d->mutex);
d->stackSize = stackSize;
}
uint QThreadPool::stackSize() const
{
Q_D(const QThreadPool);
+ QMutexLocker locker(&d->mutex);
return d->stackSize;
}
@@ -711,12 +731,14 @@ uint QThreadPool::stackSize() const
void QThreadPool::setThreadPriority(QThread::Priority priority)
{
Q_D(QThreadPool);
+ QMutexLocker locker(&d->mutex);
d->threadPriority = priority;
}
QThread::Priority QThreadPool::threadPriority() const
{
Q_D(const QThreadPool);
+ QMutexLocker locker(&d->mutex);
return d->threadPriority;
}
diff --git a/src/corelib/thread/qthreadpool_p.h b/src/corelib/thread/qthreadpool_p.h
index f967880bde..67c703fabd 100644
--- a/src/corelib/thread/qthreadpool_p.h
+++ b/src/corelib/thread/qthreadpool_p.h
@@ -134,6 +134,8 @@ public:
void stealAndRunRunnable(QRunnable *runnable);
void deletePageIfFinished(QueuePage *page);
+ static QThreadPool *qtGuiInstance();
+
mutable QMutex mutex;
QSet<QThreadPoolThread *> allThreads;
QQueue<QThreadPoolThread *> waitingThreads;
diff --git a/src/corelib/thread/qthreadstorage.cpp b/src/corelib/thread/qthreadstorage.cpp
index 55a603e0e6..c2029fe1b3 100644
--- a/src/corelib/thread/qthreadstorage.cpp
+++ b/src/corelib/thread/qthreadstorage.cpp
@@ -51,15 +51,15 @@ QThreadStorageData::QThreadStorageData(void (*func)(void *))
no where to store it, and no way to actually call it.
*/
QThreadData *data = QThreadData::current();
- id = data->tls.count();
+ id = data->tls.size();
DEBUG_MSG("QThreadStorageData: Allocated id %d, destructor %p cannot be stored", id, func);
return;
}
- for (id = 0; id < destr->count(); id++) {
+ for (id = 0; id < destr->size(); id++) {
if (destr->at(id) == nullptr)
break;
}
- if (id == destr->count()) {
+ if (id == destr->size()) {
destr->append(func);
} else {
(*destr)[id] = func;
diff --git a/src/corelib/thread/qwaitcondition.qdoc b/src/corelib/thread/qwaitcondition.qdoc
index bd3a675192..435771e1d8 100644
--- a/src/corelib/thread/qwaitcondition.qdoc
+++ b/src/corelib/thread/qwaitcondition.qdoc
@@ -98,10 +98,16 @@
/*!
\fn bool QWaitCondition::wait(QMutex *lockedMutex, unsigned long time)
\overload
+
+ Releases the \a lockedMutex and waits on the wait condition for \a time
+ milliseconds.
*/
/*!
\fn bool QWaitCondition::wait(QReadWriteLock *lockedReadWriteLock, unsigned long time)
\overload
+
+ Releases the \a lockedReadWriteLock and waits on the wait condition for \a
+ time milliseconds.
*/
/*!
diff --git a/src/corelib/thread/qwaitcondition_p.h b/src/corelib/thread/qwaitcondition_p.h
index e82f832817..0893e9dd35 100644
--- a/src/corelib/thread/qwaitcondition_p.h
+++ b/src/corelib/thread/qwaitcondition_p.h
@@ -7,10 +7,9 @@
// W A R N I N G
// -------------
//
-// This file is not part of the Qt API. It exists for the convenience
-// of qmutex.cpp, qmutex_unix.cpp, and qmutex_win.cpp. This header
-// file may change from version to version without notice, or even be
-// removed.
+// This file is not part of the Qt API. It exists for the convenience of
+// qmutex.cpp and qmutex_unix.cpp. This header file may change from version to
+// version without notice, or even be removed.
//
// We mean it.
//
diff --git a/src/corelib/thread/qwaitcondition_win.cpp b/src/corelib/thread/qwaitcondition_win.cpp
index 0deef043cd..2152ae551f 100644
--- a/src/corelib/thread/qwaitcondition_win.cpp
+++ b/src/corelib/thread/qwaitcondition_win.cpp
@@ -178,7 +178,7 @@ void QWaitCondition::wakeOne()
{
// wake up the first waiting thread in the queue
QMutexLocker locker(&d->mtx);
- for (QWaitConditionEvent *current : qAsConst(d->queue)) {
+ for (QWaitConditionEvent *current : std::as_const(d->queue)) {
if (current->wokenUp)
continue;
SetEvent(current->event);
@@ -191,7 +191,7 @@ void QWaitCondition::wakeAll()
{
// wake up the all threads in the queue
QMutexLocker locker(&d->mtx);
- for (QWaitConditionEvent *current : qAsConst(d->queue)) {
+ for (QWaitConditionEvent *current : std::as_const(d->queue)) {
SetEvent(current->event);
current->wokenUp = true;
}