9#include <private/qcoreapplication_p.h>
10#include <private/qcore_unix_p.h>
14#include <private/qtools_p.h>
17# include <private/qeventdispatcher_wasm_p.h>
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>
30# include <pthread_np.h>
33#if defined(Q_OS_FREEBSD)
34# include <sys/cpuset.h>
35#elif defined(Q_OS_BSD4)
36# include <sys/sysctl.h>
47#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
51#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE
)
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
61#include <sys/neutrino.h>
69using namespace QtMiscUtils;
73static_assert(
sizeof(pthread_t) <=
sizeof(Qt::HANDLE));
75enum { ThreadPriorityResetFlag = 0x80000000 };
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; }
100#if !QT_CONFIG(pthread_timedjoin)
101int pthread_timedjoin_np(...) {
return ENOSYS; }
104#if QT_CONFIG(broken_threadlocal_dtors)
151Q_CONSTINIT
static thread_local QThreadData *currentThreadData =
nullptr;
153static void destroy_current_thread_data(QThreadData *data)
155 QThread *thread = data->thread.loadAcquire();
160 currentThreadData = data;
163 if (data->isAdopted) {
167 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
169 if constexpr (!QT_CONFIG(broken_threadlocal_dtors))
171 }
else if constexpr (!QT_CONFIG(broken_threadlocal_dtors)) {
175 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
183static void deref_current_thread_data(QThreadData *data)
190 currentThreadData =
nullptr;
193static void destroy_auxiliary_thread_data(
void *p)
195 auto data =
static_cast<QThreadData *>(p);
196 destroy_current_thread_data(data);
197 deref_current_thread_data(data);
201static QThreadData *get_thread_data()
203 return currentThreadData;
207struct QThreadDataDestroyer
210 QThreadDataDestroyer()
noexcept
212 pthread_key_create(&key, &destroy_auxiliary_thread_data);
214 ~QThreadDataDestroyer()
217 if (QThreadData *data = get_thread_data())
218 deref_current_thread_data(data);
219 pthread_key_delete(key);
222 struct EarlyMainThread {
223 EarlyMainThread() { QThreadStoragePrivate::init(); }
227 if (QThreadData *data = get_thread_data())
228 destroy_current_thread_data(data);
233#if QT_SUPPORTS_INIT_PRIORITY
234Q_DECL_INIT_PRIORITY(10)
236static QThreadDataDestroyer threadDataDestroyer;
238static void set_thread_data(QThreadData *data)
noexcept
244 static QThreadDataDestroyer::EarlyMainThread currentThreadCleanup;
245 pthread_setspecific(threadDataDestroyer.key, data);
247 currentThreadData = data;
251static typename std::enable_if<std::is_integral_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
253 return reinterpret_cast<Qt::HANDLE>(
static_cast<intptr_t>(id));
257static typename std::enable_if<std::is_integral_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
259 return static_cast<T>(
reinterpret_cast<intptr_t>(id));
263static typename std::enable_if<std::is_pointer_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
269static typename std::enable_if<std::is_pointer_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
271 return static_cast<T>(id);
274void QThreadData::clearCurrentThreadData()
276 set_thread_data(
nullptr);
279QThreadData *QThreadData::currentThreadData()
noexcept
281 return get_thread_data();
284QThreadData *QThreadData::createCurrentThreadData()
286 Q_ASSERT(!currentThreadData());
287 std::unique_ptr data = std::make_unique<QThreadData>();
291 set_thread_data(data.get());
294 data->thread.storeRelease(
new QAdoptedThread(data.get()));
296 clearCurrentThreadData();
299 return data.release();
302void QAdoptedThread::init()
307
308
311typedef void *(*QtThreadCallback)(
void *);
319#if defined(Q_OS_DARWIN)
321 int value = qEnvironmentVariableIntValue(
"QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
323 return new QEventDispatcherCoreFoundation;
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;
335 return new QEventDispatcherUNIX;
337 return new QEventDispatcherUNIX;
343template <
typename String>
344static void setCurrentThreadName(QThread *thr, String &objectName)
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);
359 if (Q_LIKELY(objectName.isEmpty()))
360 setit(thr->metaObject()->className());
362 setit(std::exchange(objectName, {}).toLocal8Bit());
400static void setCancellationEnabled(
bool enable)
402#ifdef PTHREAD_CANCEL_DISABLE
405 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,
nullptr);
406 pthread_testcancel();
409 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
nullptr);
416void *QThreadPrivate::start(
void *arg)
418 setCancellationEnabled(
false);
420 QThread *thr =
reinterpret_cast<QThread *>(arg);
421 QThreadData *data = QThreadData::get2(thr);
424 set_thread_data(data);
427 data->reuseBindingStatusForNewNativeThread();
429 pthread_cleanup_push([](
void *arg) {
static_cast<QThread *>(arg)->d_func()->finish(); }, arg);
435 QMutexLocker locker(&thr->d_func()->mutex);
438 if (thr->d_func()->priority & ThreadPriorityResetFlag) {
439 thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
443 Q_ASSERT(data->threadId.loadRelaxed() == QThread::currentThreadId());
446 data->quitNow = thr->d_func()->exited;
452 setCurrentThreadName(thr, thr->d_func()->objectName);
459 setCancellationEnabled(
true);
461 data->ensureEventDispatcher();
462 data->eventDispatcher.loadRelaxed()->startingUp();
464 emit thr->started(QThread::QPrivateSignal());
471 pthread_cleanup_pop(1);
475void QThreadPrivate::finish()
477 QThreadPrivate *d =
this;
478 QThread *thr = q_func();
483 setCancellationEnabled(
false);
485 QMutexLocker locker(&d->mutex);
487 d->threadState = QThreadPrivate::Finishing;
489 emit thr->finished(QThread::QPrivateSignal());
490 QCoreApplication::sendPostedEvents(
nullptr, QEvent::DeferredDelete);
492 QThreadStoragePrivate::finish(&d->data->tls);
494 if constexpr (QT_CONFIG(broken_threadlocal_dtors))
498void QThreadPrivate::cleanup()
500 QThreadPrivate *d =
this;
504 setCancellationEnabled(
false);
506 QMutexLocker locker(&d->mutex);
507 d->priority = QThread::InheritPriority;
509 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
510 if (eventDispatcher) {
511 d->data->eventDispatcher =
nullptr;
513 eventDispatcher->closingDown();
514 delete eventDispatcher;
518 d->interruptionRequested.store(
false, std::memory_order_relaxed);
525
526
529
530
531
532
533
534
535
536
537
538
539
540
541
542Qt::HANDLE QThread::currentThreadIdImpl()
noexcept
544 return to_HANDLE(pthread_self());
547#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
549# define _SC_NPROCESSORS_ONLN 84
553int QThreadPrivate::idealThreadCount = 1;
556#if QT_CONFIG(trivial_auto_var_init_pattern) && defined(Q_CC_GNU_ONLY)
559__attribute__((optimize(
"trivial-auto-var-init=uninitialized")))
561int QThread::idealThreadCount()
noexcept
565#if defined(Q_OS_HPUX)
567 struct pst_dynamic psd;
568 if (pstat_getdynamic(&psd,
sizeof(psd), 1, 0) == -1) {
569 perror(
"pstat_getdynamic");
571 cores = (
int)psd.psd_proc_cnt;
573#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
575# if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1800
576 QT_WARNING_DISABLE_CLANG(
"-Wvla-cxx-extension")
580 constexpr qsizetype MaxCpuCount = 1024 * 1024;
581 constexpr qsizetype MaxCpuSetArraySize = MaxCpuCount /
sizeof(cpu_set_t) / 8;
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);
590 }
while (size < MaxCpuSetArraySize);
592#elif defined(Q_OS_BSD4)
594 size_t len =
sizeof(cores);
598 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
601#elif defined(Q_OS_INTEGRITY)
602#if (__INTEGRITY_MAJOR_VERSION >= 10
)
604 Value processorCount;
605 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
606 cores = processorCount;
611#elif defined(Q_OS_VXWORKS)
612 cpuset_t cpus = vxCpuEnabledGet();
616 for (
int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
617 if (CPUSET_ISSET(cpus, i)) {
622#elif defined(Q_OS_WASM)
623 cores = QThreadPrivate::idealThreadCount;
626 cores = (
int)sysconf(_SC_NPROCESSORS_ONLN);
633void QThread::yieldCurrentThread()
651 QT_EINTR_LOOP(r, nanosleep(&amount, &amount));
654void QThread::sleep(
unsigned long secs)
656 sleep(std::chrono::seconds{secs});
659void QThread::msleep(
unsigned long msecs)
661 sleep(std::chrono::milliseconds{msecs});
664void QThread::usleep(
unsigned long usecs)
666 sleep(std::chrono::microseconds{usecs});
669void QThread::sleep(std::chrono::nanoseconds nsec)
671 qt_nanosleep(durationToTimespec(nsec));
676#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
678static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
687 int priority_norm = 10;
690 struct _sched_info info;
691 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
694 if (priority == QThread::IdlePriority) {
695 *sched_priority = info.priority_min;
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;
705 int from_min, from_max;
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;
713 to_min = priority_norm;
714 to_max = info.priority_priv;
715 from_min = QThread::NormalPriority;
716 from_max = QThread::TimeCriticalPriority;
719 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
720 prio = qBound(to_min, prio, to_max);
722 *sched_priority = prio;
729static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
732 if (priority == QThread::IdlePriority) {
733 *sched_policy = SCHED_IDLE;
737 const int lowestPriority = QThread::LowestPriority;
739 const int lowestPriority = QThread::IdlePriority;
741 const int highestPriority = QThread::TimeCriticalPriority;
745#if defined(Q_OS_VXWORKS)
747 prio_min = SCHED_FIFO_LOW_PRI;
748 prio_max = SCHED_FIFO_HIGH_PRI;
750 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
753 prio_min = sched_get_priority_min(*sched_policy);
754 prio_max = sched_get_priority_max(*sched_policy);
757 if (prio_min == -1 || prio_max == -1)
762 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
763 prio = qMax(prio_min, qMin(prio_max, prio));
765 *sched_priority = prio;
771void QThread::start(Priority priority)
774 QMutexLocker locker(&d->mutex);
776 if (d->threadState == QThreadPrivate::Finishing)
777 d->wait(locker, QDeadlineTimer::Forever);
779 if (d->threadState == QThreadPrivate::Running)
782 d->threadState = QThreadPrivate::Running;
785 d->interruptionRequested.store(
false, std::memory_order_relaxed);
786 d->terminated =
false;
789 pthread_attr_init(&attr);
790 if constexpr (!UsingPThreadTimedJoin)
791 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
792 if (d->serviceLevel != QThread::QualityOfService::Auto) {
794 pthread_attr_set_qos_class_np(&attr, d->nativeQualityOfServiceClass(), 0);
801 d->priority = priority;
803#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
805 case InheritPriority:
807 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
814 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
817 qWarning(
"QThread::start: Cannot determine default scheduler policy");
822 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
825 qWarning(
"QThread::start: Cannot determine scheduler priority range");
830 sp.sched_priority = prio;
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) {
837 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
838 d->priority = qToUnderlying(priority) | ThreadPriorityResetFlag;
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);
854 qErrnoWarning(code,
"QThread::start: Thread stack size error");
858 d->threadState = QThreadPrivate::NotStarted;
864 if (Q_LIKELY(objectName().isEmpty()))
865 pthread_attr_setthreadname(&attr, metaObject()->className());
867 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
870 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
875 int code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
879#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
880 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
882 code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
884 d->data->threadId.storeRelaxed(to_HANDLE(threadId));
886 pthread_attr_destroy(&attr);
889 qErrnoWarning(code,
"QThread::start: Thread creation error");
891 d->threadState = QThreadPrivate::NotStarted;
892 d->data->threadId.storeRelaxed(
nullptr);
896void QThread::terminate()
898#if !defined(Q_OS_ANDROID)
900 QMutexLocker locker(&d->mutex);
902 const auto id = d->data->threadId.loadRelaxed();
909 d->terminated =
true;
911 const bool selfCancelling = d->data == get_thread_data();
912 if (selfCancelling) {
920 if (
int code = pthread_cancel(from_HANDLE<pthread_t>(id))) {
923 d->terminated =
false;
924 qErrnoWarning(code,
"QThread::start: Thread termination error");
929static void wakeAllInternal(QThreadPrivate *d)
931 d->threadState = QThreadPrivate::Finished;
933 d->thread_done.wakeAll();
936inline void QThreadPrivate::wakeAll()
938 if (data->isAdopted || !UsingPThreadTimedJoin)
939 wakeAllInternal(
this);
942bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
944 constexpr int HasJoinerBit =
int(0x8000'0000);
945 struct timespec ts, *pts =
nullptr;
946 if (!deadline.isForever()) {
947 ts = deadlineToAbstime(deadline);
955 QMutexLocker<QMutex> *locker;
956 int joinResult = ETIMEDOUT;
957 static void run(
void *arg) {
static_cast<CancelState *>(arg)->run(); }
961 if (joinResult == ETIMEDOUT && d->waiters)
962 d->thread_done.wakeOne();
963 else if (joinResult == 0)
965 d->waiters &= ~HasJoinerBit;
967 } nocancel = {
this, &locker };
968 int &r = nocancel.joinResult;
971 waiters |= HasJoinerBit;
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);
979 r = pthread_timedjoin_np(thrId,
nullptr, pts);
980 Q_ASSERT(r == 0 || r == ETIMEDOUT);
981 pthread_cleanup_pop(1);
983 Q_ASSERT(waiters >= 0);
984 return r != ETIMEDOUT;
986 Q_ASSERT(threadState != QThreadPrivate::Finished);
987 Q_ASSERT(locker.isLocked());
993 bool mustJoin = (waiters & HasJoinerBit) == 0;
994 pthread_cleanup_push([](
void *ptr) {
995 --(*
static_cast<
decltype(waiters) *>(ptr));
998 if (UsingPThreadTimedJoin && mustJoin && !data->isAdopted) {
1002 if (!thread_done.wait(locker.mutex(), deadline))
1004 result = threadState == QThreadPrivate::Finished;
1007 mustJoin = (waiters & HasJoinerBit) == 0;
1009 pthread_cleanup_pop(1);
1014void QThread::setTerminationEnabled(
bool enabled)
1016 QThread *thr = currentThread();
1017 Q_ASSERT_X(thr !=
nullptr,
"QThread::setTerminationEnabled()",
1018 "Current thread was not started with QThread.");
1021 setCancellationEnabled(enabled);
1025void QThreadPrivate::setPriority(QThread::Priority threadPriority)
1027 priority = threadPriority;
1031#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
1035 if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m) != 0) {
1038 qWarning(
"QThread::setPriority: Cannot get scheduler parameters");
1043 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
1046 qWarning(
"QThread::setPriority: Cannot determine scheduler priority range");
1050 param.sched_priority = prio;
1051 int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1055 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
1057 pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m);
1058 param.sched_priority = sched_get_priority_min(sched_policy);
1059 pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1067void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
1071 serviceLevel = qosLevel;
1073 qCDebug(lcQThread) <<
"Setting thread QoS class to" << serviceLevel <<
"for thread" << q;
1074 pthread_set_qos_class_self_np(nativeQualityOfServiceClass(), 0);
1079qos_class_t QThreadPrivate::nativeQualityOfServiceClass()
const
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;
1096 Q_UNREACHABLE_RETURN(QOS_CLASS_DEFAULT);
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
Combined button and popup list for selecting options.
#define Q_STATIC_LOGGING_CATEGORY(name,...)
static void qt_nanosleep(timespec amount)