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