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