Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qthread.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qthread.h"
6#include "qthreadstorage.h"
7#include "qmutex.h"
8#include "qreadwritelock.h"
10#include "qbindingstorage.h"
11
12#include <qeventloop.h>
13
14#include "qthread_p.h"
15#include "private/qcoreapplication_p.h"
16
17#include <limits>
18
20
21/*
22 QPostEventList
23*/
24
26{
27 int priority = ev.priority;
28 if (isEmpty() ||
29 constLast().priority >= priority ||
30 insertionOffset >= size()) {
31 // optimization: we can simply append if the last event in
32 // the queue has higher or equal priority
33 append(ev);
34 } else {
35 // insert event in descending priority order, using upper
36 // bound for a given priority (to ensure proper ordering
37 // of events with the same priority)
38 QPostEventList::iterator at = std::upper_bound(begin() + insertionOffset, end(), ev);
39 insert(at, ev);
40 }
41}
42
43
44/*
45 QThreadData
46*/
47
48QThreadData::QThreadData(int initialRefCount)
49 : _ref(initialRefCount), loopLevel(0), scopeLevel(0),
50 eventDispatcher(nullptr),
51 quitNow(false), canWait(true), isAdopted(false), requiresCoreApplication(true)
52{
53 // fprintf(stderr, "QThreadData %p created\n", this);
54}
55
57{
58#if QT_CONFIG(thread)
59 Q_ASSERT(_ref.loadRelaxed() == 0);
60#endif
61
62 // In the odd case that Qt is running on a secondary thread, the main
63 // thread instance will have been dereffed asunder because of the deref in
64 // QThreadData::current() and the deref in the pthread_destroy. To avoid
65 // crashing during QCoreApplicationData's global static cleanup we need to
66 // safeguard the main thread here.. This fix is a bit crude, but it solves
67 // the problem...
71 }
72
73 // ~QThread() sets thread to nullptr, so if it isn't null here, it's
74 // because we're being run before the main object itself. This can only
75 // happen for QAdoptedThread. Note that both ~QThreadPrivate() and
76 // ~QObjectPrivate() will deref this object again, but that is acceptable
77 // because this destructor is still running (the _ref sub-object has not
78 // been destroyed) and there's no reentrancy. The refcount will become
79 // negative, but that's acceptable.
81 thread.storeRelease(nullptr);
82 delete t;
83
84 for (int i = 0; i < postEventList.size(); ++i) {
85 const QPostEvent &pe = postEventList.at(i);
86 if (pe.event) {
87 --pe.receiver->d_func()->postedEvents;
88 pe.event->m_posted = false;
89 delete pe.event;
90 }
91 }
92
93 // fprintf(stderr, "QThreadData %p destroyed\n", this);
94}
95
97{
98#if QT_CONFIG(thread)
99 (void) _ref.ref();
100 Q_ASSERT(_ref.loadRelaxed() != 0);
101#endif
102}
103
105{
106#if QT_CONFIG(thread)
107 if (!_ref.deref())
108 delete this;
109#endif
110}
111
113{
116 return ed;
117}
118
119/*
120 QAdoptedThread
121*/
122
125{
126 // thread should be running and not finished for the lifetime
127 // of the application (even if QCoreApplication goes away)
128#if QT_CONFIG(thread)
129 d_func()->running = true;
130 d_func()->finished = false;
131 init();
132 d_func()->m_statusOrPendingObjects.setStatusAndClearList(
134#endif
135 // fprintf(stderr, "new QAdoptedThread = %p\n", this);
136}
137
139{
140 // fprintf(stderr, "~QAdoptedThread = %p\n", this);
141}
142
143#if QT_CONFIG(thread)
145{
146 // this function should never be called
147 qFatal("QAdoptedThread::run(): Internal error, this implementation should never be called.");
148}
149
150/*
151 QThreadPrivate
152*/
153
155 : QObjectPrivate(), running(false), finished(false),
156 isInFinish(false), interruptionRequested(false),
157 exited(false), returnCode(-1),
158 stackSize(0), priority(QThread::InheritPriority), data(d)
159{
160
161// INTEGRITY doesn't support self-extending stack. The default stack size for
162// a pthread on INTEGRITY is too small so we have to increase the default size
163// to 128K.
164#ifdef Q_OS_INTEGRITY
165 stackSize = 128 * 1024;
166#elif defined(Q_OS_RTEMS)
167 Q_CONSTINIT static bool envStackSizeOk = false;
168 static const int envStackSize = qEnvironmentVariableIntValue("QT_DEFAULT_THREAD_STACK_SIZE", &envStackSizeOk);
169 if (envStackSizeOk)
170 stackSize = envStackSize;
171#endif
172
173#if defined (Q_OS_WIN)
174 handle = 0;
175 id = 0;
176 waiters = 0;
177 terminationEnabled = true;
178 terminatePending = false;
179#endif
180
181 if (!data)
182 data = new QThreadData;
183}
184
186{
187 // access to m_statusOrPendingObjects cannot race with anything
188 // unless there is already a potential use-after-free bug, as the
189 // thread is in the process of being destroyed
190 delete m_statusOrPendingObjects.list();
191 data->deref();
192}
193
405{
407 Q_ASSERT(data != nullptr);
408 return data->thread.loadAcquire();
409}
410
419 : QObject(*(new QThreadPrivate), parent)
420{
421 Q_D(QThread);
422 // fprintf(stderr, "QThreadData %p created for thread %p\n", d->data, this);
423 d->data->thread.storeRelaxed(this);
424}
425
430 : QObject(dd, parent)
431{
432 Q_D(QThread);
433 // fprintf(stderr, "QThreadData %p taken from private data for thread %p\n", d->data, this);
434 d->data->thread.storeRelaxed(this);
435}
436
456{
457 Q_D(QThread);
458 {
459 QMutexLocker locker(&d->mutex);
460 if (d->isInFinish) {
461 locker.unlock();
462 wait();
463 locker.relock();
464 }
465 if (d->running && !d->finished && !d->data->isAdopted)
466 qFatal("QThread: Destroyed while thread is still running");
467
468 d->data->thread.storeRelease(nullptr);
469 }
470}
471
478bool QThread::isFinished() const
479{
480 Q_D(const QThread);
481 QMutexLocker locker(&d->mutex);
482 return d->finished || d->isInFinish;
483}
484
491bool QThread::isRunning() const
492{
493 Q_D(const QThread);
494 QMutexLocker locker(&d->mutex);
495 return d->running && !d->isInFinish;
496}
497
510void QThread::setStackSize(uint stackSize)
511{
512 Q_D(QThread);
513 QMutexLocker locker(&d->mutex);
514 Q_ASSERT_X(!d->running, "QThread::setStackSize",
515 "cannot change stack size while the thread is running");
516 d->stackSize = stackSize;
517}
518
526{
527 Q_D(const QThread);
528 QMutexLocker locker(&d->mutex);
529 return d->stackSize;
530}
531
539{
540
541 if (auto pendingObjects = list()) {
542 for (auto obj: *pendingObjects)
543 QObjectPrivate::get(obj)->reinitBindingStorageAfterThreadMove();
544 delete pendingObjects;
545 }
546 // synchronizes-with the load-acquire in bindingStatus():
547 data.store(encodeBindingStatus(status), std::memory_order_release);
548}
549
563int QThread::exec()
564{
565 Q_D(QThread);
567
568 QMutexLocker locker(&d->mutex);
569 d->m_statusOrPendingObjects.setStatusAndClearList(status);
570 d->data->quitNow = false;
571 if (d->exited) {
572 d->exited = false;
573 return d->returnCode;
574 }
575 locker.unlock();
576
577 QEventLoop eventLoop;
578 int returnCode = eventLoop.exec();
579
580 locker.relock();
581 d->exited = false;
582 d->returnCode = -1;
583 return returnCode;
584}
585
586
595{
596 if (auto status = bindingStatus())
597 return status;
598 List *objectList = list();
599 if (!objectList) {
600 objectList = new List();
601 objectList->reserve(8);
602 data.store(encodeList(objectList), std::memory_order_relaxed);
603 }
604 objectList->push_back(object);
605 return nullptr;
606}
607
613{
614 List *objectList = list();
615 if (!objectList)
616 return;
617 auto it = std::remove(objectList->begin(), objectList->end(), object);
618 objectList->erase(it, objectList->end());
619}
620
622{
623 if (auto status = m_statusOrPendingObjects.bindingStatus())
624 return status;
626 return m_statusOrPendingObjects.addObjectUnlessAlreadyStatus(obj);
627}
628
630{
631 if (m_statusOrPendingObjects.bindingStatus())
632 return;
634 m_statusOrPendingObjects.removeObject(obj);
635}
636
637
660void QThread::exit(int returnCode)
661{
662 Q_D(QThread);
663 QMutexLocker locker(&d->mutex);
664 d->exited = true;
665 d->returnCode = returnCode;
666 d->data->quitNow = true;
667 for (int i = 0; i < d->data->eventLoops.size(); ++i) {
668 QEventLoop *eventLoop = d->data->eventLoops.at(i);
669 eventLoop->exit(returnCode);
670 }
671}
672
683void QThread::quit()
684{ exit(); }
685
697void QThread::run()
698{
699 (void) exec();
700}
701
721void QThread::setPriority(Priority priority)
722{
723 if (priority == QThread::InheritPriority) {
724 qWarning("QThread::setPriority: Argument cannot be InheritPriority");
725 return;
726 }
727 Q_D(QThread);
728 QMutexLocker locker(&d->mutex);
729 if (!d->running) {
730 qWarning("QThread::setPriority: Cannot set priority, thread is not running");
731 return;
732 }
733 d->setPriority(priority);
734}
735
745{
746 Q_D(const QThread);
747 QMutexLocker locker(&d->mutex);
748
749 // mask off the high bits that are used for flags
750 return Priority(d->priority & 0xffff);
751}
752
893int QThread::loopLevel() const
894{
895 Q_D(const QThread);
896 return d->data->eventLoops.size();
897}
898
899#else // QT_CONFIG(thread)
900
902 : QObject(*(new QThreadPrivate), parent)
903{
904 Q_D(QThread);
905 d->data->thread.storeRelaxed(this);
906}
907
909{
910
911}
912
914{
915
916}
917
919{
920 return 0;
921}
922
924{
925 Q_D(QThread);
927 d->running = true;
928}
929
931{
932
933}
934
936{
937
938}
939
940void QThread::exit(int returnCode)
941{
942 Q_D(QThread);
943 d->data->quitNow = true;
944 for (int i = 0; i < d->data->eventLoops.size(); ++i) {
945 QEventLoop *eventLoop = d->data->eventLoops.at(i);
946 eventLoop->exit(returnCode);
947 }
948}
949
951{
953 return false;
954}
955
957{
958 return QObject::event(event);
959}
960
961Qt::HANDLE QThread::currentThreadIdImpl() noexcept
962{
963 return Qt::HANDLE(currentThread());
964}
965
967{
969}
970
972{
973 return 1;
974}
975
977{
978
979}
980
982{
983 return false;
984}
985
987{
988 Q_D(const QThread);
989 return d->running;
990}
991
993{
994
995}
996
998{
999 return false;
1000}
1001
1002// No threads: so we can just use static variables
1003Q_CONSTINIT static QThreadData *data = nullptr;
1004
1005QThreadData *QThreadData::current(bool createIfNecessary)
1006{
1007 if (!data && createIfNecessary) {
1008 data = new QThreadData;
1010 data->threadId.storeRelaxed(Qt::HANDLE(data->thread.loadAcquire()));
1011 data->deref();
1012 data->isAdopted = true;
1013 if (!QCoreApplicationPrivate::theMainThread.loadAcquire())
1015 }
1016 return data;
1017}
1018
1020{
1021 delete data;
1022 data = 0;
1023}
1024
1029 : QObject(dd, parent)
1030{
1031 Q_D(QThread);
1032 // fprintf(stderr, "QThreadData %p taken from private data for thread %p\n", d->data, this);
1033 d->data->thread.storeRelaxed(this);
1034}
1035
1037{
1038}
1039
1041{
1042 data->thread.storeRelease(nullptr); // prevent QThreadData from deleting the QThreadPrivate (again).
1043 delete data;
1044}
1045
1047{
1049}
1050
1052{
1053 return 0;
1054}
1055
1056#endif // QT_CONFIG(thread)
1057
1065{
1066 Q_D(const QThread);
1067 return d->data->eventDispatcher.loadRelaxed();
1068}
1069
1083{
1084 Q_D(QThread);
1085 if (d->data->hasEventDispatcher()) {
1086 qWarning("QThread::setEventDispatcher: An event dispatcher has already been created for this thread");
1087 } else {
1089 if (eventDispatcher->thread() == this) // was the move successful?
1090 d->data->eventDispatcher = eventDispatcher;
1091 else
1092 qWarning("QThread::setEventDispatcher: Could not move event dispatcher to target thread");
1093 }
1094}
1095
1104#if QT_CONFIG(thread)
1105
1110{
1111 if (event->type() == QEvent::Quit) {
1112 quit();
1113 return true;
1114 } else {
1115 return QObject::event(event);
1116 }
1117}
1118
1133{
1134 if (this == QCoreApplicationPrivate::theMainThread.loadAcquire()) {
1135 qWarning("QThread::requestInterruption has no effect on the main thread");
1136 return;
1137 }
1138 Q_D(QThread);
1139 QMutexLocker locker(&d->mutex);
1140 if (!d->running || d->finished || d->isInFinish)
1141 return;
1142 d->interruptionRequested.store(true, std::memory_order_relaxed);
1143}
1144
1172{
1173 Q_D(const QThread);
1174 // fast path: check that the flag is not set:
1175 if (!d->interruptionRequested.load(std::memory_order_relaxed))
1176 return false;
1177 // slow path: if the flag is set, take into account run status:
1178 QMutexLocker locker(&d->mutex);
1179 return d->running && !d->finished && !d->isInFinish;
1180}
1181
1204#if QT_CONFIG(cxx11_future)
1205class QThreadCreateThread : public QThread
1206{
1207public:
1208 explicit QThreadCreateThread(std::future<void> &&future)
1209 : m_future(std::move(future))
1210 {
1211 }
1212
1213 ~QThreadCreateThread()
1214 {
1216 quit();
1217 wait();
1218 }
1219
1220private:
1221 void run() override
1222 {
1223 m_future.get();
1224 }
1225
1226 std::future<void> m_future;
1227};
1228
1229QThread *QThread::createThreadImpl(std::future<void> &&future)
1230{
1231 return new QThreadCreateThread(std::move(future));
1232}
1233#endif // QT_CONFIG(cxx11_future)
1234
1243QDaemonThread::QDaemonThread(QObject *parent)
1244 : QThread(parent)
1245{
1246 // QThread::started() is emitted from the thread we start
1248 this,
1251}
1252
1253QDaemonThread::~QDaemonThread()
1254{
1255}
1256
1257#endif // QT_CONFIG(thread)
1258
1260
1261#include "moc_qthread.cpp"
QAdoptedThread(QThreadData *data=nullptr)
Definition qthread.cpp:123
bool ref() noexcept
bool deref() noexcept
T loadRelaxed() const noexcept
Type loadAcquire() const noexcept
void storeRelease(Type newValue) noexcept
static QBasicAtomicPointer< QThread > theMainThread
\inmodule QtCore
\inmodule QtCore
Definition qeventloop.h:16
int exec(ProcessEventsFlags flags=AllEvents)
Enters the main event loop and waits until exit() is called.
void exit(int returnCode=0)
Tells the event loop to exit with a return code.
\inmodule QtCore
Definition qcoreevent.h:45
qsizetype size() const noexcept
Definition qlist.h:386
bool isEmpty() const noexcept
Definition qlist.h:390
const QPostEvent & constLast() const noexcept
Definition qlist.h:633
iterator insert(qsizetype i, parameter_type t)
Definition qlist.h:471
iterator end()
Definition qlist.h:609
const_reference at(qsizetype i) const noexcept
Definition qlist.h:429
iterator begin()
Definition qlist.h:608
void append(parameter_type t)
Definition qlist.h:441
\inmodule QtCore
Definition qmutex.h:317
\inmodule QtCore
Definition qobject.h:90
void moveToThread(QThread *thread)
Changes the thread affinity for this object and its children.
Definition qobject.cpp:1606
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2823
virtual bool event(QEvent *event)
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qobject.cpp:1363
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1561
void addEvent(const QPostEvent &ev)
Definition qthread.cpp:25
qsizetype insertionOffset
Definition qthread_p.h:71
QObject * receiver
Definition qthread_p.h:42
QEvent * event
Definition qthread_p.h:43
int priority
Definition qthread_p.h:44
iterator end()
Definition qset.h:140
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
Definition qthread.cpp:1005
QAtomicPointer< QAbstractEventDispatcher > eventDispatcher
Definition qthread_p.h:324
QThreadData(int initialRefCount=1)
Definition qthread.cpp:48
bool requiresCoreApplication
Definition qthread_p.h:330
void deref()
Definition qthread.cpp:104
static void clearCurrentThreadData()
Definition qthread.cpp:1019
QPostEventList postEventList
Definition qthread_p.h:321
void ref()
Definition qthread.cpp:96
QAtomicPointer< QThread > thread
Definition qthread_p.h:322
QAbstractEventDispatcher * createEventDispatcher()
Definition qthread.cpp:112
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
QThreadPrivate(QThreadData *d=nullptr)
Definition qthread.cpp:1036
void removeObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:269
QThreadData * data
Definition qthread_p.h:263
QBindingStatus * addObjectWithPendingBindingStatusChange(QObject *)
Definition qthread_p.h:268
void terminate()
Definition qthread.cpp:930
bool isInterruptionRequested() const
Definition qthread.cpp:997
void start(Priority=InheritPriority)
Definition qthread.cpp:923
QAbstractEventDispatcher * eventDispatcher() const
Definition qthread.cpp:1064
bool isRunning() const
Definition qthread.cpp:986
static int idealThreadCount() noexcept
Definition qthread.cpp:971
bool event(QEvent *event) override
This virtual function receives events to an object and should return true if the event e was recogniz...
Definition qthread.cpp:956
virtual void run()
Definition qthread.cpp:913
bool isFinished() const
Definition qthread.cpp:981
static QThread * currentThread()
Definition qthread.cpp:966
@ InheritPriority
Definition qthread.h:52
static void yieldCurrentThread()
Definition qthread.cpp:976
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
Definition qthread.cpp:950
QThread(QObject *parent=nullptr)
Definition qthread.cpp:901
uint stackSize() const
Definition qthread.cpp:1051
Priority priority() const
void finished(QPrivateSignal)
int exec()
Definition qthread.cpp:918
void setPriority(Priority priority)
void requestInterruption()
Definition qthread.cpp:992
void setStackSize(uint stackSize)
Definition qthread.cpp:1046
void quit()
Definition qthread.cpp:935
int loopLevel() const
void setEventDispatcher(QAbstractEventDispatcher *eventDispatcher)
Definition qthread.cpp:1082
friend class QThreadData
Definition qthread.h:121
void started(QPrivateSignal)
void exit(int retcode=0)
Definition qthread.cpp:940
List * list() const noexcept
Definition qthread_p.h:135
void removeObject(QObject *object)
void setStatusAndClearList(QBindingStatus *status) noexcept
QBindingStatus * addObjectUnlessAlreadyStatus(QObject *object)
QBindingStatus * bindingStatus() const noexcept
Definition qthread_p.h:124
std::vector< QObject * > List
Definition qthread_p.h:103
QSet< QString >::iterator it
Combined button and popup list for selecting options.
Q_AUTOTEST_EXPORT QBindingStatus * getBindingStatus(QBindingStatusAccessToken)
void * HANDLE
@ DirectConnection
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage void
static QDBusError::ErrorType get(const char *name)
static Q_CONSTINIT QBasicAtomicInt running
#define qWarning
Definition qlogging.h:162
#define qFatal
Definition qlogging.h:164
GLuint64 GLenum void * handle
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
struct _cl_event * event
GLhandleARB obj
[2]
GLdouble GLdouble t
Definition qopenglext.h:243
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
#define Q_UNUSED(x)
unsigned int uint
Definition qtypes.h:29
QList< int > list
[14]
QFuture< void > future
[5]
QDeadlineTimer deadline(30s)
QObject::connect nullptr
QMutex mutex
[2]
QReadWriteLock lock
[0]
dialog exec()
QAction * at
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent