diff options
Diffstat (limited to 'src/corelib/thread/qthread_p.h')
-rw-r--r-- | src/corelib/thread/qthread_p.h | 143 |
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 |