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#include "QtCore/qwaitcondition.h"
61#include "QtCore/qmap.h"
62#include "QtCore/qcoreapplication.h"
63#include "private/qobject_p.h"
64
65#include <algorithm>
66
67#ifdef Q_OS_WINRT
68namespace ABI {
69 namespace Windows {
70 namespace Foundation {
71 struct IAsyncAction;
72 }
73 }
74}
75#endif // Q_OS_WINRT
76
77QT_BEGIN_NAMESPACE
78
79class QAbstractEventDispatcher;
80class QEventLoop;
81
82class QPostEvent
83{
84public:
85 QObject *receiver;
86 QEvent *event;
87 int priority;
88 inline QPostEvent()
89 : receiver(0), event(0), priority(0)
90 { }
91 inline QPostEvent(QObject *r, QEvent *e, int p)
92 : receiver(r), event(e), priority(p)
93 { }
94};
95Q_DECLARE_TYPEINFO(QPostEvent, Q_MOVABLE_TYPE);
96
97inline bool operator<(const QPostEvent &first, const QPostEvent &second)
98{
99 return first.priority > second.priority;
100}
101
102// This class holds the list of posted events.
103// The list has to be kept sorted by priority
104class QPostEventList : public QVector<QPostEvent>
105{
106public:
107 // recursion == recursion count for sendPostedEvents()
108 int recursion;
109
110 // sendOffset == the current event to start sending
111 int startOffset;
112 // insertionOffset == set by sendPostedEvents to tell postEvent() where to start insertions
113 int insertionOffset;
114
115 QMutex mutex;
116
117 inline QPostEventList()
118 : QVector<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0)
119 { }
120
121 void addEvent(const QPostEvent &ev) {
122 int priority = ev.priority;
123 if (isEmpty() ||
124 constLast().priority >= priority ||
125 insertionOffset >= size()) {
126 // optimization: we can simply append if the last event in
127 // the queue has higher or equal priority
128 append(ev);
129 } else {
130 // insert event in descending priority order, using upper
131 // bound for a given priority (to ensure proper ordering
132 // of events with the same priority)
133 QPostEventList::iterator at = std::upper_bound(begin() + insertionOffset, end(), ev);
134 insert(at, ev);
135 }
136 }
137private:
138 //hides because they do not keep that list sorted. addEvent must be used
139 using QVector<QPostEvent>::append;
140 using QVector<QPostEvent>::insert;
141};
142
143#ifndef QT_NO_THREAD
144
145class Q_CORE_EXPORT QDaemonThread : public QThread
146{
147public:
148 QDaemonThread(QObject *parent = 0);
149 ~QDaemonThread();
150};
151
152class QThreadPrivate : public QObjectPrivate
153{
154 Q_DECLARE_PUBLIC(QThread)
155
156public:
157 QThreadPrivate(QThreadData *d = 0);
158 ~QThreadPrivate();
159
160 void setPriority(QThread::Priority prio);
161
162 mutable QMutex mutex;
163 QAtomicInt quitLockRef;
164
165 bool running;
166 bool finished;
167 bool isInFinish; //when in QThreadPrivate::finish
168 bool interruptionRequested;
169
170 bool exited;
171 int returnCode;
172
173 uint stackSize;
174 QThread::Priority priority;
175
176 static QThread *threadForId(int id);
177
178#ifdef Q_OS_UNIX
179 QWaitCondition thread_done;
180
181 static void *start(void *arg);
182 static void finish(void *);
183
184#endif // Q_OS_UNIX
185
186#ifdef Q_OS_WIN
187 static unsigned int __stdcall start(void *) Q_DECL_NOEXCEPT;
188 static void finish(void *, bool lockAnyway=true) Q_DECL_NOEXCEPT;
189
190 Qt::HANDLE handle;
191 unsigned int id;
192 int waiters;
193 bool terminationEnabled, terminatePending;
194#endif // Q_OS_WIN
195 QThreadData *data;
196
197 static void createEventDispatcher(QThreadData *data);
198
199 void ref()
200 {
201 quitLockRef.ref();
202 }
203
204 void deref()
205 {
206 if (!quitLockRef.deref() && running) {
207 QCoreApplication::instance()->postEvent(q_ptr, new QEvent(QEvent::Quit));
208 }
209 }
210};
211
212#else // QT_NO_THREAD
213
214class QThreadPrivate : public QObjectPrivate
215{
216public:
217 QThreadPrivate(QThreadData *d = 0) : data(d ? d : new QThreadData) {}
218 ~QThreadPrivate() { delete data; }
219
220 QThreadData *data;
221
222 static void setCurrentThread(QThread*) {}
223 static QThread *threadForId(int) { return QThread::currentThread(); }
224 static void createEventDispatcher(QThreadData *data);
225
226 void ref() {}
227 void deref() {}
228
229 Q_DECLARE_PUBLIC(QThread)
230};
231
232#endif // QT_NO_THREAD
233
234class QThreadData
235{
236public:
237 QThreadData(int initialRefCount = 1);
238 ~QThreadData();
239
240 static Q_AUTOTEST_EXPORT QThreadData *current(bool createIfNecessary = true);
241 static void clearCurrentThreadData();
242 static QThreadData *get2(QThread *thread)
243 { Q_ASSERT_X(thread != 0, "QThread", "internal error"); return thread->d_func()->data; }
244
245
246 void ref();
247 void deref();
248 inline bool hasEventDispatcher() const
249 { return eventDispatcher.load() != 0; }
250
251 bool canWaitLocked()
252 {
253 QMutexLocker locker(&postEventList.mutex);
254 return canWait;
255 }
256
257 // This class provides per-thread (by way of being a QThreadData
258 // member) storage for qFlagLocation()
259 class FlaggedDebugSignatures
260 {
261 static const uint Count = 2;
262
263 uint idx;
264 const char* locations[Count];
265
266 public:
267 FlaggedDebugSignatures() : idx(0)
268 { std::fill_n(locations, Count, static_cast<char*>(0)); }
269
270 void store(const char* method)
271 { locations[idx++ % Count] = method; }
272
273 bool contains(const char *method) const
274 { return std::find(locations, locations + Count, method) != locations + Count; }
275 };
276
277private:
278 QAtomicInt _ref;
279
280public:
281 int loopLevel;
282 int scopeLevel;
283
284 QStack<QEventLoop *> eventLoops;
285 QPostEventList postEventList;
286 QAtomicPointer<QThread> thread;
287 QAtomicPointer<void> threadId;
288 QAtomicPointer<QAbstractEventDispatcher> eventDispatcher;
289 QVector<void *> tls;
290 FlaggedDebugSignatures flaggedSignatures;
291
292 bool quitNow;
293 bool canWait;
294 bool isAdopted;
295 bool requiresCoreApplication;
296};
297
298class QScopedScopeLevelCounter
299{
300 QThreadData *threadData;
301public:
302 inline QScopedScopeLevelCounter(QThreadData *threadData)
303 : threadData(threadData)
304 { ++threadData->scopeLevel; }
305 inline ~QScopedScopeLevelCounter()
306 { --threadData->scopeLevel; }
307};
308
309// thread wrapper for the main() thread
310class QAdoptedThread : public QThread
311{
312 Q_DECLARE_PRIVATE(QThread)
313
314public:
315 QAdoptedThread(QThreadData *data = 0);
316 ~QAdoptedThread();
317 void init();
318
319private:
320 void run() override;
321};
322
323QT_END_NAMESPACE
324
325#endif // QTHREAD_P_H
326