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 #include "qthread.h"
42
43 #include "qplatformdefs.h"
44
45 #include <private/qcoreapplication_p.h>
46 #include <private/qcore_unix_p.h>
47
48 #if defined(Q_OS_DARWIN)
49 # include <private/qeventdispatcher_cf_p.h>
50 #else
51 # if !defined(QT_NO_GLIB)
52 # include "../kernel/qeventdispatcher_glib_p.h"
53 # endif
54 #endif
55
56 #include <private/qeventdispatcher_unix_p.h>
57
58 #include "qthreadstorage.h"
59
60 #include "qthread_p.h"
61
62 #include "qdebug.h"
63
64 #ifdef __GLIBCXX__
65 #include <cxxabi.h>
66 #endif
67
68 #include <sched.h>
69 #include <errno.h>
70
71 #ifdef Q_OS_BSD4
72 #include <sys/sysctl.h>
73 #endif
74 #ifdef Q_OS_VXWORKS
75 # if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
76 # include <vxCpuLib.h>
77 # include <cpuset.h>
78 # define QT_VXWORKS_HAS_CPUSET
79 # endif
80 #endif
81
82 #ifdef Q_OS_HPUX
83 #include <sys/pstat.h>
84 #endif
85
86 #if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
87 #include <sys/prctl.h>
88 #endif
89
90 #if defined(Q_OS_LINUX) && !defined(SCHED_IDLE)
91 // from linux/sched.h
92 # define SCHED_IDLE 5
93 #endif
94
95 #if defined(Q_OS_DARWIN) || !defined(Q_OS_ANDROID) && !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
96 #define QT_HAS_THREAD_PRIORITY_SCHEDULING
97 #endif
98
99 #if defined(Q_OS_QNX)
100 #include <sys/neutrino.h>
101 #endif
102
103 QT_BEGIN_NAMESPACE
104
105 #if QT_CONFIG(thread)
106
107 Q_STATIC_ASSERT(sizeof(pthread_t) <= sizeof(Qt::HANDLE));
108
109 enum { ThreadPriorityResetFlag = 0x80000000 };
110
111
112 static thread_local QThreadData *currentThreadData = nullptr;
113
114 static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT;
115 static pthread_key_t current_thread_data_key;
116
destroy_current_thread_data(void * p)117 static void destroy_current_thread_data(void *p)
118 {
119 QThreadData *data = static_cast<QThreadData *>(p);
120 // thread_local variables are set to zero before calling this destructor function,
121 // if they are internally using pthread-specific data management,
122 // so we need to set it back to the right value...
123 currentThreadData = data;
124 if (data->isAdopted) {
125 QThread *thread = data->thread.loadAcquire();
126 Q_ASSERT(thread);
127 QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
128 Q_ASSERT(!thread_p->finished);
129 thread_p->finish(thread);
130 }
131 data->deref();
132
133 // ... but we must reset it to zero before returning so we aren't
134 // leaving a dangling pointer.
135 currentThreadData = nullptr;
136 }
137
create_current_thread_data_key()138 static void create_current_thread_data_key()
139 {
140 pthread_key_create(¤t_thread_data_key, destroy_current_thread_data);
141 }
142
destroy_current_thread_data_key()143 static void destroy_current_thread_data_key()
144 {
145 pthread_once(¤t_thread_data_once, create_current_thread_data_key);
146 pthread_key_delete(current_thread_data_key);
147
148 // Reset current_thread_data_once in case we end up recreating
149 // the thread-data in the rare case of QObject construction
150 // after destroying the QThreadData.
151 pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT;
152 current_thread_data_once = pthread_once_init;
153 }
Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)154 Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)
155
156
157 // Utility functions for getting, setting and clearing thread specific data.
158 static QThreadData *get_thread_data()
159 {
160 return currentThreadData;
161 }
162
set_thread_data(QThreadData * data)163 static void set_thread_data(QThreadData *data)
164 {
165 currentThreadData = data;
166 pthread_once(¤t_thread_data_once, create_current_thread_data_key);
167 pthread_setspecific(current_thread_data_key, data);
168 }
169
clear_thread_data()170 static void clear_thread_data()
171 {
172 currentThreadData = nullptr;
173 pthread_setspecific(current_thread_data_key, nullptr);
174 }
175
176 template <typename T>
to_HANDLE(T id)177 static typename std::enable_if<QTypeInfo<T>::isIntegral, Qt::HANDLE>::type to_HANDLE(T id)
178 {
179 return reinterpret_cast<Qt::HANDLE>(static_cast<intptr_t>(id));
180 }
181
182 template <typename T>
from_HANDLE(Qt::HANDLE id)183 static typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type from_HANDLE(Qt::HANDLE id)
184 {
185 return static_cast<T>(reinterpret_cast<intptr_t>(id));
186 }
187
188 template <typename T>
to_HANDLE(T id)189 static typename std::enable_if<QTypeInfo<T>::isPointer, Qt::HANDLE>::type to_HANDLE(T id)
190 {
191 return id;
192 }
193
194 template <typename T>
from_HANDLE(Qt::HANDLE id)195 static typename std::enable_if<QTypeInfo<T>::isPointer, T>::type from_HANDLE(Qt::HANDLE id)
196 {
197 return static_cast<T>(id);
198 }
199
clearCurrentThreadData()200 void QThreadData::clearCurrentThreadData()
201 {
202 clear_thread_data();
203 }
204
current(bool createIfNecessary)205 QThreadData *QThreadData::current(bool createIfNecessary)
206 {
207 QThreadData *data = get_thread_data();
208 if (!data && createIfNecessary) {
209 data = new QThreadData;
210 QT_TRY {
211 set_thread_data(data);
212 data->thread = new QAdoptedThread(data);
213 } QT_CATCH(...) {
214 clear_thread_data();
215 data->deref();
216 data = nullptr;
217 QT_RETHROW;
218 }
219 data->deref();
220 data->isAdopted = true;
221 data->threadId.storeRelaxed(to_HANDLE(pthread_self()));
222 if (!QCoreApplicationPrivate::theMainThread.loadAcquire())
223 QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed());
224 }
225 return data;
226 }
227
228
init()229 void QAdoptedThread::init()
230 {
231 }
232
233 /*
234 QThreadPrivate
235 */
236
237 extern "C" {
238 typedef void*(*QtThreadCallback)(void*);
239 }
240
241 #endif // QT_CONFIG(thread)
242
createEventDispatcher(QThreadData * data)243 QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *data)
244 {
245 Q_UNUSED(data);
246 #if defined(Q_OS_DARWIN)
247 bool ok = false;
248 int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
249 if (ok && value > 0)
250 return new QEventDispatcherCoreFoundation;
251 else
252 return new QEventDispatcherUNIX;
253 #elif !defined(QT_NO_GLIB)
254 const bool isQtMainThread = data->thread.loadAcquire() == QCoreApplicationPrivate::mainThread();
255 if (qEnvironmentVariableIsEmpty("QT_NO_GLIB")
256 && (isQtMainThread || qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB"))
257 && QEventDispatcherGlib::versionSupported())
258 return new QEventDispatcherGlib;
259 else
260 return new QEventDispatcherUNIX;
261 #else
262 return new QEventDispatcherUNIX;
263 #endif
264 }
265
266 #if QT_CONFIG(thread)
267
268 #if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
setCurrentThreadName(const char * name)269 static void setCurrentThreadName(const char *name)
270 {
271 # if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
272 prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
273 # elif defined(Q_OS_MAC)
274 pthread_setname_np(name);
275 # elif defined(Q_OS_QNX)
276 pthread_setname_np(pthread_self(), name);
277 # endif
278 }
279 #endif
280
start(void * arg)281 void *QThreadPrivate::start(void *arg)
282 {
283 #if !defined(Q_OS_ANDROID)
284 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
285 #endif
286 pthread_cleanup_push(QThreadPrivate::finish, arg);
287
288 #ifndef QT_NO_EXCEPTIONS
289 try
290 #endif
291 {
292 QThread *thr = reinterpret_cast<QThread *>(arg);
293 QThreadData *data = QThreadData::get2(thr);
294
295 {
296 QMutexLocker locker(&thr->d_func()->mutex);
297
298 // do we need to reset the thread priority?
299 if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
300 thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
301 }
302
303 data->threadId.storeRelaxed(to_HANDLE(pthread_self()));
304 set_thread_data(data);
305
306 data->ref();
307 data->quitNow = thr->d_func()->exited;
308 }
309
310 data->ensureEventDispatcher();
311
312 #if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
313 {
314 // Sets the name of the current thread. We can only do this
315 // when the thread is starting, as we don't have a cross
316 // platform way of setting the name of an arbitrary thread.
317 if (Q_LIKELY(thr->objectName().isEmpty()))
318 setCurrentThreadName(thr->metaObject()->className());
319 else
320 setCurrentThreadName(thr->objectName().toLocal8Bit());
321 }
322 #endif
323
324 emit thr->started(QThread::QPrivateSignal());
325 #if !defined(Q_OS_ANDROID)
326 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr);
327 pthread_testcancel();
328 #endif
329 thr->run();
330 }
331 #ifndef QT_NO_EXCEPTIONS
332 #ifdef __GLIBCXX__
333 // POSIX thread cancellation under glibc is implemented by throwing an exception
334 // of this type. Do what libstdc++ is doing and handle it specially in order not to
335 // abort the application if user's code calls a cancellation function.
336 catch (const abi::__forced_unwind &) {
337 throw;
338 }
339 #endif // __GLIBCXX__
340 catch (...) {
341 qTerminate();
342 }
343 #endif // QT_NO_EXCEPTIONS
344
345 // This pop runs finish() below. It's outside the try/catch (and has its
346 // own try/catch) to prevent finish() to be run in case an exception is
347 // thrown.
348 pthread_cleanup_pop(1);
349
350 return nullptr;
351 }
352
finish(void * arg)353 void QThreadPrivate::finish(void *arg)
354 {
355 #ifndef QT_NO_EXCEPTIONS
356 try
357 #endif
358 {
359 QThread *thr = reinterpret_cast<QThread *>(arg);
360 QThreadPrivate *d = thr->d_func();
361
362 QMutexLocker locker(&d->mutex);
363
364 d->isInFinish = true;
365 d->priority = QThread::InheritPriority;
366 void *data = &d->data->tls;
367 locker.unlock();
368 emit thr->finished(QThread::QPrivateSignal());
369 QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
370 QThreadStorageData::finish((void **)data);
371 locker.relock();
372
373 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
374 if (eventDispatcher) {
375 d->data->eventDispatcher = nullptr;
376 locker.unlock();
377 eventDispatcher->closingDown();
378 delete eventDispatcher;
379 locker.relock();
380 }
381
382 d->running = false;
383 d->finished = true;
384 d->interruptionRequested = false;
385
386 d->isInFinish = false;
387 d->thread_done.wakeAll();
388 }
389 #ifndef QT_NO_EXCEPTIONS
390 #ifdef __GLIBCXX__
391 // POSIX thread cancellation under glibc is implemented by throwing an exception
392 // of this type. Do what libstdc++ is doing and handle it specially in order not to
393 // abort the application if user's code calls a cancellation function.
394 catch (const abi::__forced_unwind &) {
395 throw;
396 }
397 #endif // __GLIBCXX__
398 catch (...) {
399 qTerminate();
400 }
401 #endif // QT_NO_EXCEPTIONS
402 }
403
404
405
406
407 /**************************************************************************
408 ** QThread
409 *************************************************************************/
410
currentThreadId()411 Qt::HANDLE QThread::currentThreadId() noexcept
412 {
413 // requires a C cast here otherwise we run into trouble on AIX
414 return to_HANDLE(pthread_self());
415 }
416
417 #if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
418 // LSB doesn't define _SC_NPROCESSORS_ONLN.
419 # define _SC_NPROCESSORS_ONLN 84
420 #endif
421
422 #ifdef Q_OS_WASM
423 int QThreadPrivate::idealThreadCount = 1;
424 #endif
425
idealThreadCount()426 int QThread::idealThreadCount() noexcept
427 {
428 int cores = 1;
429
430 #if defined(Q_OS_HPUX)
431 // HP-UX
432 struct pst_dynamic psd;
433 if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
434 perror("pstat_getdynamic");
435 } else {
436 cores = (int)psd.psd_proc_cnt;
437 }
438 #elif defined(Q_OS_BSD4)
439 // FreeBSD, OpenBSD, NetBSD, BSD/OS, OS X, iOS
440 size_t len = sizeof(cores);
441 int mib[2];
442 mib[0] = CTL_HW;
443 mib[1] = HW_NCPU;
444 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
445 perror("sysctl");
446 }
447 #elif defined(Q_OS_INTEGRITY)
448 #if (__INTEGRITY_MAJOR_VERSION >= 10)
449 // Integrity V10+ does support multicore CPUs
450 Value processorCount;
451 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
452 cores = processorCount;
453 else
454 #endif
455 // as of aug 2008 Integrity only supports one single core CPU
456 cores = 1;
457 #elif defined(Q_OS_VXWORKS)
458 // VxWorks
459 # if defined(QT_VXWORKS_HAS_CPUSET)
460 cpuset_t cpus = vxCpuEnabledGet();
461 cores = 0;
462
463 // 128 cores should be enough for everyone ;)
464 for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
465 if (CPUSET_ISSET(cpus, i)) {
466 CPUSET_CLR(cpus, i);
467 cores++;
468 }
469 }
470 # else
471 // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
472 cores = 1;
473 # endif
474 #elif defined(Q_OS_WASM)
475 cores = QThreadPrivate::idealThreadCount;
476 #else
477 // the rest: Linux, Solaris, AIX, Tru64
478 cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
479 if (cores == -1)
480 return 1;
481 #endif
482 return cores;
483 }
484
yieldCurrentThread()485 void QThread::yieldCurrentThread()
486 {
487 sched_yield();
488 }
489
490 #endif // QT_CONFIG(thread)
491
makeTimespec(time_t secs,long nsecs)492 static timespec makeTimespec(time_t secs, long nsecs)
493 {
494 struct timespec ts;
495 ts.tv_sec = secs;
496 ts.tv_nsec = nsecs;
497 return ts;
498 }
499
sleep(unsigned long secs)500 void QThread::sleep(unsigned long secs)
501 {
502 qt_nanosleep(makeTimespec(secs, 0));
503 }
504
msleep(unsigned long msecs)505 void QThread::msleep(unsigned long msecs)
506 {
507 qt_nanosleep(makeTimespec(msecs / 1000, msecs % 1000 * 1000 * 1000));
508 }
509
usleep(unsigned long usecs)510 void QThread::usleep(unsigned long usecs)
511 {
512 qt_nanosleep(makeTimespec(usecs / 1000 / 1000, usecs % (1000*1000) * 1000));
513 }
514
515 #if QT_CONFIG(thread)
516
517 #ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
518 #if defined(Q_OS_QNX)
calculateUnixPriority(int priority,int * sched_policy,int * sched_priority)519 static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
520 {
521 // On QNX, NormalPriority is mapped to 10. A QNX system could use a value different
522 // than 10 for the "normal" priority but it's difficult to achieve this so we'll
523 // assume that no one has ever created such a system. This makes the mapping from
524 // Qt priorities to QNX priorities lopsided. There's usually more space available
525 // to map into above the "normal" priority than below it. QNX also has a privileged
526 // priority range (for threads that assist the kernel). We'll assume that no Qt
527 // thread needs to use priorities in that range.
528 int priority_norm = 10;
529 // _sched_info::priority_priv isn't documented. You'd think that it's the start of the
530 // privileged priority range but it's actually the end of the unpriviledged range.
531 struct _sched_info info;
532 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
533 return false;
534
535 if (priority == QThread::IdlePriority) {
536 *sched_priority = info.priority_min;
537 return true;
538 }
539
540 if (priority_norm < info.priority_min)
541 priority_norm = info.priority_min;
542 if (priority_norm > info.priority_priv)
543 priority_norm = info.priority_priv;
544
545 int to_min, to_max;
546 int from_min, from_max;
547 int prio;
548 if (priority < QThread::NormalPriority) {
549 to_min = info.priority_min;
550 to_max = priority_norm;
551 from_min = QThread::LowestPriority;
552 from_max = QThread::NormalPriority;
553 } else {
554 to_min = priority_norm;
555 to_max = info.priority_priv;
556 from_min = QThread::NormalPriority;
557 from_max = QThread::TimeCriticalPriority;
558 }
559
560 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
561 prio = qBound(to_min, prio, to_max);
562
563 *sched_priority = prio;
564 return true;
565 }
566 #else
567 // Does some magic and calculate the Unix scheduler priorities
568 // sched_policy is IN/OUT: it must be set to a valid policy before calling this function
569 // sched_priority is OUT only
calculateUnixPriority(int priority,int * sched_policy,int * sched_priority)570 static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
571 {
572 #ifdef SCHED_IDLE
573 if (priority == QThread::IdlePriority) {
574 *sched_policy = SCHED_IDLE;
575 *sched_priority = 0;
576 return true;
577 }
578 const int lowestPriority = QThread::LowestPriority;
579 #else
580 const int lowestPriority = QThread::IdlePriority;
581 #endif
582 const int highestPriority = QThread::TimeCriticalPriority;
583
584 int prio_min;
585 int prio_max;
586 #if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM)
587 // for other scheduling policies than SCHED_RR or SCHED_FIFO
588 prio_min = SCHED_FIFO_LOW_PRI;
589 prio_max = SCHED_FIFO_HIGH_PRI;
590
591 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
592 #endif
593 {
594 prio_min = sched_get_priority_min(*sched_policy);
595 prio_max = sched_get_priority_max(*sched_policy);
596 }
597
598 if (prio_min == -1 || prio_max == -1)
599 return false;
600
601 int prio;
602 // crudely scale our priority enum values to the prio_min/prio_max
603 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
604 prio = qMax(prio_min, qMin(prio_max, prio));
605
606 *sched_priority = prio;
607 return true;
608 }
609 #endif
610 #endif
611
start(Priority priority)612 void QThread::start(Priority priority)
613 {
614 Q_D(QThread);
615 QMutexLocker locker(&d->mutex);
616
617 if (d->isInFinish)
618 d->thread_done.wait(locker.mutex());
619
620 if (d->running)
621 return;
622
623 d->running = true;
624 d->finished = false;
625 d->returnCode = 0;
626 d->exited = false;
627 d->interruptionRequested = false;
628
629 pthread_attr_t attr;
630 pthread_attr_init(&attr);
631 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
632
633 d->priority = priority;
634
635 #if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
636 switch (priority) {
637 case InheritPriority:
638 {
639 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
640 break;
641 }
642
643 default:
644 {
645 int sched_policy;
646 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
647 // failed to get the scheduling policy, don't bother
648 // setting the priority
649 qWarning("QThread::start: Cannot determine default scheduler policy");
650 break;
651 }
652
653 int prio;
654 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
655 // failed to get the scheduling parameters, don't
656 // bother setting the priority
657 qWarning("QThread::start: Cannot determine scheduler priority range");
658 break;
659 }
660
661 sched_param sp;
662 sp.sched_priority = prio;
663
664 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
665 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
666 || pthread_attr_setschedparam(&attr, &sp) != 0) {
667 // could not set scheduling hints, fallback to inheriting them
668 // we'll try again from inside the thread
669 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
670 d->priority = Priority(priority | ThreadPriorityResetFlag);
671 }
672 break;
673 }
674 }
675 #endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
676
677
678 if (d->stackSize > 0) {
679 #if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
680 int code = pthread_attr_setstacksize(&attr, d->stackSize);
681 #else
682 int code = ENOSYS; // stack size not supported, automatically fail
683 #endif // _POSIX_THREAD_ATTR_STACKSIZE
684
685 if (code) {
686 qErrnoWarning(code, "QThread::start: Thread stack size error");
687
688 // we failed to set the stacksize, and as the documentation states,
689 // the thread will fail to run...
690 d->running = false;
691 d->finished = false;
692 return;
693 }
694 }
695
696 #ifdef Q_OS_INTEGRITY
697 if (Q_LIKELY(objectName().isEmpty()))
698 pthread_attr_setthreadname(&attr, metaObject()->className());
699 else
700 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
701 #endif
702 pthread_t threadId;
703 int code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
704 if (code == EPERM) {
705 // caller does not have permission to set the scheduling
706 // parameters/policy
707 #if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
708 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
709 #endif
710 code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
711 }
712 d->data->threadId.storeRelaxed(to_HANDLE(threadId));
713
714 pthread_attr_destroy(&attr);
715
716 if (code) {
717 qErrnoWarning(code, "QThread::start: Thread creation error");
718
719 d->running = false;
720 d->finished = false;
721 d->data->threadId.storeRelaxed(nullptr);
722 }
723 }
724
terminate()725 void QThread::terminate()
726 {
727 #if !defined(Q_OS_ANDROID)
728 Q_D(QThread);
729 QMutexLocker locker(&d->mutex);
730
731 if (!d->data->threadId.loadRelaxed())
732 return;
733
734 int code = pthread_cancel(from_HANDLE<pthread_t>(d->data->threadId.loadRelaxed()));
735 if (code) {
736 qErrnoWarning(code, "QThread::start: Thread termination error");
737 }
738 #endif
739 }
740
wait(QDeadlineTimer deadline)741 bool QThread::wait(QDeadlineTimer deadline)
742 {
743 Q_D(QThread);
744 QMutexLocker locker(&d->mutex);
745
746 if (from_HANDLE<pthread_t>(d->data->threadId.loadRelaxed()) == pthread_self()) {
747 qWarning("QThread::wait: Thread tried to wait on itself");
748 return false;
749 }
750
751 if (d->finished || !d->running)
752 return true;
753
754 while (d->running) {
755 if (!d->thread_done.wait(locker.mutex(), deadline))
756 return false;
757 }
758 return true;
759 }
760
setTerminationEnabled(bool enabled)761 void QThread::setTerminationEnabled(bool enabled)
762 {
763 QThread *thr = currentThread();
764 Q_ASSERT_X(thr != nullptr, "QThread::setTerminationEnabled()",
765 "Current thread was not started with QThread.");
766
767 Q_UNUSED(thr)
768 #if defined(Q_OS_ANDROID)
769 Q_UNUSED(enabled);
770 #else
771 pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, nullptr);
772 if (enabled)
773 pthread_testcancel();
774 #endif
775 }
776
777 // Caller must lock the mutex
setPriority(QThread::Priority threadPriority)778 void QThreadPrivate::setPriority(QThread::Priority threadPriority)
779 {
780 priority = threadPriority;
781
782 // copied from start() with a few modifications:
783
784 #ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
785 int sched_policy;
786 sched_param param;
787
788 if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m) != 0) {
789 // failed to get the scheduling policy, don't bother setting
790 // the priority
791 qWarning("QThread::setPriority: Cannot get scheduler parameters");
792 return;
793 }
794
795 int prio;
796 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
797 // failed to get the scheduling parameters, don't
798 // bother setting the priority
799 qWarning("QThread::setPriority: Cannot determine scheduler priority range");
800 return;
801 }
802
803 param.sched_priority = prio;
804 int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
805
806 # ifdef SCHED_IDLE
807 // were we trying to set to idle priority and failed?
808 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
809 // reset to lowest priority possible
810 pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m);
811 param.sched_priority = sched_get_priority_min(sched_policy);
812 pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
813 }
814 # else
815 Q_UNUSED(status);
816 # endif // SCHED_IDLE
817 #endif
818 }
819
820 #endif // QT_CONFIG(thread)
821
822 QT_END_NAMESPACE
823
824