Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qthread_unix.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qthread.h"
6#include "qthread_p.h"
7
8#include <private/qcoreapplication_p.h>
9#include <private/qcore_unix_p.h>
10#include "qdebug.h"
11#include "qthreadstorage.h"
12#include <private/qtools_p.h>
13
14#if defined(Q_OS_WASM)
15# include <private/qeventdispatcher_wasm_p.h>
16#else
17# include <private/qeventdispatcher_unix_p.h>
18# if defined(Q_OS_DARWIN)
19# include <private/qeventdispatcher_cf_p.h>
20# elif !defined(QT_NO_GLIB)
21# include <private/qeventdispatcher_glib_p.h>
22# endif
23#endif
24
25#ifdef __GLIBCXX__
26#include <cxxabi.h>
27#endif
28
29#include <sched.h>
30#include <errno.h>
31#if __has_include(<pthread_np.h>)
32# include <pthread_np.h>
33#endif
34
35#if defined(Q_OS_FREEBSD)
36# include <sys/cpuset.h>
37#elif defined(Q_OS_BSD4)
38# include <sys/sysctl.h>
39#endif
40#ifdef Q_OS_VXWORKS
41# include <vxCpuLib.h>
42# include <cpuset.h>
43#endif
44
45#ifdef Q_OS_HPUX
46#include <sys/pstat.h>
47#endif
48
49#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
50#include <sys/prctl.h>
51#endif
52
53#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE)
54// from linux/sched.h
55# define SCHED_IDLE 5
56#endif
57
58#if defined(Q_OS_DARWIN) || !defined(Q_OS_ANDROID) && !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
59#define QT_HAS_THREAD_PRIORITY_SCHEDULING
60#endif
61
62#if defined(Q_OS_QNX)
63#include <sys/neutrino.h>
64#endif
65
67
68[[maybe_unused]]
69Q_STATIC_LOGGING_CATEGORY(lcQThread, "qt.core.thread", QtWarningMsg)
70
71using namespace QtMiscUtils;
72
73#if QT_CONFIG(thread)
74
75static_assert(sizeof(pthread_t) <= sizeof(Qt::HANDLE));
76
77enum { ThreadPriorityResetFlag = 0x80000000 };
78
79// If we have a way to perform a timed pthread_join(), we will do it if its
80// clock is not worse than the one QWaitCondition is using. This ensures that
81// QThread::wait() only returns after pthread_join() or equivalent has
82// returned, ensuring that the thread has definitely exited.
83//
84// Because only one thread can call this family of functions at a time, we
85// count how many threads are waiting and all but one of them wait on a
86// QWaitCondition, with the joining thread having the responsibility for waking
87// up all others when the joining concludes. If the joining times out, the
88// thread in charge wakes up one of the other waiters (if there's any) to
89// assume responsibility for joining.
90//
91// If we don't have a way to perform timed pthread_join(), then we don't try
92// joining a all. All waiting threads will wait for the launched thread to
93// call QWaitCondition::wakeAll(). Note in this case it is possible for the
94// waiting threads to conclude the launched thread has exited before it has.
95//
96// To support this scenario, we start the thread in detached state.
97static constexpr bool UsingPThreadTimedJoin = QT_CONFIG(pthread_clockjoin)
98 || (QT_CONFIG(pthread_timedjoin) && QWaitConditionClockId == CLOCK_REALTIME);
99#if !QT_CONFIG(pthread_clockjoin)
100int pthread_clockjoin_np(...) { return ENOSYS; } // pretend
101#endif
102#if !QT_CONFIG(pthread_timedjoin)
103int pthread_timedjoin_np(...) { return ENOSYS; } // pretend
104#endif
105
106#if QT_CONFIG(broken_threadlocal_dtors)
107// On most modern platforms, the C runtime has a helper function that helps the
108// C++ runtime run the thread_local non-trivial destructors when threads exit
109// and that code ensures that they are run in the correct order on program exit
110// too ([basic.start.term]/2: "The destruction of all constructed objects with
111// thread storage duration within that thread strongly happens before
112// destroying any object with static storage duration."). In the absence of
113// this function, the ordering can be wrong depending on when the first
114// non-trivial thread_local object was created relative to other statics.
115// Moreover, this can be racy and having our own thread_local early in
116// QThreadPrivate::start() made it even more so. See QTBUG-129846 for analysis.
117//
118// For the platforms where this C++11 feature is not properly implemented yet,
119// we fall back to a pthread_setspecific() call and do not perform late
120// clean-up, because then the order of registration of those pthread_specific_t
121// keys matters and Glib uses them too.
122//
123// https://gcc.gnu.org/git/?p=gcc.git;a=blob;f=libstdc%2B%2B-v3/libsupc%2B%2B/atexit_thread.cc;hb=releases/gcc-14.2.0#l133
124// https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/libcxxabi/src/cxa_thread_atexit.cpp#L118-L120
125#endif // QT_CONFIG(broken_threadlocal_dtors)
126
127// Always access this through the {get,set,clear}_thread_data() functions.
128Q_CONSTINIT static thread_local QThreadData *currentThreadData = nullptr;
129
130static void destroy_current_thread_data(void *p)
131{
132 QThreadData *data = static_cast<QThreadData *>(p);
133 QThread *thread = data->thread.loadAcquire();
134
135 if (data->isAdopted) {
136 // If this is an adopted thread, then QThreadData owns the QThread and
137 // this is very likely the last reference. These pointers cannot be
138 // null and there is no race.
139 QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
140 thread_p->finish();
141 if constexpr (!QT_CONFIG(broken_threadlocal_dtors))
142 thread_p->cleanup();
143 } else if constexpr (!QT_CONFIG(broken_threadlocal_dtors)) {
144 // We may be racing the QThread destructor in another thread. With
145 // two-phase clean-up enabled, there's also no race because it will
146 // stop in a call to QThread::wait() until we call cleanup().
147 QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
148 thread_p->cleanup();
149 } else {
150 // We may be racing the QThread destructor in another thread and it may
151 // have begun destruction; we must not dereference the QThread pointer.
152 }
153
154 // the QThread object may still have a reference, so this may not delete
155 data->deref();
156
157 // ... but we must reset it to zero before returning so we aren't
158 // leaving a dangling pointer.
159 currentThreadData = nullptr;
160}
161
162// Utility functions for getting, setting and clearing thread specific data.
163static QThreadData *get_thread_data()
164{
165 return currentThreadData;
166}
167
168#if QT_CONFIG(broken_threadlocal_dtors)
169// The destructors registered with pthread_key_create() below are NOT run from
170// exit(), so we must also use atexit().
171static void destroy_main_thread_data()
172{
173 if (QThreadData *d = get_thread_data())
174 destroy_current_thread_data(d);
175}
176Q_DESTRUCTOR_FUNCTION(destroy_main_thread_data)
177#endif
178
179static void set_thread_data(QThreadData *data)
180{
181 if (data) {
182 if constexpr (QT_CONFIG(broken_threadlocal_dtors)) {
183 static pthread_key_t tls_key;
184 struct TlsKey {
185 TlsKey() { pthread_key_create(&tls_key, destroy_current_thread_data); }
186 ~TlsKey() { pthread_key_delete(tls_key); }
187 };
188 static TlsKey currentThreadCleanup;
189 pthread_setspecific(tls_key, data);
190 } else {
191 struct Cleanup {
192 ~Cleanup() { destroy_current_thread_data(currentThreadData); }
193 };
194 static thread_local Cleanup currentThreadCleanup;
195 }
196 }
197 currentThreadData = data;
198}
199
200static void clear_thread_data()
201{
202 set_thread_data(nullptr);
203}
204
205template <typename T>
206static typename std::enable_if<std::is_integral_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
207{
208 return reinterpret_cast<Qt::HANDLE>(static_cast<intptr_t>(id));
209}
210
211template <typename T>
212static typename std::enable_if<std::is_integral_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
213{
214 return static_cast<T>(reinterpret_cast<intptr_t>(id));
215}
216
217template <typename T>
218static typename std::enable_if<std::is_pointer_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
219{
220 return id;
221}
222
223template <typename T>
224static typename std::enable_if<std::is_pointer_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
225{
226 return static_cast<T>(id);
227}
228
229void QThreadData::clearCurrentThreadData()
230{
231 clear_thread_data();
232}
233
234QThreadData *QThreadData::current(bool createIfNecessary)
235{
236 QThreadData *data = get_thread_data();
237 if (!data && createIfNecessary) {
238 data = new QThreadData;
239 QT_TRY {
240 set_thread_data(data);
241 data->thread.storeRelease(new QAdoptedThread(data));
242 } QT_CATCH(...) {
243 clear_thread_data();
244 data->deref();
245 data = nullptr;
246 QT_RETHROW;
247 }
248 data->deref();
249 data->isAdopted = true;
250 data->threadId.storeRelaxed(QThread::currentThreadId());
251 if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
252 auto *mainThread = data->thread.loadRelaxed();
253 mainThread->setObjectName("Qt mainThread");
254 QCoreApplicationPrivate::theMainThread.storeRelease(mainThread);
255 QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed());
256 }
257 }
258 return data;
259}
260
261
262void QAdoptedThread::init()
263{
264}
265
266/*
267 QThreadPrivate
268*/
269
270extern "C" {
271typedef void *(*QtThreadCallback)(void *);
272}
273
274#endif // QT_CONFIG(thread)
275
276QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *data)
277{
278 Q_UNUSED(data);
279#if defined(Q_OS_DARWIN)
280 bool ok = false;
281 int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
282 if (ok && value > 0)
283 return new QEventDispatcherCoreFoundation;
284 else
285 return new QEventDispatcherUNIX;
286#elif defined(Q_OS_WASM)
287 return new QEventDispatcherWasm();
288#elif !defined(QT_NO_GLIB)
289 const bool isQtMainThread = data->thread.loadAcquire() == QCoreApplicationPrivate::mainThread();
290 if (qEnvironmentVariableIsEmpty("QT_NO_GLIB")
291 && (isQtMainThread || qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB"))
292 && QEventDispatcherGlib::versionSupported())
293 return new QEventDispatcherGlib;
294 else
295 return new QEventDispatcherUNIX;
296#else
297 return new QEventDispatcherUNIX;
298#endif
299}
300
301#if QT_CONFIG(thread)
302
303#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX))
304static void setCurrentThreadName(const char *name)
305{
306# if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
307 prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
308# elif defined(Q_OS_DARWIN)
309 pthread_setname_np(name);
310# elif defined(Q_OS_QNX)
311 pthread_setname_np(pthread_self(), name);
312# endif
313}
314#endif
315
316namespace {
317template <typename T>
318void terminate_on_exception(T &&t)
319{
320#ifndef QT_NO_EXCEPTIONS
321 try {
322#endif
323 std::forward<T>(t)();
324#ifndef QT_NO_EXCEPTIONS
325#ifdef __GLIBCXX__
326 // POSIX thread cancellation under glibc is implemented by throwing an exception
327 // of this type. Do what libstdc++ is doing and handle it specially in order not to
328 // abort the application if user's code calls a cancellation function.
329 } catch (abi::__forced_unwind &) {
330 throw;
331#endif // __GLIBCXX__
332 } catch (...) {
333 qTerminate();
334 }
335#endif // QT_NO_EXCEPTIONS
336}
337} // unnamed namespace
338
339void *QThreadPrivate::start(void *arg)
340{
341#ifdef PTHREAD_CANCEL_DISABLE
342 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
343#endif
344 QThread *thr = reinterpret_cast<QThread *>(arg);
345 QThreadData *data = QThreadData::get2(thr);
346
347 // this ensures the thread-local is created as early as possible
348 set_thread_data(data);
349
350 pthread_cleanup_push([](void *arg) { static_cast<QThread *>(arg)->d_func()->finish(); }, arg);
351 terminate_on_exception([&] {
352 {
353 QMutexLocker locker(&thr->d_func()->mutex);
354
355 // do we need to reset the thread priority?
356 if (thr->d_func()->priority & ThreadPriorityResetFlag) {
357 thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
358 }
359#ifndef Q_OS_DARWIN // For Darwin we set it as an attribute when starting the thread
360 if (thr->d_func()->serviceLevel != QThread::QualityOfService::Auto)
361 thr->d_func()->setQualityOfServiceLevel(thr->d_func()->serviceLevel);
362#endif
363
364 // threadId is set in QThread::start()
365 Q_ASSERT(data->threadId.loadRelaxed() == QThread::currentThreadId());
366
367 data->ref();
368 data->quitNow = thr->d_func()->exited;
369 }
370
371 data->ensureEventDispatcher();
372 data->eventDispatcher.loadRelaxed()->startingUp();
373
374#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX))
375 {
376 // Sets the name of the current thread. We can only do this
377 // when the thread is starting, as we don't have a cross
378 // platform way of setting the name of an arbitrary thread.
379 if (Q_LIKELY(thr->d_func()->objectName.isEmpty()))
380 setCurrentThreadName(thr->metaObject()->className());
381 else
382 setCurrentThreadName(std::exchange(thr->d_func()->objectName, {}).toLocal8Bit());
383 }
384#endif
385
386 emit thr->started(QThread::QPrivateSignal());
387#ifdef PTHREAD_CANCEL_DISABLE
388 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr);
389 pthread_testcancel();
390#endif
391 thr->run();
392 });
393
394 // This calls finish(); later, the currentThreadCleanup thread-local
395 // destructor will call cleanup().
396 pthread_cleanup_pop(1);
397 return nullptr;
398}
399
400void QThreadPrivate::finish()
401{
402 terminate_on_exception([&] {
403 QThreadPrivate *d = this;
404 QThread *thr = q_func();
405
406 // Disable cancellation; we're already in the finishing touches of this
407 // thread, and we don't want cleanup to be disturbed by
408 // abi::__forced_unwind being thrown from all kinds of functions.
409#ifdef PTHREAD_CANCEL_DISABLE
410 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
411#endif
412
413 QMutexLocker locker(&d->mutex);
414
415 d->threadState = QThreadPrivate::Finishing;
416 locker.unlock();
417 emit thr->finished(QThread::QPrivateSignal());
418 qCDebug(lcDeleteLater) << "Sending deferred delete events as part of finishing thread" << thr;
419 QCoreApplication::sendPostedEvents(nullptr, QEvent::DeferredDelete);
420
421 void *data = &d->data->tls;
422 QThreadStorageData::finish((void **)data);
423 });
424
425 if constexpr (QT_CONFIG(broken_threadlocal_dtors))
426 cleanup();
427}
428
429void QThreadPrivate::cleanup()
430{
431 terminate_on_exception([&] {
432 QThreadPrivate *d = this;
433
434 // Disable cancellation again: we did it above, but some user code
435 // running between finish() and cleanup() may have turned them back on.
436#ifdef PTHREAD_CANCEL_DISABLE
437 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
438#endif
439
440 QMutexLocker locker(&d->mutex);
441 d->priority = QThread::InheritPriority;
442
443 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
444 if (eventDispatcher) {
445 d->data->eventDispatcher = nullptr;
446 locker.unlock();
447 eventDispatcher->closingDown();
448 delete eventDispatcher;
449 locker.relock();
450 }
451
452 d->interruptionRequested.store(false, std::memory_order_relaxed);
453
454 d->wakeAll();
455 });
456}
457
458
459/**************************************************************************
460 ** QThread
461 *************************************************************************/
462
463/*
464 CI tests fails on ARM architectures if we try to use the assembler, so
465 stick to the pthread version there. The assembler would be
466
467 // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344k/Babeihid.html
468 asm volatile ("mrc p15, 0, %0, c13, c0, 3" : "=r" (tid));
469
470 and
471
472 // see glibc/sysdeps/aarch64/nptl/tls.h
473 asm volatile ("mrs %0, tpidr_el0" : "=r" (tid));
474
475 for 32 and 64bit versions, respectively.
476*/
477Qt::HANDLE QThread::currentThreadIdImpl() noexcept
478{
479 return to_HANDLE(pthread_self());
480}
481
482#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
483// LSB doesn't define _SC_NPROCESSORS_ONLN.
484# define _SC_NPROCESSORS_ONLN 84
485#endif
486
487#ifdef Q_OS_WASM
488int QThreadPrivate::idealThreadCount = 1;
489#endif
490
491int QThread::idealThreadCount() noexcept
492{
493 int cores = 1;
494
495#if defined(Q_OS_HPUX)
496 // HP-UX
497 struct pst_dynamic psd;
498 if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
499 perror("pstat_getdynamic");
500 } else {
501 cores = (int)psd.psd_proc_cnt;
502 }
503#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
504# if defined(Q_OS_FREEBSD) && !defined(CPU_COUNT_S)
505# define CPU_COUNT_S(setsize, cpusetp) ((int)BIT_COUNT(setsize, cpusetp))
506 // match the Linux API for simplicity
507 using cpu_set_t = cpuset_t;
508 auto sched_getaffinity = [](pid_t, size_t cpusetsize, cpu_set_t *mask) {
509 return cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, cpusetsize, mask);
510 };
511# endif
512
513 // get the number of threads we're assigned, not the total in the system
514 QVarLengthArray<cpu_set_t, 1> cpuset(1);
515 int size = 1;
516 if (Q_UNLIKELY(sched_getaffinity(0, sizeof(cpu_set_t), cpuset.data()) < 0)) {
517 for (size = 2; size <= 4; size *= 2) {
518 cpuset.resize(size);
519 if (sched_getaffinity(0, sizeof(cpu_set_t) * size, cpuset.data()) == 0)
520 break;
521 }
522 if (size > 4)
523 return 1;
524 }
525 cores = CPU_COUNT_S(sizeof(cpu_set_t) * size, cpuset.data());
526#elif defined(Q_OS_BSD4)
527 // OpenBSD, NetBSD, BSD/OS, Darwin (macOS, iOS, etc.)
528 size_t len = sizeof(cores);
529 int mib[2];
530 mib[0] = CTL_HW;
531 mib[1] = HW_NCPU;
532 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
533 perror("sysctl");
534 }
535#elif defined(Q_OS_INTEGRITY)
536#if (__INTEGRITY_MAJOR_VERSION >= 10)
537 // Integrity V10+ does support multicore CPUs
538 Value processorCount;
539 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
540 cores = processorCount;
541 else
542#endif
543 // as of aug 2008 Integrity only supports one single core CPU
544 cores = 1;
545#elif defined(Q_OS_VXWORKS)
546 cpuset_t cpus = vxCpuEnabledGet();
547 cores = 0;
548
549 // 128 cores should be enough for everyone ;)
550 for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
551 if (CPUSET_ISSET(cpus, i)) {
552 CPUSET_CLR(cpus, i);
553 cores++;
554 }
555 }
556#elif defined(Q_OS_WASM)
557 cores = QThreadPrivate::idealThreadCount;
558#else
559 // the rest: Solaris, AIX, Tru64
560 cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
561 if (cores == -1)
562 return 1;
563#endif
564 return cores;
565}
566
567void QThread::yieldCurrentThread()
568{
569 sched_yield();
570}
571
572#endif // QT_CONFIG(thread)
573
574static void qt_nanosleep(timespec amount)
575{
576 // We'd like to use clock_nanosleep.
577 //
578 // But clock_nanosleep is from POSIX.1-2001 and both are *not*
579 // affected by clock changes when using relative sleeps, even for
580 // CLOCK_REALTIME.
581 //
582 // nanosleep is POSIX.1-1993
583
584 int r;
585 QT_EINTR_LOOP(r, nanosleep(&amount, &amount));
586}
587
588void QThread::sleep(unsigned long secs)
589{
590 sleep(std::chrono::seconds{secs});
591}
592
593void QThread::msleep(unsigned long msecs)
594{
595 sleep(std::chrono::milliseconds{msecs});
596}
597
598void QThread::usleep(unsigned long usecs)
599{
600 sleep(std::chrono::microseconds{usecs});
601}
602
603void QThread::sleep(std::chrono::nanoseconds nsec)
604{
605 qt_nanosleep(durationToTimespec(nsec));
606}
607
608#if QT_CONFIG(thread)
609
610#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
611#if defined(Q_OS_QNX)
612static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
613{
614 // On QNX, NormalPriority is mapped to 10. A QNX system could use a value different
615 // than 10 for the "normal" priority but it's difficult to achieve this so we'll
616 // assume that no one has ever created such a system. This makes the mapping from
617 // Qt priorities to QNX priorities lopsided. There's usually more space available
618 // to map into above the "normal" priority than below it. QNX also has a privileged
619 // priority range (for threads that assist the kernel). We'll assume that no Qt
620 // thread needs to use priorities in that range.
621 int priority_norm = 10;
622 // _sched_info::priority_priv isn't documented. You'd think that it's the start of the
623 // privileged priority range but it's actually the end of the unpriviledged range.
624 struct _sched_info info;
625 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
626 return false;
627
628 if (priority == QThread::IdlePriority) {
629 *sched_priority = info.priority_min;
630 return true;
631 }
632
633 if (priority_norm < info.priority_min)
634 priority_norm = info.priority_min;
635 if (priority_norm > info.priority_priv)
636 priority_norm = info.priority_priv;
637
638 int to_min, to_max;
639 int from_min, from_max;
640 int prio;
641 if (priority < QThread::NormalPriority) {
642 to_min = info.priority_min;
643 to_max = priority_norm;
644 from_min = QThread::LowestPriority;
645 from_max = QThread::NormalPriority;
646 } else {
647 to_min = priority_norm;
648 to_max = info.priority_priv;
649 from_min = QThread::NormalPriority;
650 from_max = QThread::TimeCriticalPriority;
651 }
652
653 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
654 prio = qBound(to_min, prio, to_max);
655
656 *sched_priority = prio;
657 return true;
658}
659#else
660// Does some magic and calculate the Unix scheduler priorities
661// sched_policy is IN/OUT: it must be set to a valid policy before calling this function
662// sched_priority is OUT only
663static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
664{
665#ifdef SCHED_IDLE
666 if (priority == QThread::IdlePriority) {
667 *sched_policy = SCHED_IDLE;
668 *sched_priority = 0;
669 return true;
670 }
671 const int lowestPriority = QThread::LowestPriority;
672#else
673 const int lowestPriority = QThread::IdlePriority;
674#endif
675 const int highestPriority = QThread::TimeCriticalPriority;
676
677 int prio_min;
678 int prio_max;
679#if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM)
680 // for other scheduling policies than SCHED_RR or SCHED_FIFO
681 prio_min = SCHED_FIFO_LOW_PRI;
682 prio_max = SCHED_FIFO_HIGH_PRI;
683
684 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
685#endif
686 {
687 prio_min = sched_get_priority_min(*sched_policy);
688 prio_max = sched_get_priority_max(*sched_policy);
689 }
690
691 if (prio_min == -1 || prio_max == -1)
692 return false;
693
694 int prio;
695 // crudely scale our priority enum values to the prio_min/prio_max
696 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
697 prio = qMax(prio_min, qMin(prio_max, prio));
698
699 *sched_priority = prio;
700 return true;
701}
702#endif
703#endif
704
705void QThread::start(Priority priority)
706{
707 Q_D(QThread);
708 QMutexLocker locker(&d->mutex);
709
710 if (d->threadState == QThreadPrivate::Finishing)
711 d->wait(locker, QDeadlineTimer::Forever);
712
713 if (d->threadState == QThreadPrivate::Running)
714 return;
715
716 d->threadState = QThreadPrivate::Running;
717 d->returnCode = 0;
718 d->exited = false;
719 d->interruptionRequested.store(false, std::memory_order_relaxed);
720 d->terminated = false;
721
722 pthread_attr_t attr;
723 pthread_attr_init(&attr);
724 if constexpr (!UsingPThreadTimedJoin)
725 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
726#ifdef Q_OS_DARWIN
727 if (d->serviceLevel != QThread::QualityOfService::Auto)
728 pthread_attr_set_qos_class_np(&attr, d->nativeQualityOfServiceClass(), 0);
729#endif
730
731 d->priority = priority;
732
733#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
734 switch (priority) {
735 case InheritPriority:
736 {
737 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
738 break;
739 }
740
741 default:
742 {
743 int sched_policy;
744 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
745 // failed to get the scheduling policy, don't bother
746 // setting the priority
747 qWarning("QThread::start: Cannot determine default scheduler policy");
748 break;
749 }
750
751 int prio;
752 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
753 // failed to get the scheduling parameters, don't
754 // bother setting the priority
755 qWarning("QThread::start: Cannot determine scheduler priority range");
756 break;
757 }
758
759 sched_param sp;
760 sp.sched_priority = prio;
761
762 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
763 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
764 || pthread_attr_setschedparam(&attr, &sp) != 0) {
765 // could not set scheduling hints, fallback to inheriting them
766 // we'll try again from inside the thread
767 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
768 d->priority = qToUnderlying(priority) | ThreadPriorityResetFlag;
769 }
770 break;
771 }
772 }
773#endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
774
775
776 if (d->stackSize > 0) {
777#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
778 int code = pthread_attr_setstacksize(&attr, d->stackSize);
779#else
780 int code = ENOSYS; // stack size not supported, automatically fail
781#endif // _POSIX_THREAD_ATTR_STACKSIZE
782
783 if (code) {
784 qErrnoWarning(code, "QThread::start: Thread stack size error");
785
786 // we failed to set the stacksize, and as the documentation states,
787 // the thread will fail to run...
788 d->threadState = QThreadPrivate::NotStarted;
789 return;
790 }
791 }
792
793#ifdef Q_OS_INTEGRITY
794 if (Q_LIKELY(objectName().isEmpty()))
795 pthread_attr_setthreadname(&attr, metaObject()->className());
796 else
797 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
798#else
799 // avoid interacting with the binding system
800 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
801 : QString();
802#endif
803
804 pthread_t threadId;
805 int code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
806 if (code == EPERM) {
807 // caller does not have permission to set the scheduling
808 // parameters/policy
809#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
810 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
811#endif
812 code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
813 }
814 d->data->threadId.storeRelaxed(to_HANDLE(threadId));
815
816 pthread_attr_destroy(&attr);
817
818 if (code) {
819 qErrnoWarning(code, "QThread::start: Thread creation error");
820
821 d->threadState = QThreadPrivate::NotStarted;
822 d->data->threadId.storeRelaxed(nullptr);
823 }
824}
825
826void QThread::terminate()
827{
828#if !defined(Q_OS_ANDROID)
829 Q_D(QThread);
830 QMutexLocker locker(&d->mutex);
831
832 const auto id = d->data->threadId.loadRelaxed();
833 if (!id)
834 return;
835
836 if (d->terminated) // don't try again, avoids killing the wrong thread on threadId reuse (ABA)
837 return;
838
839 d->terminated = true;
840
841 const bool selfCancelling = d->data == get_thread_data();
842 if (selfCancelling) {
843 // Posix doesn't seem to specify whether the stack of cancelled threads
844 // is unwound, and there's nothing preventing a QThread from
845 // terminate()ing itself, so drop the mutex before calling
846 // pthread_cancel():
847 locker.unlock();
848 }
849
850 if (int code = pthread_cancel(from_HANDLE<pthread_t>(id))) {
851 if (selfCancelling)
852 locker.relock();
853 d->terminated = false; // allow to try again
854 qErrnoWarning(code, "QThread::start: Thread termination error");
855 }
856#endif
857}
858
859static void wakeAllInternal(QThreadPrivate *d)
860{
861 d->threadState = QThreadPrivate::Finished;
862 if (d->waiters)
863 d->thread_done.wakeAll();
864}
865
866inline void QThreadPrivate::wakeAll()
867{
868 if (data->isAdopted || !UsingPThreadTimedJoin)
869 wakeAllInternal(this);
870}
871
872bool QThread::wait(QDeadlineTimer deadline)
873{
874 Q_D(QThread);
875 QMutexLocker locker(&d->mutex);
876
877 if (d->threadState == QThreadPrivate::NotStarted)
878 return true;
879 if (d->threadState == QThreadPrivate::Finished)
880 return true;
881
882 if (isCurrentThread()) {
883 qWarning("QThread::wait: Thread tried to wait on itself");
884 return false;
885 }
886
887 return d->wait(locker, deadline);
888}
889
890bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
891{
892 constexpr int HasJoinerBit = int(0x8000'0000); // a.k.a. sign bit
893 struct timespec ts, *pts = nullptr;
894 if (!deadline.isForever()) {
895 ts = deadlineToAbstime(deadline);
896 pts = &ts;
897 }
898
899 auto doJoin = [&] {
900 // pthread_join() & family are cancellation points
901 struct CancelState {
902 QThreadPrivate *d;
903 QMutexLocker<QMutex> *locker;
904 int joinResult = ETIMEDOUT;
905 static void run(void *arg) { static_cast<CancelState *>(arg)->run(); }
906 void run()
907 {
908 locker->relock();
909 if (joinResult == ETIMEDOUT && d->waiters)
910 d->thread_done.wakeOne();
911 else if (joinResult == 0)
912 wakeAllInternal(d);
913 d->waiters &= ~HasJoinerBit;
914 }
915 } nocancel = { this, &locker };
916 int &r = nocancel.joinResult;
917
918 // we're going to perform the join, so don't let other threads do it
919 waiters |= HasJoinerBit;
920 locker.unlock();
921
922 pthread_cleanup_push(&CancelState::run, &nocancel);
923 pthread_t thrId = from_HANDLE<pthread_t>(data->threadId.loadRelaxed());
924 if constexpr (QT_CONFIG(pthread_clockjoin))
925 r = pthread_clockjoin_np(thrId, nullptr, SteadyClockClockId, pts);
926 else
927 r = pthread_timedjoin_np(thrId, nullptr, pts);
928 Q_ASSERT(r == 0 || r == ETIMEDOUT);
929 pthread_cleanup_pop(1);
930
931 Q_ASSERT(waiters >= 0);
932 return r != ETIMEDOUT;
933 };
934 Q_ASSERT(threadState != QThreadPrivate::Finished);
935 Q_ASSERT(locker.isLocked());
936
937 bool result = false;
938
939 // both branches call cancellation points
940 ++waiters;
941 bool mustJoin = (waiters & HasJoinerBit) == 0;
942 pthread_cleanup_push([](void *ptr) {
943 --(*static_cast<decltype(waiters) *>(ptr));
944 }, &waiters);
945 for (;;) {
946 if (UsingPThreadTimedJoin && mustJoin && !data->isAdopted) {
947 result = doJoin();
948 break;
949 }
950 if (!thread_done.wait(locker.mutex(), deadline))
951 break; // timed out
952 result = threadState == QThreadPrivate::Finished;
953 if (result)
954 break; // success
955 mustJoin = (waiters & HasJoinerBit) == 0;
956 }
957 pthread_cleanup_pop(1);
958
959 return result;
960}
961
962void QThread::setTerminationEnabled(bool enabled)
963{
964 QThread *thr = currentThread();
965 Q_ASSERT_X(thr != nullptr, "QThread::setTerminationEnabled()",
966 "Current thread was not started with QThread.");
967
968 Q_UNUSED(thr);
969#if defined(Q_OS_ANDROID)
970 Q_UNUSED(enabled);
971#else
972 pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, nullptr);
973 if (enabled)
974 pthread_testcancel();
975#endif
976}
977
978// Caller must lock the mutex
979void QThreadPrivate::setPriority(QThread::Priority threadPriority)
980{
981 priority = threadPriority;
982
983 // copied from start() with a few modifications:
984
985#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
986 int sched_policy;
987 sched_param param;
988
989 if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, &param) != 0) {
990 // failed to get the scheduling policy, don't bother setting
991 // the priority
992 qWarning("QThread::setPriority: Cannot get scheduler parameters");
993 return;
994 }
995
996 int prio;
997 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
998 // failed to get the scheduling parameters, don't
999 // bother setting the priority
1000 qWarning("QThread::setPriority: Cannot determine scheduler priority range");
1001 return;
1002 }
1003
1004 param.sched_priority = prio;
1005 int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, &param);
1006
1007# ifdef SCHED_IDLE
1008 // were we trying to set to idle priority and failed?
1009 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
1010 // reset to lowest priority possible
1011 pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, &param);
1012 param.sched_priority = sched_get_priority_min(sched_policy);
1013 pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, &param);
1014 }
1015# else
1016 Q_UNUSED(status);
1017# endif // SCHED_IDLE
1018#endif
1019}
1020
1021void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
1022{
1023 [[maybe_unused]]
1024 Q_Q(QThread);
1025 serviceLevel = qosLevel;
1026#ifdef Q_OS_DARWIN
1027 qCDebug(lcQThread) << "Setting thread QoS class to" << serviceLevel << "for thread" << q;
1028 pthread_set_qos_class_self_np(nativeQualityOfServiceClass(), 0);
1029#endif
1030}
1031
1032#ifdef Q_OS_DARWIN
1033qos_class_t QThreadPrivate::nativeQualityOfServiceClass() const
1034{
1035 // @note Consult table[0] to see what the levels mean
1036 // [0] https://developer.apple.com/library/archive/documentation/Performance/Conceptual/power_efficiency_guidelines_osx/PrioritizeWorkAtTheTaskLevel.html#//apple_ref/doc/uid/TP40013929-CH35-SW5
1037 // There are more levels but they have two other documented ones,
1038 // QOS_CLASS_BACKGROUND, which is below UTILITY, but has no guarantees
1039 // for scheduling (ie. the OS could choose to never give it CPU time),
1040 // and QOS_CLASS_USER_INITIATED, documented as being intended for
1041 // user-initiated actions, such as loading a text document.
1042 switch (serviceLevel) {
1043 case QThread::QualityOfService::Auto:
1044 return QOS_CLASS_DEFAULT;
1045 case QThread::QualityOfService::High:
1046 return QOS_CLASS_USER_INTERACTIVE;
1047 case QThread::QualityOfService::Eco:
1048 return QOS_CLASS_UTILITY;
1049 }
1050 Q_UNREACHABLE_RETURN(QOS_CLASS_DEFAULT);
1051}
1052#endif
1053
1054#endif // QT_CONFIG(thread)
1055
1056QT_END_NAMESPACE
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
Combined button and popup list for selecting options.
#define __has_include(x)
static void qt_nanosleep(timespec amount)