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
71namespace ABI {
72 namespace Windows {
73 namespace Foundation {
74 struct IAsyncAction;
75 }
76 }
77}
78#endif // Q_OS_WINRT
79
80QT_BEGIN_NAMESPACE
81
82class QAbstractEventDispatcher;
83class QEventLoop;
84
85class QPostEvent
86{
87public:
88 QObject *receiver;
89 QEvent *event;
90 int priority;
91 inline QPostEvent()
92 : receiver(0), event(0), priority(0)
93 { }
94 inline QPostEvent(QObject *r, QEvent *e, int p)
95 : receiver(r), event(e), priority(p)
96 { }
97};
98Q_DECLARE_TYPEINFO(QPostEvent, Q_MOVABLE_TYPE);
99
100inline 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
107class QPostEventList : public QVector<QPostEvent>
108{
109public:
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
120 inline QPostEventList()
121 : QVector<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0)
122 { }
123
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 }
140private:
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
148class Q_CORE_EXPORT QDaemonThread : public QThread
149{
150public:
151 QDaemonThread(QObject *parent = 0);
152 ~QDaemonThread();
153};
154
155class QThreadPrivate : public QObjectPrivate
156{
157 Q_DECLARE_PUBLIC(QThread)
158
159public:
160 QThreadPrivate(QThreadData *d = 0);
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 *) Q_DECL_NOEXCEPT;
191 static void finish(void *, bool lockAnyway=true) Q_DECL_NOEXCEPT;
192
193 Qt::HANDLE handle;
194 unsigned int id;
195 int waiters;
196 bool terminationEnabled, terminatePending;
197#endif // Q_OS_WIN
198 QThreadData *data;
199
200 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
201
202 void ref()
203 {
204 quitLockRef.ref();
205 }
206
207 void deref()
208 {
209 if (!quitLockRef.deref() && running) {
210 QCoreApplication::instance()->postEvent(q_ptr, new QEvent(QEvent::Quit));
211 }
212 }
213};
214
215#else // QT_CONFIG(thread)
216
217class QThreadPrivate : public QObjectPrivate
218{
219public:
220 QThreadPrivate(QThreadData *d = 0);
221 ~QThreadPrivate();
222
223 mutable QMutex mutex;
224 QThreadData *data;
225 bool running = false;
226
227 static void setCurrentThread(QThread*) {}
228 static QThread *threadForId(int) { return QThread::currentThread(); }
229 static QAbstractEventDispatcher *createEventDispatcher(QThreadData *data);
230
231 void ref() {}
232 void deref() {}
233
234 Q_DECLARE_PUBLIC(QThread)
235};
236
237#endif // QT_CONFIG(thread)
238
239class QThreadData
240{
241public:
242 QThreadData(int initialRefCount = 1);
243 ~QThreadData();
244
245 static Q_AUTOTEST_EXPORT QThreadData *current(bool createIfNecessary = true);
246#ifdef Q_OS_WINRT
247 static void setMainThread();
248#endif
249 static void clearCurrentThreadData();
250 static QThreadData *get2(QThread *thread)
251 { Q_ASSERT_X(thread != 0, "QThread", "internal error"); return thread->d_func()->data; }
252
253
254 void ref();
255 void deref();
256 inline bool hasEventDispatcher() const
257 { return eventDispatcher.load() != nullptr; }
258 QAbstractEventDispatcher *createEventDispatcher();
259 QAbstractEventDispatcher *ensureEventDispatcher()
260 {
261 QAbstractEventDispatcher *ed = eventDispatcher.load();
262 if (Q_LIKELY(ed))
263 return ed;
264 return createEventDispatcher();
265 }
266
267 bool canWaitLocked()
268 {
269 QMutexLocker locker(&postEventList.mutex);
270 return canWait;
271 }
272
273 // This class provides per-thread (by way of being a QThreadData
274 // member) storage for qFlagLocation()
275 class FlaggedDebugSignatures
276 {
277 static const uint Count = 2;
278
279 uint idx;
280 const char* locations[Count];
281
282 public:
283 FlaggedDebugSignatures() : idx(0)
284 { std::fill_n(locations, Count, static_cast<char*>(0)); }
285
286 void store(const char* method)
287 { locations[idx++ % Count] = method; }
288
289 bool contains(const char *method) const
290 { return std::find(locations, locations + Count, method) != locations + Count; }
291 };
292
293private:
294 QAtomicInt _ref;
295
296public:
297 int loopLevel;
298 int scopeLevel;
299
300 QStack<QEventLoop *> eventLoops;
301 QPostEventList postEventList;
302 QAtomicPointer<QThread> thread;
303 QAtomicPointer<void> threadId;
304 QAtomicPointer<QAbstractEventDispatcher> eventDispatcher;
305 QVector<void *> tls;
306 FlaggedDebugSignatures flaggedSignatures;
307
308 bool quitNow;
309 bool canWait;
310 bool isAdopted;
311 bool requiresCoreApplication;
312};
313
314class QScopedScopeLevelCounter
315{
316 QThreadData *threadData;
317public:
318 inline QScopedScopeLevelCounter(QThreadData *threadData)
319 : threadData(threadData)
320 { ++threadData->scopeLevel; }
321 inline ~QScopedScopeLevelCounter()
322 { --threadData->scopeLevel; }
323};
324
325// thread wrapper for the main() thread
326class QAdoptedThread : public QThread
327{
328 Q_DECLARE_PRIVATE(QThread)
329
330public:
331 QAdoptedThread(QThreadData *data = 0);
332 ~QAdoptedThread();
333 void init();
334
335private:
336#if QT_CONFIG(thread)
337 void run() override;
338#endif
339};
340
341QT_END_NAMESPACE
342
343#endif // QTHREAD_P_H
344