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