1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
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 
69 QT_BEGIN_NAMESPACE
70 
71 class QAbstractEventDispatcher;
72 class QEventLoop;
73 
74 class QPostEvent
75 {
76 public:
77     QObject *receiver;
78     QEvent *event;
79     int priority;
QPostEvent()80     inline QPostEvent()
81         : receiver(0), event(0), priority(0)
82     { }
QPostEvent(QObject * r,QEvent * e,int p)83     inline QPostEvent(QObject *r, QEvent *e, int p)
84         : receiver(r), event(e), priority(p)
85     { }
86 };
87 inline bool operator<(int priority, const QPostEvent &pe)
88 {
89     return pe.priority < priority;
90 }
91 inline 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
98 class QPostEventList : public QList<QPostEvent>
99 {
100 public:
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 
QPostEventList()111     inline QPostEventList()
112         : QList<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0)
113     { }
114 
addEvent(const QPostEvent & ev)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     }
129 private:
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 
137 class QThreadPrivate : public QObjectPrivate
138 {
139     Q_DECLARE_PUBLIC(QThread)
140 
141 public:
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 
192 class QThreadPrivate : public QObjectPrivate
193 {
194 public:
195     QThreadPrivate(QThreadData *d = 0) : data(d ? d : new QThreadData) {}
~QThreadPrivate()196     ~QThreadPrivate() { delete data; }
197 
198     QThreadData *data;
199 
setCurrentThread(QThread *)200     static void setCurrentThread(QThread*) {}
threadForId(int)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 
209 class QThreadData
210 {
211     QAtomicInt _ref;
212 
213 public:
214     QThreadData(int initialRefCount = 1);
215     ~QThreadData();
216 
217     static QThreadData *current();
218     static void clearCurrentThreadData();
get2(QThread * thread)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 
canWaitLocked()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:
FlaggedDebugSignatures()242         FlaggedDebugSignatures() : idx(0)
243         {
244             for (uint i = 0; i < Count; ++i)
245                 locations[i] = 0;
246         }
247 
store(const char * method)248         void store(const char* method)
249         { locations[idx++ % Count] = method; }
250 
contains(const char * method)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 
278 class QScopedLoopLevelCounter
279 {
280     QThreadData *threadData;
281 public:
QScopedLoopLevelCounter(QThreadData * threadData)282     inline QScopedLoopLevelCounter(QThreadData *threadData)
283         : threadData(threadData)
284     { ++threadData->loopLevel; }
~QScopedLoopLevelCounter()285     inline ~QScopedLoopLevelCounter()
286     { --threadData->loopLevel; }
287 };
288 
289 // thread wrapper for the main() thread
290 class QAdoptedThread : public QThread
291 {
292     Q_DECLARE_PRIVATE(QThread)
293 
294 public:
295     QAdoptedThread(QThreadData *data = 0);
296     ~QAdoptedThread();
297     void init();
298 
299     static QThread *createThreadForAdoption();
300 private:
301     void run();
302 };
303 
304 QT_END_NAMESPACE
305 
306 #endif // QTHREAD_P_H
307