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