1 /**************************************************************************** 2 ** 3 ** Copyright (C) 2016 The Qt Company Ltd. 4 ** Copyright (C) 2016 Intel Corporation. 5 ** Contact: https://www.qt.io/licensing/ 6 ** 7 ** This file is part of the QtCore module of the Qt Toolkit. 8 ** 9 ** $QT_BEGIN_LICENSE:LGPL$ 10 ** Commercial License Usage 11 ** Licensees holding valid commercial Qt licenses may use this file in 12 ** accordance with the commercial license agreement provided with the 13 ** Software or, alternatively, in accordance with the terms contained in 14 ** a written agreement between you and The Qt Company. For licensing terms 15 ** and conditions see https://www.qt.io/terms-conditions. For further 16 ** information use the contact form at https://www.qt.io/contact-us. 17 ** 18 ** GNU Lesser General Public License Usage 19 ** Alternatively, this file may be used under the terms of the GNU Lesser 20 ** General Public License version 3 as published by the Free Software 21 ** Foundation and appearing in the file LICENSE.LGPL3 included in the 22 ** packaging of this file. Please review the following information to 23 ** ensure the GNU Lesser General Public License version 3 requirements 24 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 25 ** 26 ** GNU General Public License Usage 27 ** Alternatively, this file may be used under the terms of the GNU 28 ** General Public License version 2.0 or (at your option) the GNU General 29 ** Public license version 3 or any later version approved by the KDE Free 30 ** Qt Foundation. The licenses are as published by the Free Software 31 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 32 ** included in the packaging of this file. Please review the following 33 ** information to ensure the GNU General Public License requirements will 34 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 35 ** https://www.gnu.org/licenses/gpl-3.0.html. 36 ** 37 ** $QT_END_LICENSE$ 38 ** 39 ****************************************************************************/ 40 41 #ifndef QTHREAD_P_H 42 #define QTHREAD_P_H 43 44 // 45 // W A R N I N G 46 // ------------- 47 // 48 // This file is not part of the Qt API. It exists purely as an 49 // implementation detail. This header file may change from version to 50 // version without notice, or even be removed. 51 // 52 // We mean it. 53 // 54 // 55 56 #include "qplatformdefs.h" 57 #include "QtCore/qthread.h" 58 #include "QtCore/qmutex.h" 59 #include "QtCore/qstack.h" 60 #if QT_CONFIG(thread) 61 #include "QtCore/qwaitcondition.h" 62 #endif 63 #include "QtCore/qmap.h" 64 #include "QtCore/qcoreapplication.h" 65 #include "private/qobject_p.h" 66 67 #include <algorithm> 68 #include <atomic> 69 70 #ifdef Q_OS_WINRT 71 namespace ABI { 72 namespace Windows { 73 namespace Foundation { 74 struct IAsyncAction; 75 } 76 } 77 } 78 #endif // Q_OS_WINRT 79 80 QT_BEGIN_NAMESPACE 81 82 class QAbstractEventDispatcher; 83 class QEventLoop; 84 85 class QPostEvent 86 { 87 public: 88 QObject *receiver; 89 QEvent *event; 90 int priority; QPostEvent()91 inline QPostEvent() 92 : receiver(nullptr), event(nullptr), priority(0) 93 { } QPostEvent(QObject * r,QEvent * e,int p)94 inline QPostEvent(QObject *r, QEvent *e, int p) 95 : receiver(r), event(e), priority(p) 96 { } 97 }; 98 Q_DECLARE_TYPEINFO(QPostEvent, Q_MOVABLE_TYPE); 99 100 inline bool operator<(const QPostEvent &first, const QPostEvent &second) 101 { 102 return first.priority > second.priority; 103 } 104 105 // This class holds the list of posted events. 106 // The list has to be kept sorted by priority 107 class QPostEventList : public QVector<QPostEvent> 108 { 109 public: 110 // recursion == recursion count for sendPostedEvents() 111 int recursion; 112 113 // sendOffset == the current event to start sending 114 int startOffset; 115 // insertionOffset == set by sendPostedEvents to tell postEvent() where to start insertions 116 int insertionOffset; 117 118 QMutex mutex; 119 QPostEventList()120 inline QPostEventList() 121 : QVector<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0) 122 { } 123 addEvent(const QPostEvent & ev)124 void addEvent(const QPostEvent &ev) { 125 int priority = ev.priority; 126 if (isEmpty() || 127 constLast().priority >= priority || 128 insertionOffset >= size()) { 129 // optimization: we can simply append if the last event in 130 // the queue has higher or equal priority 131 append(ev); 132 } else { 133 // insert event in descending priority order, using upper 134 // bound for a given priority (to ensure proper ordering 135 // of events with the same priority) 136 QPostEventList::iterator at = std::upper_bound(begin() + insertionOffset, end(), ev); 137 insert(at, ev); 138 } 139 } 140 private: 141 //hides because they do not keep that list sorted. addEvent must be used 142 using QVector<QPostEvent>::append; 143 using QVector<QPostEvent>::insert; 144 }; 145 146 #if QT_CONFIG(thread) 147 148 class Q_CORE_EXPORT QDaemonThread : public QThread 149 { 150 public: 151 QDaemonThread(QObject *parent = nullptr); 152 ~QDaemonThread(); 153 }; 154 155 class QThreadPrivate : public QObjectPrivate 156 { 157 Q_DECLARE_PUBLIC(QThread) 158 159 public: 160 QThreadPrivate(QThreadData *d = nullptr); 161 ~QThreadPrivate(); 162 163 void setPriority(QThread::Priority prio); 164 165 mutable QMutex mutex; 166 QAtomicInt quitLockRef; 167 168 bool running; 169 bool finished; 170 bool isInFinish; //when in QThreadPrivate::finish 171 std::atomic<bool> interruptionRequested; 172 173 bool exited; 174 int returnCode; 175 176 uint stackSize; 177 QThread::Priority priority; 178 179 static QThread *threadForId(int id); 180 181 #ifdef Q_OS_UNIX 182 QWaitCondition thread_done; 183 184 static void *start(void *arg); 185 static void finish(void *); 186 187 #endif // Q_OS_UNIX 188 189 #ifdef Q_OS_WIN 190 static unsigned int __stdcall start(void *) noexcept; 191 static void finish(void *, bool lockAnyway=true) noexcept; 192 193 Qt::HANDLE handle; 194 unsigned int id; 195 int waiters; 196 bool terminationEnabled, terminatePending; 197 #endif // Q_OS_WIN 198 #ifdef Q_OS_WASM 199 static int idealThreadCount; 200 #endif 201 QThreadData *data; 202 203 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data); 204 ref()205 void ref() 206 { 207 quitLockRef.ref(); 208 } 209 deref()210 void deref() 211 { 212 if (!quitLockRef.deref() && running) { 213 QCoreApplication::instance()->postEvent(q_ptr, new QEvent(QEvent::Quit)); 214 } 215 } 216 }; 217 218 #else // QT_CONFIG(thread) 219 220 class QThreadPrivate : public QObjectPrivate 221 { 222 public: 223 QThreadPrivate(QThreadData *d = 0); 224 ~QThreadPrivate(); 225 226 mutable QMutex mutex; 227 QThreadData *data; 228 bool running = false; 229 setCurrentThread(QThread *)230 static void setCurrentThread(QThread*) {} threadForId(int)231 static QThread *threadForId(int) { return QThread::currentThread(); } 232 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data); 233 ref()234 void ref() {} deref()235 void deref() {} 236 237 Q_DECLARE_PUBLIC(QThread) 238 }; 239 240 #endif // QT_CONFIG(thread) 241 242 class QThreadData 243 { 244 public: 245 QThreadData(int initialRefCount = 1); 246 ~QThreadData(); 247 248 static Q_AUTOTEST_EXPORT QThreadData *current(bool createIfNecessary = true); 249 #ifdef Q_OS_WINRT 250 static void setMainThread(); 251 #endif 252 static void clearCurrentThreadData(); get2(QThread * thread)253 static QThreadData *get2(QThread *thread) 254 { Q_ASSERT_X(thread != nullptr, "QThread", "internal error"); return thread->d_func()->data; } 255 256 257 void ref(); 258 void deref(); hasEventDispatcher()259 inline bool hasEventDispatcher() const 260 { return eventDispatcher.loadRelaxed() != nullptr; } 261 QAbstractEventDispatcher *createEventDispatcher(); ensureEventDispatcher()262 QAbstractEventDispatcher *ensureEventDispatcher() 263 { 264 QAbstractEventDispatcher *ed = eventDispatcher.loadRelaxed(); 265 if (Q_LIKELY(ed)) 266 return ed; 267 return createEventDispatcher(); 268 } 269 canWaitLocked()270 bool canWaitLocked() 271 { 272 QMutexLocker locker(&postEventList.mutex); 273 return canWait; 274 } 275 276 // This class provides per-thread (by way of being a QThreadData 277 // member) storage for qFlagLocation() 278 class FlaggedDebugSignatures 279 { 280 static const uint Count = 2; 281 282 uint idx; 283 const char* locations[Count]; 284 285 public: FlaggedDebugSignatures()286 FlaggedDebugSignatures() : idx(0) 287 { std::fill_n(locations, Count, static_cast<char*>(nullptr)); } 288 store(const char * method)289 void store(const char* method) 290 { locations[idx++ % Count] = method; } 291 contains(const char * method)292 bool contains(const char *method) const 293 { return std::find(locations, locations + Count, method) != locations + Count; } 294 }; 295 296 private: 297 QAtomicInt _ref; 298 299 public: 300 int loopLevel; 301 int scopeLevel; 302 303 QStack<QEventLoop *> eventLoops; 304 QPostEventList postEventList; 305 QAtomicPointer<QThread> thread; 306 QAtomicPointer<void> threadId; 307 QAtomicPointer<QAbstractEventDispatcher> eventDispatcher; 308 QVector<void *> tls; 309 FlaggedDebugSignatures flaggedSignatures; 310 311 bool quitNow; 312 bool canWait; 313 bool isAdopted; 314 bool requiresCoreApplication; 315 }; 316 317 class QScopedScopeLevelCounter 318 { 319 QThreadData *threadData; 320 public: QScopedScopeLevelCounter(QThreadData * threadData)321 inline QScopedScopeLevelCounter(QThreadData *threadData) 322 : threadData(threadData) 323 { ++threadData->scopeLevel; } ~QScopedScopeLevelCounter()324 inline ~QScopedScopeLevelCounter() 325 { --threadData->scopeLevel; } 326 }; 327 328 // thread wrapper for the main() thread 329 class QAdoptedThread : public QThread 330 { 331 Q_DECLARE_PRIVATE(QThread) 332 333 public: 334 QAdoptedThread(QThreadData *data = nullptr); 335 ~QAdoptedThread(); 336 void init(); 337 338 private: 339 #if QT_CONFIG(thread) 340 void run() override; 341 #endif 342 }; 343 344 QT_END_NAMESPACE 345 346 #endif // QTHREAD_P_H 347