8#include <private/qcoreapplication_p.h>
9#include <private/qcore_unix_p.h>
12#include <private/qtools_p.h>
15# include <private/qeventdispatcher_wasm_p.h>
17# include <private/qeventdispatcher_unix_p.h>
18# if defined(Q_OS_DARWIN)
19# include <private/qeventdispatcher_cf_p.h>
20# elif !defined(QT_NO_GLIB)
21# include <private/qeventdispatcher_glib_p.h>
32# include <pthread_np.h>
35#if defined(Q_OS_FREEBSD)
36# include <sys/cpuset.h>
37#elif defined(Q_OS_BSD4)
38# include <sys/sysctl.h>
49#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
53#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE
)
58#if defined(Q_OS_DARWIN) || !defined(Q_OS_ANDROID) && !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0
>= 0
)
59#define QT_HAS_THREAD_PRIORITY_SCHEDULING
63#include <sys/neutrino.h>
69Q_STATIC_LOGGING_CATEGORY(lcQThread,
"qt.core.thread", QtWarningMsg)
71using namespace QtMiscUtils;
75static_assert(
sizeof(pthread_t) <=
sizeof(Qt::HANDLE));
77enum { ThreadPriorityResetFlag = 0x80000000 };
97static constexpr bool UsingPThreadTimedJoin = QT_CONFIG(pthread_clockjoin)
98 || (QT_CONFIG(pthread_timedjoin) && QWaitConditionClockId == CLOCK_REALTIME);
99#if !QT_CONFIG(pthread_clockjoin)
100int pthread_clockjoin_np(...) {
return ENOSYS; }
102#if !QT_CONFIG(pthread_timedjoin)
103int pthread_timedjoin_np(...) {
return ENOSYS; }
106#if QT_CONFIG(broken_threadlocal_dtors)
128Q_CONSTINIT
static thread_local QThreadData *currentThreadData =
nullptr;
130static void destroy_current_thread_data(
void *p)
132 QThreadData *data =
static_cast<QThreadData *>(p);
133 QThread *thread = data->thread.loadAcquire();
135 if (data->isAdopted) {
139 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
141 if constexpr (!QT_CONFIG(broken_threadlocal_dtors))
143 }
else if constexpr (!QT_CONFIG(broken_threadlocal_dtors)) {
147 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
159 currentThreadData =
nullptr;
163static QThreadData *get_thread_data()
165 return currentThreadData;
168#if QT_CONFIG(broken_threadlocal_dtors)
171static void destroy_main_thread_data()
173 if (QThreadData *d = get_thread_data())
174 destroy_current_thread_data(d);
176Q_DESTRUCTOR_FUNCTION(destroy_main_thread_data)
179static void set_thread_data(QThreadData *data)
182 if constexpr (QT_CONFIG(broken_threadlocal_dtors)) {
183 static pthread_key_t tls_key;
185 TlsKey() { pthread_key_create(&tls_key, destroy_current_thread_data); }
186 ~TlsKey() { pthread_key_delete(tls_key); }
188 static TlsKey currentThreadCleanup;
189 pthread_setspecific(tls_key, data);
192 ~Cleanup() { destroy_current_thread_data(currentThreadData); }
194 static thread_local Cleanup currentThreadCleanup;
197 currentThreadData = data;
200static void clear_thread_data()
202 set_thread_data(
nullptr);
206static typename std::enable_if<std::is_integral_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
208 return reinterpret_cast<Qt::HANDLE>(
static_cast<intptr_t>(id));
212static typename std::enable_if<std::is_integral_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
214 return static_cast<T>(
reinterpret_cast<intptr_t>(id));
218static typename std::enable_if<std::is_pointer_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
224static typename std::enable_if<std::is_pointer_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
226 return static_cast<T>(id);
229void QThreadData::clearCurrentThreadData()
234QThreadData *QThreadData::current(
bool createIfNecessary)
236 QThreadData *data = get_thread_data();
237 if (!data && createIfNecessary) {
238 data =
new QThreadData;
240 set_thread_data(data);
241 data->thread.storeRelease(
new QAdoptedThread(data));
249 data->isAdopted =
true;
250 data->threadId.storeRelaxed(QThread::currentThreadId());
251 if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
252 auto *mainThread = data->thread.loadRelaxed();
253 mainThread->setObjectName(
"Qt mainThread");
254 QCoreApplicationPrivate::theMainThread.storeRelease(mainThread);
255 QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed());
262void QAdoptedThread::init()
267
268
271typedef void *(*QtThreadCallback)(
void *);
279#if defined(Q_OS_DARWIN)
281 int value = qEnvironmentVariableIntValue(
"QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
283 return new QEventDispatcherCoreFoundation;
285 return new QEventDispatcherUNIX;
286#elif defined(Q_OS_WASM)
287 return new QEventDispatcherWasm();
288#elif !defined(QT_NO_GLIB)
289 const bool isQtMainThread = data->thread.loadAcquire() == QCoreApplicationPrivate::mainThread();
290 if (qEnvironmentVariableIsEmpty(
"QT_NO_GLIB")
291 && (isQtMainThread || qEnvironmentVariableIsEmpty(
"QT_NO_THREADED_GLIB"))
292 && QEventDispatcherGlib::versionSupported())
293 return new QEventDispatcherGlib;
295 return new QEventDispatcherUNIX;
297 return new QEventDispatcherUNIX;
303#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX))
304static void setCurrentThreadName(
const char *name)
306# if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
307 prctl(PR_SET_NAME, (
unsigned long)name, 0, 0, 0);
308# elif defined(Q_OS_DARWIN)
309 pthread_setname_np(name);
310# elif defined(Q_OS_QNX)
311 pthread_setname_np(pthread_self(), name);
318void terminate_on_exception(T &&t)
320#ifndef QT_NO_EXCEPTIONS
323 std::forward<T>(t)();
324#ifndef QT_NO_EXCEPTIONS
329 }
catch (abi::__forced_unwind &) {
339void *QThreadPrivate::start(
void *arg)
341#ifdef PTHREAD_CANCEL_DISABLE
342 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
nullptr);
344 QThread *thr =
reinterpret_cast<QThread *>(arg);
345 QThreadData *data = QThreadData::get2(thr);
348 set_thread_data(data);
350 pthread_cleanup_push([](
void *arg) {
static_cast<QThread *>(arg)->d_func()->finish(); }, arg);
351 terminate_on_exception([&] {
353 QMutexLocker locker(&thr->d_func()->mutex);
356 if (thr->d_func()->priority & ThreadPriorityResetFlag) {
357 thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
360 if (thr->d_func()->serviceLevel != QThread::QualityOfService::Auto)
361 thr->d_func()->setQualityOfServiceLevel(thr->d_func()->serviceLevel);
365 Q_ASSERT(data->threadId.loadRelaxed() == QThread::currentThreadId());
368 data->quitNow = thr->d_func()->exited;
371 data->ensureEventDispatcher();
372 data->eventDispatcher.loadRelaxed()->startingUp();
374#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX))
379 if (Q_LIKELY(thr->d_func()->objectName.isEmpty()))
380 setCurrentThreadName(thr->metaObject()->className());
382 setCurrentThreadName(std::exchange(thr->d_func()->objectName, {}).toLocal8Bit());
386 emit thr->started(QThread::QPrivateSignal());
387#ifdef PTHREAD_CANCEL_DISABLE
388 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,
nullptr);
389 pthread_testcancel();
396 pthread_cleanup_pop(1);
400void QThreadPrivate::finish()
402 terminate_on_exception([&] {
403 QThreadPrivate *d =
this;
404 QThread *thr = q_func();
409#ifdef PTHREAD_CANCEL_DISABLE
410 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
nullptr);
413 QMutexLocker locker(&d->mutex);
415 d->threadState = QThreadPrivate::Finishing;
417 emit thr->finished(QThread::QPrivateSignal());
418 qCDebug(lcDeleteLater) <<
"Sending deferred delete events as part of finishing thread" << thr;
419 QCoreApplication::sendPostedEvents(
nullptr, QEvent::DeferredDelete);
421 void *data = &d->data->tls;
422 QThreadStorageData::finish((
void **)data);
425 if constexpr (QT_CONFIG(broken_threadlocal_dtors))
429void QThreadPrivate::cleanup()
431 terminate_on_exception([&] {
432 QThreadPrivate *d =
this;
436#ifdef PTHREAD_CANCEL_DISABLE
437 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
nullptr);
440 QMutexLocker locker(&d->mutex);
441 d->priority = QThread::InheritPriority;
443 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
444 if (eventDispatcher) {
445 d->data->eventDispatcher =
nullptr;
447 eventDispatcher->closingDown();
448 delete eventDispatcher;
452 d->interruptionRequested.store(
false, std::memory_order_relaxed);
460
461
464
465
466
467
468
469
470
471
472
473
474
475
476
477Qt::HANDLE QThread::currentThreadIdImpl()
noexcept
479 return to_HANDLE(pthread_self());
482#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
484# define _SC_NPROCESSORS_ONLN 84
488int QThreadPrivate::idealThreadCount = 1;
491int QThread::idealThreadCount()
noexcept
495#if defined(Q_OS_HPUX)
497 struct pst_dynamic psd;
498 if (pstat_getdynamic(&psd,
sizeof(psd), 1, 0) == -1) {
499 perror(
"pstat_getdynamic");
501 cores = (
int)psd.psd_proc_cnt;
503#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
504# if defined(Q_OS_FREEBSD) && !defined(CPU_COUNT_S)
505# define CPU_COUNT_S(setsize, cpusetp) ((int)BIT_COUNT(setsize, cpusetp))
507 using cpu_set_t = cpuset_t;
508 auto sched_getaffinity = [](pid_t, size_t cpusetsize, cpu_set_t *mask) {
509 return cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, cpusetsize, mask);
514 QVarLengthArray<cpu_set_t, 1> cpuset(1);
516 if (Q_UNLIKELY(sched_getaffinity(0,
sizeof(cpu_set_t), cpuset.data()) < 0)) {
517 for (size = 2; size <= 4; size *= 2) {
519 if (sched_getaffinity(0,
sizeof(cpu_set_t) * size, cpuset.data()) == 0)
525 cores = CPU_COUNT_S(
sizeof(cpu_set_t) * size, cpuset.data());
526#elif defined(Q_OS_BSD4)
528 size_t len =
sizeof(cores);
532 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
535#elif defined(Q_OS_INTEGRITY)
536#if (__INTEGRITY_MAJOR_VERSION >= 10
)
538 Value processorCount;
539 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
540 cores = processorCount;
545#elif defined(Q_OS_VXWORKS)
546 cpuset_t cpus = vxCpuEnabledGet();
550 for (
int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
551 if (CPUSET_ISSET(cpus, i)) {
556#elif defined(Q_OS_WASM)
557 cores = QThreadPrivate::idealThreadCount;
560 cores = (
int)sysconf(_SC_NPROCESSORS_ONLN);
567void QThread::yieldCurrentThread()
585 QT_EINTR_LOOP(r, nanosleep(&amount, &amount));
588void QThread::sleep(
unsigned long secs)
590 sleep(std::chrono::seconds{secs});
593void QThread::msleep(
unsigned long msecs)
595 sleep(std::chrono::milliseconds{msecs});
598void QThread::usleep(
unsigned long usecs)
600 sleep(std::chrono::microseconds{usecs});
603void QThread::sleep(std::chrono::nanoseconds nsec)
605 qt_nanosleep(durationToTimespec(nsec));
610#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
612static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
621 int priority_norm = 10;
624 struct _sched_info info;
625 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
628 if (priority == QThread::IdlePriority) {
629 *sched_priority = info.priority_min;
633 if (priority_norm < info.priority_min)
634 priority_norm = info.priority_min;
635 if (priority_norm > info.priority_priv)
636 priority_norm = info.priority_priv;
639 int from_min, from_max;
641 if (priority < QThread::NormalPriority) {
642 to_min = info.priority_min;
643 to_max = priority_norm;
644 from_min = QThread::LowestPriority;
645 from_max = QThread::NormalPriority;
647 to_min = priority_norm;
648 to_max = info.priority_priv;
649 from_min = QThread::NormalPriority;
650 from_max = QThread::TimeCriticalPriority;
653 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
654 prio = qBound(to_min, prio, to_max);
656 *sched_priority = prio;
663static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
666 if (priority == QThread::IdlePriority) {
667 *sched_policy = SCHED_IDLE;
671 const int lowestPriority = QThread::LowestPriority;
673 const int lowestPriority = QThread::IdlePriority;
675 const int highestPriority = QThread::TimeCriticalPriority;
679#if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM)
681 prio_min = SCHED_FIFO_LOW_PRI;
682 prio_max = SCHED_FIFO_HIGH_PRI;
684 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
687 prio_min = sched_get_priority_min(*sched_policy);
688 prio_max = sched_get_priority_max(*sched_policy);
691 if (prio_min == -1 || prio_max == -1)
696 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
697 prio = qMax(prio_min, qMin(prio_max, prio));
699 *sched_priority = prio;
705void QThread::start(Priority priority)
708 QMutexLocker locker(&d->mutex);
710 if (d->threadState == QThreadPrivate::Finishing)
711 d->wait(locker, QDeadlineTimer::Forever);
713 if (d->threadState == QThreadPrivate::Running)
716 d->threadState = QThreadPrivate::Running;
719 d->interruptionRequested.store(
false, std::memory_order_relaxed);
720 d->terminated =
false;
723 pthread_attr_init(&attr);
724 if constexpr (!UsingPThreadTimedJoin)
725 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
727 if (d->serviceLevel != QThread::QualityOfService::Auto)
728 pthread_attr_set_qos_class_np(&attr, d->nativeQualityOfServiceClass(), 0);
731 d->priority = priority;
733#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
735 case InheritPriority:
737 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
744 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
747 qWarning(
"QThread::start: Cannot determine default scheduler policy");
752 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
755 qWarning(
"QThread::start: Cannot determine scheduler priority range");
760 sp.sched_priority = prio;
762 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
763 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
764 || pthread_attr_setschedparam(&attr, &sp) != 0) {
767 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
768 d->priority = qToUnderlying(priority) | ThreadPriorityResetFlag;
776 if (d->stackSize > 0) {
777#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0
> 0
)
778 int code = pthread_attr_setstacksize(&attr, d->stackSize);
784 qErrnoWarning(code,
"QThread::start: Thread stack size error");
788 d->threadState = QThreadPrivate::NotStarted;
794 if (Q_LIKELY(objectName().isEmpty()))
795 pthread_attr_setthreadname(&attr, metaObject()->className());
797 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
800 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
805 int code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
809#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
810 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
812 code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
814 d->data->threadId.storeRelaxed(to_HANDLE(threadId));
816 pthread_attr_destroy(&attr);
819 qErrnoWarning(code,
"QThread::start: Thread creation error");
821 d->threadState = QThreadPrivate::NotStarted;
822 d->data->threadId.storeRelaxed(
nullptr);
826void QThread::terminate()
828#if !defined(Q_OS_ANDROID)
830 QMutexLocker locker(&d->mutex);
832 const auto id = d->data->threadId.loadRelaxed();
839 d->terminated =
true;
841 const bool selfCancelling = d->data == get_thread_data();
842 if (selfCancelling) {
850 if (
int code = pthread_cancel(from_HANDLE<pthread_t>(id))) {
853 d->terminated =
false;
854 qErrnoWarning(code,
"QThread::start: Thread termination error");
859static void wakeAllInternal(QThreadPrivate *d)
861 d->threadState = QThreadPrivate::Finished;
863 d->thread_done.wakeAll();
866inline void QThreadPrivate::wakeAll()
868 if (data->isAdopted || !UsingPThreadTimedJoin)
869 wakeAllInternal(
this);
872bool QThread::wait(QDeadlineTimer deadline)
875 QMutexLocker locker(&d->mutex);
877 if (d->threadState == QThreadPrivate::NotStarted)
879 if (d->threadState == QThreadPrivate::Finished)
882 if (isCurrentThread()) {
883 qWarning(
"QThread::wait: Thread tried to wait on itself");
887 return d->wait(locker, deadline);
890bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
892 constexpr int HasJoinerBit =
int(0x8000'0000);
893 struct timespec ts, *pts =
nullptr;
894 if (!deadline.isForever()) {
895 ts = deadlineToAbstime(deadline);
903 QMutexLocker<QMutex> *locker;
904 int joinResult = ETIMEDOUT;
905 static void run(
void *arg) {
static_cast<CancelState *>(arg)->run(); }
909 if (joinResult == ETIMEDOUT && d->waiters)
910 d->thread_done.wakeOne();
911 else if (joinResult == 0)
913 d->waiters &= ~HasJoinerBit;
915 } nocancel = {
this, &locker };
916 int &r = nocancel.joinResult;
919 waiters |= HasJoinerBit;
922 pthread_cleanup_push(&CancelState::run, &nocancel);
923 pthread_t thrId = from_HANDLE<pthread_t>(data->threadId.loadRelaxed());
924 if constexpr (QT_CONFIG(pthread_clockjoin))
925 r = pthread_clockjoin_np(thrId,
nullptr, SteadyClockClockId, pts);
927 r = pthread_timedjoin_np(thrId,
nullptr, pts);
928 Q_ASSERT(r == 0 || r == ETIMEDOUT);
929 pthread_cleanup_pop(1);
931 Q_ASSERT(waiters >= 0);
932 return r != ETIMEDOUT;
934 Q_ASSERT(threadState != QThreadPrivate::Finished);
935 Q_ASSERT(locker.isLocked());
941 bool mustJoin = (waiters & HasJoinerBit) == 0;
942 pthread_cleanup_push([](
void *ptr) {
943 --(*
static_cast<
decltype(waiters) *>(ptr));
946 if (UsingPThreadTimedJoin && mustJoin && !data->isAdopted) {
950 if (!thread_done.wait(locker.mutex(), deadline))
952 result = threadState == QThreadPrivate::Finished;
955 mustJoin = (waiters & HasJoinerBit) == 0;
957 pthread_cleanup_pop(1);
962void QThread::setTerminationEnabled(
bool enabled)
964 QThread *thr = currentThread();
965 Q_ASSERT_X(thr !=
nullptr,
"QThread::setTerminationEnabled()",
966 "Current thread was not started with QThread.");
969#if defined(Q_OS_ANDROID)
972 pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE,
nullptr);
974 pthread_testcancel();
979void QThreadPrivate::setPriority(QThread::Priority threadPriority)
981 priority = threadPriority;
985#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
989 if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m) != 0) {
992 qWarning(
"QThread::setPriority: Cannot get scheduler parameters");
997 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
1000 qWarning(
"QThread::setPriority: Cannot determine scheduler priority range");
1004 param.sched_priority = prio;
1005 int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1009 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
1011 pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m);
1012 param.sched_priority = sched_get_priority_min(sched_policy);
1013 pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1021void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
1025 serviceLevel = qosLevel;
1027 qCDebug(lcQThread) <<
"Setting thread QoS class to" << serviceLevel <<
"for thread" << q;
1028 pthread_set_qos_class_self_np(nativeQualityOfServiceClass(), 0);
1033qos_class_t QThreadPrivate::nativeQualityOfServiceClass()
const
1042 switch (serviceLevel) {
1043 case QThread::QualityOfService::Auto:
1044 return QOS_CLASS_DEFAULT;
1045 case QThread::QualityOfService::High:
1046 return QOS_CLASS_USER_INTERACTIVE;
1047 case QThread::QualityOfService::Eco:
1048 return QOS_CLASS_UTILITY;
1050 Q_UNREACHABLE_RETURN(QOS_CLASS_DEFAULT);
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
Combined button and popup list for selecting options.
static void qt_nanosleep(timespec amount)