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
107Q_STATIC_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(o: 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(key: &current_thread_data_key, destr_function: destroy_current_thread_data);
141}
142
143static void destroy_current_thread_data_key()
144{
145 pthread_once(once_control: &current_thread_data_once, init_routine: create_current_thread_data_key);
146 pthread_key_delete(key: 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(once_control: &current_thread_data_once, init_routine: create_current_thread_data_key);
167 pthread_setspecific(key: current_thread_data_key, pointer: data);
168}
169
170static void clear_thread_data()
171{
172 currentThreadData = nullptr;
173 pthread_setspecific(key: current_thread_data_key, pointer: 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(newValue: to_HANDLE(id: pthread_self()));
222 if (!QCoreApplicationPrivate::theMainThread.loadAcquire())
223 QCoreApplicationPrivate::theMainThread.storeRelease(newValue: 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(varName: "QT_NO_GLIB")
256 && (isQtMainThread || qEnvironmentVariableIsEmpty(varName: "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
281namespace {
282template <typename T>
283void terminate_on_exception(T &&t)
284{
285#ifndef QT_NO_EXCEPTIONS
286 try {
287#endif
288 std::forward<T>(t)();
289#ifndef QT_NO_EXCEPTIONS
290#ifdef __GLIBCXX__
291 // POSIX thread cancellation under glibc is implemented by throwing an exception
292 // of this type. Do what libstdc++ is doing and handle it specially in order not to
293 // abort the application if user's code calls a cancellation function.
294 } catch (abi::__forced_unwind &) {
295 throw;
296#endif // __GLIBCXX__
297 } catch (...) {
298 qTerminate();
299 }
300#endif // QT_NO_EXCEPTIONS
301}
302} // unnamed namespace
303
304void *QThreadPrivate::start(void *arg)
305{
306#if !defined(Q_OS_ANDROID)
307 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, oldstate: nullptr);
308#endif
309 pthread_cleanup_push(QThreadPrivate::finish, arg);
310
311 terminate_on_exception(t: [&] {
312 QThread *thr = reinterpret_cast<QThread *>(arg);
313 QThreadData *data = QThreadData::get2(thread: thr);
314
315 {
316 QMutexLocker locker(&thr->d_func()->mutex);
317
318 // do we need to reset the thread priority?
319 if (thr->d_func()->priority & ThreadPriorityResetFlag) {
320 thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
321 }
322
323 // threadId is set in QThread::start()
324 Q_ASSERT(pthread_equal(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()),
325 pthread_self()));
326 set_thread_data(data);
327
328 data->ref();
329 data->quitNow = thr->d_func()->exited;
330 }
331
332 data->ensureEventDispatcher();
333
334#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
335 {
336 // Sets the name of the current thread. We can only do this
337 // when the thread is starting, as we don't have a cross
338 // platform way of setting the name of an arbitrary thread.
339 if (Q_LIKELY(thr->d_func()->objectName.isEmpty()))
340 setCurrentThreadName(thr->metaObject()->className());
341 else
342 setCurrentThreadName(std::exchange(obj&: thr->d_func()->objectName, new_val: {}).toLocal8Bit());
343 }
344#endif
345
346 emit thr->started(QThread::QPrivateSignal());
347#if !defined(Q_OS_ANDROID)
348 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, oldstate: nullptr);
349 pthread_testcancel();
350#endif
351 thr->run();
352 });
353
354 // This pop runs finish() below. It's outside the try/catch (and has its
355 // own try/catch) to prevent finish() to be run in case an exception is
356 // thrown.
357 pthread_cleanup_pop(1);
358
359 return nullptr;
360}
361
362void QThreadPrivate::finish(void *arg)
363{
364 terminate_on_exception(t: [&] {
365 QThread *thr = reinterpret_cast<QThread *>(arg);
366 QThreadPrivate *d = thr->d_func();
367
368 QMutexLocker locker(&d->mutex);
369
370 d->isInFinish = true;
371 d->priority = QThread::InheritPriority;
372 void *data = &d->data->tls;
373 locker.unlock();
374 emit thr->finished(QThread::QPrivateSignal());
375 QCoreApplication::sendPostedEvents(receiver: nullptr, event_type: QEvent::DeferredDelete);
376 QThreadStorageData::finish((void **)data);
377 locker.relock();
378
379 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
380 if (eventDispatcher) {
381 d->data->eventDispatcher = nullptr;
382 locker.unlock();
383 eventDispatcher->closingDown();
384 delete eventDispatcher;
385 locker.relock();
386 }
387
388 d->running = false;
389 d->finished = true;
390 d->interruptionRequested = false;
391
392 d->isInFinish = false;
393 d->data->threadId.storeRelaxed(newValue: nullptr);
394
395 d->thread_done.wakeAll();
396 });
397}
398
399
400
401
402/**************************************************************************
403 ** QThread
404 *************************************************************************/
405
406Qt::HANDLE QThread::currentThreadId() noexcept
407{
408 // requires a C cast here otherwise we run into trouble on AIX
409 return to_HANDLE(id: pthread_self());
410}
411
412#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
413// LSB doesn't define _SC_NPROCESSORS_ONLN.
414# define _SC_NPROCESSORS_ONLN 84
415#endif
416
417#ifdef Q_OS_WASM
418int QThreadPrivate::idealThreadCount = 1;
419#endif
420
421int QThread::idealThreadCount() noexcept
422{
423 int cores = 1;
424
425#if defined(Q_OS_HPUX)
426 // HP-UX
427 struct pst_dynamic psd;
428 if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
429 perror("pstat_getdynamic");
430 } else {
431 cores = (int)psd.psd_proc_cnt;
432 }
433#elif defined(Q_OS_BSD4)
434 // FreeBSD, OpenBSD, NetBSD, BSD/OS, OS X, iOS
435 size_t len = sizeof(cores);
436 int mib[2];
437 mib[0] = CTL_HW;
438 mib[1] = HW_NCPU;
439 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
440 perror("sysctl");
441 }
442#elif defined(Q_OS_INTEGRITY)
443#if (__INTEGRITY_MAJOR_VERSION >= 10)
444 // Integrity V10+ does support multicore CPUs
445 Value processorCount;
446 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
447 cores = processorCount;
448 else
449#endif
450 // as of aug 2008 Integrity only supports one single core CPU
451 cores = 1;
452#elif defined(Q_OS_VXWORKS)
453 // VxWorks
454# if defined(QT_VXWORKS_HAS_CPUSET)
455 cpuset_t cpus = vxCpuEnabledGet();
456 cores = 0;
457
458 // 128 cores should be enough for everyone ;)
459 for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
460 if (CPUSET_ISSET(cpus, i)) {
461 CPUSET_CLR(cpus, i);
462 cores++;
463 }
464 }
465# else
466 // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
467 cores = 1;
468# endif
469#elif defined(Q_OS_WASM)
470 cores = QThreadPrivate::idealThreadCount;
471#else
472 // the rest: Linux, Solaris, AIX, Tru64
473 cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
474 if (cores == -1)
475 return 1;
476#endif
477 return cores;
478}
479
480void QThread::yieldCurrentThread()
481{
482 sched_yield();
483}
484
485#endif // QT_CONFIG(thread)
486
487static timespec makeTimespec(time_t secs, long nsecs)
488{
489 struct timespec ts;
490 ts.tv_sec = secs;
491 ts.tv_nsec = nsecs;
492 return ts;
493}
494
495void QThread::sleep(unsigned long secs)
496{
497 qt_nanosleep(amount: makeTimespec(secs, nsecs: 0));
498}
499
500void QThread::msleep(unsigned long msecs)
501{
502 qt_nanosleep(amount: makeTimespec(secs: msecs / 1000, nsecs: msecs % 1000 * 1000 * 1000));
503}
504
505void QThread::usleep(unsigned long usecs)
506{
507 qt_nanosleep(amount: makeTimespec(secs: usecs / 1000 / 1000, nsecs: usecs % (1000*1000) * 1000));
508}
509
510#if QT_CONFIG(thread)
511
512#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
513#if defined(Q_OS_QNX)
514static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
515{
516 // On QNX, NormalPriority is mapped to 10. A QNX system could use a value different
517 // than 10 for the "normal" priority but it's difficult to achieve this so we'll
518 // assume that no one has ever created such a system. This makes the mapping from
519 // Qt priorities to QNX priorities lopsided. There's usually more space available
520 // to map into above the "normal" priority than below it. QNX also has a privileged
521 // priority range (for threads that assist the kernel). We'll assume that no Qt
522 // thread needs to use priorities in that range.
523 int priority_norm = 10;
524 // _sched_info::priority_priv isn't documented. You'd think that it's the start of the
525 // privileged priority range but it's actually the end of the unpriviledged range.
526 struct _sched_info info;
527 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
528 return false;
529
530 if (priority == QThread::IdlePriority) {
531 *sched_priority = info.priority_min;
532 return true;
533 }
534
535 if (priority_norm < info.priority_min)
536 priority_norm = info.priority_min;
537 if (priority_norm > info.priority_priv)
538 priority_norm = info.priority_priv;
539
540 int to_min, to_max;
541 int from_min, from_max;
542 int prio;
543 if (priority < QThread::NormalPriority) {
544 to_min = info.priority_min;
545 to_max = priority_norm;
546 from_min = QThread::LowestPriority;
547 from_max = QThread::NormalPriority;
548 } else {
549 to_min = priority_norm;
550 to_max = info.priority_priv;
551 from_min = QThread::NormalPriority;
552 from_max = QThread::TimeCriticalPriority;
553 }
554
555 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
556 prio = qBound(to_min, prio, to_max);
557
558 *sched_priority = prio;
559 return true;
560}
561#else
562// Does some magic and calculate the Unix scheduler priorities
563// sched_policy is IN/OUT: it must be set to a valid policy before calling this function
564// sched_priority is OUT only
565static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
566{
567#ifdef SCHED_IDLE
568 if (priority == QThread::IdlePriority) {
569 *sched_policy = SCHED_IDLE;
570 *sched_priority = 0;
571 return true;
572 }
573 const int lowestPriority = QThread::LowestPriority;
574#else
575 const int lowestPriority = QThread::IdlePriority;
576#endif
577 const int highestPriority = QThread::TimeCriticalPriority;
578
579 int prio_min;
580 int prio_max;
581#if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM)
582 // for other scheduling policies than SCHED_RR or SCHED_FIFO
583 prio_min = SCHED_FIFO_LOW_PRI;
584 prio_max = SCHED_FIFO_HIGH_PRI;
585
586 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
587#endif
588 {
589 prio_min = sched_get_priority_min(algorithm: *sched_policy);
590 prio_max = sched_get_priority_max(algorithm: *sched_policy);
591 }
592
593 if (prio_min == -1 || prio_max == -1)
594 return false;
595
596 int prio;
597 // crudely scale our priority enum values to the prio_min/prio_max
598 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
599 prio = qMax(a: prio_min, b: qMin(a: prio_max, b: prio));
600
601 *sched_priority = prio;
602 return true;
603}
604#endif
605#endif
606
607void QThread::start(Priority priority)
608{
609 Q_D(QThread);
610 QMutexLocker locker(&d->mutex);
611
612 if (d->isInFinish)
613 d->thread_done.wait(lockedMutex: locker.mutex());
614
615 if (d->running)
616 return;
617
618 d->running = true;
619 d->finished = false;
620 d->returnCode = 0;
621 d->exited = false;
622 d->interruptionRequested = false;
623
624 pthread_attr_t attr;
625 pthread_attr_init(attr: &attr);
626 pthread_attr_setdetachstate(attr: &attr, PTHREAD_CREATE_DETACHED);
627
628 d->priority = priority;
629
630#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
631 switch (priority) {
632 case InheritPriority:
633 {
634 pthread_attr_setinheritsched(attr: &attr, PTHREAD_INHERIT_SCHED);
635 break;
636 }
637
638 default:
639 {
640 int sched_policy;
641 if (pthread_attr_getschedpolicy(attr: &attr, policy: &sched_policy) != 0) {
642 // failed to get the scheduling policy, don't bother
643 // setting the priority
644 qWarning(msg: "QThread::start: Cannot determine default scheduler policy");
645 break;
646 }
647
648 int prio;
649 if (!calculateUnixPriority(priority, sched_policy: &sched_policy, sched_priority: &prio)) {
650 // failed to get the scheduling parameters, don't
651 // bother setting the priority
652 qWarning(msg: "QThread::start: Cannot determine scheduler priority range");
653 break;
654 }
655
656 sched_param sp;
657 sp.sched_priority = prio;
658
659 if (pthread_attr_setinheritsched(attr: &attr, PTHREAD_EXPLICIT_SCHED) != 0
660 || pthread_attr_setschedpolicy(attr: &attr, policy: sched_policy) != 0
661 || pthread_attr_setschedparam(attr: &attr, param: &sp) != 0) {
662 // could not set scheduling hints, fallback to inheriting them
663 // we'll try again from inside the thread
664 pthread_attr_setinheritsched(attr: &attr, PTHREAD_INHERIT_SCHED);
665 d->priority = std::underlying_type<Priority>::type(priority) | ThreadPriorityResetFlag;
666 }
667 break;
668 }
669 }
670#endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
671
672
673 if (d->stackSize > 0) {
674#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
675 int code = pthread_attr_setstacksize(attr: &attr, stacksize: d->stackSize);
676#else
677 int code = ENOSYS; // stack size not supported, automatically fail
678#endif // _POSIX_THREAD_ATTR_STACKSIZE
679
680 if (code) {
681 qErrnoWarning(code, msg: "QThread::start: Thread stack size error");
682
683 // we failed to set the stacksize, and as the documentation states,
684 // the thread will fail to run...
685 d->running = false;
686 d->finished = false;
687 return;
688 }
689 }
690
691#ifdef Q_OS_INTEGRITY
692 if (Q_LIKELY(objectName().isEmpty()))
693 pthread_attr_setthreadname(&attr, metaObject()->className());
694 else
695 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
696#else
697 d->objectName = objectName();
698#endif
699
700 pthread_t threadId;
701 int code = pthread_create(newthread: &threadId, attr: &attr, start_routine: QThreadPrivate::start, arg: this);
702 if (code == EPERM) {
703 // caller does not have permission to set the scheduling
704 // parameters/policy
705#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
706 pthread_attr_setinheritsched(attr: &attr, PTHREAD_INHERIT_SCHED);
707#endif
708 code = pthread_create(newthread: &threadId, attr: &attr, start_routine: QThreadPrivate::start, arg: this);
709 }
710 d->data->threadId.storeRelaxed(newValue: to_HANDLE(id: threadId));
711
712 pthread_attr_destroy(attr: &attr);
713
714 if (code) {
715 qErrnoWarning(code, msg: "QThread::start: Thread creation error");
716
717 d->running = false;
718 d->finished = false;
719 d->data->threadId.storeRelaxed(newValue: nullptr);
720 }
721}
722
723void QThread::terminate()
724{
725#if !defined(Q_OS_ANDROID)
726 Q_D(QThread);
727 QMutexLocker locker(&d->mutex);
728
729 if (!d->data->threadId.loadRelaxed())
730 return;
731
732 int code = pthread_cancel(th: from_HANDLE<pthread_t>(id: d->data->threadId.loadRelaxed()));
733 if (code) {
734 qErrnoWarning(code, msg: "QThread::start: Thread termination error");
735 }
736#endif
737}
738
739bool QThread::wait(QDeadlineTimer deadline)
740{
741 Q_D(QThread);
742 QMutexLocker locker(&d->mutex);
743
744 if (from_HANDLE<pthread_t>(id: d->data->threadId.loadRelaxed()) == pthread_self()) {
745 qWarning(msg: "QThread::wait: Thread tried to wait on itself");
746 return false;
747 }
748
749 if (d->finished || !d->running)
750 return true;
751
752 while (d->running) {
753 if (!d->thread_done.wait(lockedMutex: locker.mutex(), deadline))
754 return false;
755 }
756 Q_ASSERT(d->data->threadId.loadRelaxed() == nullptr);
757
758 return true;
759}
760
761void 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(state: enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, oldstate: nullptr);
772 if (enabled)
773 pthread_testcancel();
774#endif
775}
776
777// Caller must lock the mutex
778void 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(target_thread: from_HANDLE<pthread_t>(id: data->threadId.loadRelaxed()), policy: &sched_policy, param: &param) != 0) {
789 // failed to get the scheduling policy, don't bother setting
790 // the priority
791 qWarning(msg: "QThread::setPriority: Cannot get scheduler parameters");
792 return;
793 }
794
795 int prio;
796 if (!calculateUnixPriority(priority, sched_policy: &sched_policy, sched_priority: &prio)) {
797 // failed to get the scheduling parameters, don't
798 // bother setting the priority
799 qWarning(msg: "QThread::setPriority: Cannot determine scheduler priority range");
800 return;
801 }
802
803 param.sched_priority = prio;
804 int status = pthread_setschedparam(target_thread: from_HANDLE<pthread_t>(id: data->threadId.loadRelaxed()), policy: sched_policy, param: &param);
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(target_thread: from_HANDLE<pthread_t>(id: data->threadId.loadRelaxed()), policy: &sched_policy, param: &param);
811 param.sched_priority = sched_get_priority_min(algorithm: sched_policy);
812 pthread_setschedparam(target_thread: from_HANDLE<pthread_t>(id: data->threadId.loadRelaxed()), policy: sched_policy, param: &param);
813 }
814# else
815 Q_UNUSED(status);
816# endif // SCHED_IDLE
817#endif
818}
819
820#endif // QT_CONFIG(thread)
821
822QT_END_NAMESPACE
823
824

source code of qtbase/src/corelib/thread/qthread_unix.cpp