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