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
103QT_BEGIN_NAMESPACE
104
105#if QT_CONFIG(thread)
106
107static_assert(sizeof(pthread_t) <= sizeof(Qt::HANDLE));
108
109enum { ThreadPriorityResetFlag = 0x80000000 };
110
111
112static thread_local QThreadData *currentThreadData = nullptr;
113
114static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT;
115static pthread_key_t current_thread_data_key;
116
117static 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
138static void create_current_thread_data_key()
139{
140 pthread_key_create(&current_thread_data_key, destroy_current_thread_data);
141}
142
143static void destroy_current_thread_data_key()
144{
145 pthread_once(&current_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}
154Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)
155
156
157// Utility functions for getting, setting and clearing thread specific data.
158static QThreadData *get_thread_data()
159{
160 return currentThreadData;
161}
162
163static void set_thread_data(QThreadData *data)
164{
165 currentThreadData = data;
166 pthread_once(&current_thread_data_once, create_current_thread_data_key);
167 pthread_setspecific(current_thread_data_key, data);
168}
169
170static void clear_thread_data()
171{
172 currentThreadData = nullptr;
173 pthread_setspecific(current_thread_data_key, nullptr);
174}
175
176template <typename T>
177static 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
182template <typename T>
183static 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
188template <typename T>
189static typename std::enable_if<QTypeInfo<T>::isPointer, Qt::HANDLE>::type to_HANDLE(T id)
190{
191 return id;
192}
193
194template <typename T>
195static typename std::enable_if<QTypeInfo<T>::isPointer, T>::type from_HANDLE(Qt::HANDLE id)
196{
197 return static_cast<T>(id);
198}
199
200void QThreadData::clearCurrentThreadData()
201{
202 clear_thread_data();
203}
204
205QThreadData *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
229void QAdoptedThread::init()
230{
231}
232
233/*
234 QThreadPrivate
235*/
236
237extern "C" {
238typedef void *(*QtThreadCallback)(void *);
239}
240
241#endif // QT_CONFIG(thread)
242
243QAbstractEventDispatcher *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))
269static 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
281void *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
353void 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 ** QThread
407 *************************************************************************/
408
409/*
410 CI tests fails on ARM architectures if we try to use the assembler, so
411 stick to the pthread version there. The assembler would be
412
413 // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344k/Babeihid.html
414 asm volatile ("mrc p15, 0, %0, c13, c0, 3" : "=r" (tid));
415
416 and
417
418 // see glibc/sysdeps/aarch64/nptl/tls.h
419 asm volatile ("mrs %0, tpidr_el0" : "=r" (tid));
420
421 for 32 and 64bit versions, respectively.
422*/
423Qt::HANDLE QThread::currentThreadIdImpl() noexcept
424{
425 return to_HANDLE(pthread_self());
426}
427
428#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
429// LSB doesn't define _SC_NPROCESSORS_ONLN.
430# define _SC_NPROCESSORS_ONLN 84
431#endif
432
433#ifdef Q_OS_WASM
434int QThreadPrivate::idealThreadCount = 1;
435#endif
436
437int QThread::idealThreadCount() noexcept
438{
439 int cores = 1;
440
441#if defined(Q_OS_HPUX)
442 // HP-UX
443 struct pst_dynamic psd;
444 if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
445 perror("pstat_getdynamic");
446 } else {
447 cores = (int)psd.psd_proc_cnt;
448 }
449#elif defined(Q_OS_BSD4)
450 // FreeBSD, OpenBSD, NetBSD, BSD/OS, OS X, iOS
451 size_t len = sizeof(cores);
452 int mib[2];
453 mib[0] = CTL_HW;
454 mib[1] = HW_NCPU;
455 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
456 perror("sysctl");
457 }
458#elif defined(Q_OS_INTEGRITY)
459#if (__INTEGRITY_MAJOR_VERSION >= 10)
460 // Integrity V10+ does support multicore CPUs
461 Value processorCount;
462 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
463 cores = processorCount;
464 else
465#endif
466 // as of aug 2008 Integrity only supports one single core CPU
467 cores = 1;
468#elif defined(Q_OS_VXWORKS)
469 // VxWorks
470# if defined(QT_VXWORKS_HAS_CPUSET)
471 cpuset_t cpus = vxCpuEnabledGet();
472 cores = 0;
473
474 // 128 cores should be enough for everyone ;)
475 for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
476 if (CPUSET_ISSET(cpus, i)) {
477 CPUSET_CLR(cpus, i);
478 cores++;
479 }
480 }
481# else
482 // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
483 cores = 1;
484# endif
485#elif defined(Q_OS_WASM)
486 cores = QThreadPrivate::idealThreadCount;
487#else
488 // the rest: Linux, Solaris, AIX, Tru64
489 cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
490 if (cores == -1)
491 return 1;
492#endif
493 return cores;
494}
495
496void QThread::yieldCurrentThread()
497{
498 sched_yield();
499}
500
501#endif // QT_CONFIG(thread)
502
503static timespec makeTimespec(time_t secs, long nsecs)
504{
505 struct timespec ts;
506 ts.tv_sec = secs;
507 ts.tv_nsec = nsecs;
508 return ts;
509}
510
511void QThread::sleep(unsigned long secs)
512{
513 qt_nanosleep(makeTimespec(secs, 0));
514}
515
516void QThread::msleep(unsigned long msecs)
517{
518 qt_nanosleep(makeTimespec(msecs / 1000, msecs % 1000 * 1000 * 1000));
519}
520
521void QThread::usleep(unsigned long usecs)
522{
523 qt_nanosleep(makeTimespec(usecs / 1000 / 1000, usecs % (1000*1000) * 1000));
524}
525
526#if QT_CONFIG(thread)
527
528#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
529#if defined(Q_OS_QNX)
530static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
531{
532 // On QNX, NormalPriority is mapped to 10. A QNX system could use a value different
533 // than 10 for the "normal" priority but it's difficult to achieve this so we'll
534 // assume that no one has ever created such a system. This makes the mapping from
535 // Qt priorities to QNX priorities lopsided. There's usually more space available
536 // to map into above the "normal" priority than below it. QNX also has a privileged
537 // priority range (for threads that assist the kernel). We'll assume that no Qt
538 // thread needs to use priorities in that range.
539 int priority_norm = 10;
540 // _sched_info::priority_priv isn't documented. You'd think that it's the start of the
541 // privileged priority range but it's actually the end of the unpriviledged range.
542 struct _sched_info info;
543 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
544 return false;
545
546 if (priority == QThread::IdlePriority) {
547 *sched_priority = info.priority_min;
548 return true;
549 }
550
551 if (priority_norm < info.priority_min)
552 priority_norm = info.priority_min;
553 if (priority_norm > info.priority_priv)
554 priority_norm = info.priority_priv;
555
556 int to_min, to_max;
557 int from_min, from_max;
558 int prio;
559 if (priority < QThread::NormalPriority) {
560 to_min = info.priority_min;
561 to_max = priority_norm;
562 from_min = QThread::LowestPriority;
563 from_max = QThread::NormalPriority;
564 } else {
565 to_min = priority_norm;
566 to_max = info.priority_priv;
567 from_min = QThread::NormalPriority;
568 from_max = QThread::TimeCriticalPriority;
569 }
570
571 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
572 prio = qBound(to_min, prio, to_max);
573
574 *sched_priority = prio;
575 return true;
576}
577#else
578// Does some magic and calculate the Unix scheduler priorities
579// sched_policy is IN/OUT: it must be set to a valid policy before calling this function
580// sched_priority is OUT only
581static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
582{
583#ifdef SCHED_IDLE
584 if (priority == QThread::IdlePriority) {
585 *sched_policy = SCHED_IDLE;
586 *sched_priority = 0;
587 return true;
588 }
589 const int lowestPriority = QThread::LowestPriority;
590#else
591 const int lowestPriority = QThread::IdlePriority;
592#endif
593 const int highestPriority = QThread::TimeCriticalPriority;
594
595 int prio_min;
596 int prio_max;
597#if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM)
598 // for other scheduling policies than SCHED_RR or SCHED_FIFO
599 prio_min = SCHED_FIFO_LOW_PRI;
600 prio_max = SCHED_FIFO_HIGH_PRI;
601
602 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
603#endif
604 {
605 prio_min = sched_get_priority_min(*sched_policy);
606 prio_max = sched_get_priority_max(*sched_policy);
607 }
608
609 if (prio_min == -1 || prio_max == -1)
610 return false;
611
612 int prio;
613 // crudely scale our priority enum values to the prio_min/prio_max
614 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
615 prio = qMax(prio_min, qMin(prio_max, prio));
616
617 *sched_priority = prio;
618 return true;
619}
620#endif
621#endif
622
623void QThread::start(Priority priority)
624{
625 Q_D(QThread);
626 QMutexLocker locker(&d->mutex);
627
628 if (d->isInFinish)
629 d->thread_done.wait(locker.mutex());
630
631 if (d->running)
632 return;
633
634 d->running = true;
635 d->finished = false;
636 d->returnCode = 0;
637 d->exited = false;
638 d->interruptionRequested = false;
639
640 pthread_attr_t attr;
641 pthread_attr_init(&attr);
642 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
643
644 d->priority = priority;
645
646#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
647 switch (priority) {
648 case InheritPriority:
649 {
650 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
651 break;
652 }
653
654 default:
655 {
656 int sched_policy;
657 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
658 // failed to get the scheduling policy, don't bother
659 // setting the priority
660 qWarning("QThread::start: Cannot determine default scheduler policy");
661 break;
662 }
663
664 int prio;
665 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
666 // failed to get the scheduling parameters, don't
667 // bother setting the priority
668 qWarning("QThread::start: Cannot determine scheduler priority range");
669 break;
670 }
671
672 sched_param sp;
673 sp.sched_priority = prio;
674
675 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
676 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
677 || pthread_attr_setschedparam(&attr, &sp) != 0) {
678 // could not set scheduling hints, fallback to inheriting them
679 // we'll try again from inside the thread
680 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
681 d->priority = Priority(priority | ThreadPriorityResetFlag);
682 }
683 break;
684 }
685 }
686#endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
687
688
689 if (d->stackSize > 0) {
690#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
691 int code = pthread_attr_setstacksize(&attr, d->stackSize);
692#else
693 int code = ENOSYS; // stack size not supported, automatically fail
694#endif // _POSIX_THREAD_ATTR_STACKSIZE
695
696 if (code) {
697 qErrnoWarning(code, "QThread::start: Thread stack size error");
698
699 // we failed to set the stacksize, and as the documentation states,
700 // the thread will fail to run...
701 d->running = false;
702 d->finished = false;
703 return;
704 }
705 }
706
707#ifdef Q_OS_INTEGRITY
708 if (Q_LIKELY(objectName().isEmpty()))
709 pthread_attr_setthreadname(&attr, metaObject()->className());
710 else
711 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
712#endif
713 pthread_t threadId;
714 int code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
715 if (code == EPERM) {
716 // caller does not have permission to set the scheduling
717 // parameters/policy
718#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
719 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
720#endif
721 code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
722 }
723 d->data->threadId.storeRelaxed(to_HANDLE(threadId));
724
725 pthread_attr_destroy(&attr);
726
727 if (code) {
728 qErrnoWarning(code, "QThread::start: Thread creation error");
729
730 d->running = false;
731 d->finished = false;
732 d->data->threadId.storeRelaxed(nullptr);
733 }
734}
735
736void QThread::terminate()
737{
738#if !defined(Q_OS_ANDROID)
739 Q_D(QThread);
740 QMutexLocker locker(&d->mutex);
741
742 if (!d->data->threadId.loadRelaxed())
743 return;
744
745 int code = pthread_cancel(from_HANDLE<pthread_t>(d->data->threadId.loadRelaxed()));
746 if (code) {
747 qErrnoWarning(code, "QThread::start: Thread termination error");
748 }
749#endif
750}
751
752bool QThread::wait(QDeadlineTimer deadline)
753{
754 Q_D(QThread);
755 QMutexLocker locker(&d->mutex);
756
757 if (from_HANDLE<pthread_t>(d->data->threadId.loadRelaxed()) == pthread_self()) {
758 qWarning("QThread::wait: Thread tried to wait on itself");
759 return false;
760 }
761
762 if (d->finished || !d->running)
763 return true;
764
765 while (d->running) {
766 if (!d->thread_done.wait(locker.mutex(), deadline))
767 return false;
768 }
769 return true;
770}
771
772void QThread::setTerminationEnabled(bool enabled)
773{
774 QThread *thr = currentThread();
775 Q_ASSERT_X(thr != nullptr, "QThread::setTerminationEnabled()",
776 "Current thread was not started with QThread.");
777
778 Q_UNUSED(thr);
779#if defined(Q_OS_ANDROID)
780 Q_UNUSED(enabled);
781#else
782 pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, nullptr);
783 if (enabled)
784 pthread_testcancel();
785#endif
786}
787
788// Caller must lock the mutex
789void QThreadPrivate::setPriority(QThread::Priority threadPriority)
790{
791 priority = threadPriority;
792
793 // copied from start() with a few modifications:
794
795#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
796 int sched_policy;
797 sched_param param;
798
799 if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, &param) != 0) {
800 // failed to get the scheduling policy, don't bother setting
801 // the priority
802 qWarning("QThread::setPriority: Cannot get scheduler parameters");
803 return;
804 }
805
806 int prio;
807 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
808 // failed to get the scheduling parameters, don't
809 // bother setting the priority
810 qWarning("QThread::setPriority: Cannot determine scheduler priority range");
811 return;
812 }
813
814 param.sched_priority = prio;
815 int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, &param);
816
817# ifdef SCHED_IDLE
818 // were we trying to set to idle priority and failed?
819 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
820 // reset to lowest priority possible
821 pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, &param);
822 param.sched_priority = sched_get_priority_min(sched_policy);
823 pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, &param);
824 }
825# else
826 Q_UNUSED(status);
827# endif // SCHED_IDLE
828#endif
829}
830
831#endif // QT_CONFIG(thread)
832
833QT_END_NAMESPACE
834
835