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