summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread/qthread_p.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib/thread/qthread_p.h')
-rw-r--r--src/corelib/thread/qthread_p.h143
1 files changed, 95 insertions, 48 deletions
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
index 4520be76eb..c39e21ec9a 100644
--- a/src/corelib/thread/qthread_p.h
+++ b/src/corelib/thread/qthread_p.h
@@ -58,6 +58,7 @@ inline bool operator<(const QPostEvent &first, const QPostEvent &second)
// This class holds the list of posted events.
// The list has to be kept sorted by priority
+// It's used in a virtual in QCoreApplication, so ELFVERSION:ignore-next
class QPostEventList : public QList<QPostEvent>
{
public:
@@ -73,23 +74,7 @@ public:
inline QPostEventList() : QList<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0) { }
- void addEvent(const QPostEvent &ev)
- {
- int priority = ev.priority;
- if (isEmpty() ||
- constLast().priority >= priority ||
- insertionOffset >= size()) {
- // optimization: we can simply append if the last event in
- // the queue has higher or equal priority
- append(ev);
- } else {
- // insert event in descending priority order, using upper
- // bound for a given priority (to ensure proper ordering
- // of events with the same priority)
- QPostEventList::iterator at = std::upper_bound(begin() + insertionOffset, end(), ev);
- insert(at, ev);
- }
- }
+ void addEvent(const QPostEvent &ev);
private:
//hides because they do not keep that list sorted. addEvent must be used
@@ -97,6 +82,85 @@ private:
using QList<QPostEvent>::insert;
};
+namespace QtPrivate {
+
+/* BindingStatusOrList is basically a QBiPointer (as found in declarative)
+ with some helper methods to manipulate the list. BindingStatusOrList starts
+ its life in a null state and supports the following transitions
+
+ 0 state (initial)
+ / \
+ / \
+ v v
+ pending object list----------->binding status
+ Note that binding status is the final state, and we never transition away
+ from it
+*/
+class BindingStatusOrList
+{
+ Q_DISABLE_COPY_MOVE(BindingStatusOrList)
+public:
+ using List = std::vector<QObject *>;
+
+ constexpr BindingStatusOrList() noexcept : data(0) {}
+ explicit BindingStatusOrList(QBindingStatus *status) noexcept :
+ data(encodeBindingStatus(status)) {}
+ explicit BindingStatusOrList(List *list) noexcept : data(encodeList(list)) {}
+
+ // requires external synchronization:
+ QBindingStatus *addObjectUnlessAlreadyStatus(QObject *object);
+ void removeObject(QObject *object);
+ void setStatusAndClearList(QBindingStatus *status) noexcept;
+
+
+ static bool isBindingStatus(quintptr data) noexcept
+ {
+ return !isNull(data) && !isList(data);
+ }
+ static bool isList(quintptr data) noexcept { return data & 1; }
+ static bool isNull(quintptr data) noexcept { return data == 0; }
+
+ // thread-safe:
+ QBindingStatus *bindingStatus() const noexcept
+ {
+ // synchronizes-with the store-release in setStatusAndClearList():
+ const auto d = data.load(std::memory_order_acquire);
+ if (isBindingStatus(d))
+ return reinterpret_cast<QBindingStatus *>(d);
+ else
+ return nullptr;
+ }
+
+ // requires external synchronization:
+ List *list() const noexcept
+ {
+ return decodeList(data.load(std::memory_order_relaxed));
+ }
+
+private:
+ static List *decodeList(quintptr ptr) noexcept
+ {
+ if (isList(ptr))
+ return reinterpret_cast<List *>(ptr & ~1);
+ else
+ return nullptr;
+ }
+
+ static quintptr encodeBindingStatus(QBindingStatus *status) noexcept
+ {
+ return quintptr(status);
+ }
+
+ static quintptr encodeList(List *list) noexcept
+ {
+ return quintptr(list) | 1;
+ }
+
+ std::atomic<quintptr> data;
+};
+
+} // namespace QtPrivate
+
#if QT_CONFIG(thread)
class Q_CORE_EXPORT QDaemonThread : public QThread
@@ -106,7 +170,7 @@ public:
~QDaemonThread();
};
-class QThreadPrivate : public QObjectPrivate
+class Q_AUTOTEST_EXPORT QThreadPrivate : public QObjectPrivate
{
Q_DECLARE_PUBLIC(QThread)
@@ -115,6 +179,7 @@ public:
~QThreadPrivate();
void setPriority(QThread::Priority prio);
+ Qt::HANDLE threadId() const;
mutable QMutex mutex;
QAtomicInt quitLockRef;
@@ -168,32 +233,17 @@ public:
QBindingStatus *bindingStatus()
{
- auto statusOrPendingObjects = m_statusOrPendingObjects.loadAcquire();
- if (!(statusOrPendingObjects & 1))
- return (QBindingStatus *) statusOrPendingObjects;
- return nullptr;
+ return m_statusOrPendingObjects.bindingStatus();
}
- void addObjectWithPendingBindingStatusChange(QObject *obj)
- {
- Q_ASSERT(!bindingStatus());
- auto pendingObjects = pendingObjectsWithBindingStatusChange();
- if (!pendingObjects) {
- pendingObjects = new std::vector<QObject *>();
- m_statusOrPendingObjects = quintptr(pendingObjects) | 1;
- }
- pendingObjects->push_back(obj);
- }
-
- std::vector<QObject *> *pendingObjectsWithBindingStatusChange()
- {
- auto statusOrPendingObjects = m_statusOrPendingObjects.loadAcquire();
- if (statusOrPendingObjects & 1)
- return reinterpret_cast<std::vector<QObject *> *>(statusOrPendingObjects - 1);
- return nullptr;
- }
+ /* Returns nullptr if the object has been added, or the binding status
+ if that one has been set in the meantime
+ */
+ QBindingStatus *addObjectWithPendingBindingStatusChange(QObject *obj);
+ void removeObjectWithPendingBindingStatusChange(QObject *obj);
- QAtomicInteger<quintptr> m_statusOrPendingObjects = 0;
+ // manipulating m_statusOrPendingObjects requires mutex to be locked
+ QtPrivate::BindingStatusOrList m_statusOrPendingObjects = {};
#ifndef Q_OS_INTEGRITY
private:
// Used in QThread(Private)::start to avoid racy access to QObject::objectName,
@@ -216,8 +266,8 @@ public:
bool running = false;
QBindingStatus* bindingStatus() { return m_bindingStatus; }
- void addObjectWithPendingBindingStatusChange(QObject *) {}
- std::vector<QObject *> * pendingObjectsWithBindingStatusChange() { return nullptr; }
+ QBindingStatus *addObjectWithPendingBindingStatusChange(QObject *) { return nullptr; }
+ void removeObjectWithPendingBindingStatusChange(QObject *) {}
static void setCurrentThread(QThread *) { }
static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
@@ -285,11 +335,8 @@ class QScopedScopeLevelCounter
{
QThreadData *threadData;
public:
- inline QScopedScopeLevelCounter(QThreadData *threadData)
- : threadData(threadData)
- { ++threadData->scopeLevel; }
- inline ~QScopedScopeLevelCounter()
- { --threadData->scopeLevel; }
+ QScopedScopeLevelCounter(QThreadData *threadData);
+ ~QScopedScopeLevelCounter();
};
// thread wrapper for the main() thread