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