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