9#include <private/qcoreapplication_p.h>
10#include <private/qcore_unix_p.h>
13#include <private/qtools_p.h>
16# include <private/qeventdispatcher_wasm_p.h>
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>
29# include <pthread_np.h>
32#if defined(Q_OS_FREEBSD)
33# include <sys/cpuset.h>
34#elif defined(Q_OS_BSD4)
35# include <sys/sysctl.h>
46#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
50#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE
)
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
60#include <sys/neutrino.h>
63#if defined(Q_OS_HARMONY)
66# undef PTHREAD_CANCEL_DISABLE
74using namespace QtMiscUtils;
78static_assert(
sizeof(pthread_t) <=
sizeof(Qt::HANDLE));
80enum { ThreadPriorityResetFlag = 0x80000000 };
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; }
105#if !QT_CONFIG(pthread_timedjoin)
106int pthread_timedjoin_np(...) {
return ENOSYS; }
109#if QT_CONFIG(broken_threadlocal_dtors)
156Q_CONSTINIT
static thread_local QThreadData *currentThreadData =
nullptr;
158static void destroy_current_thread_data(QThreadData *data,
bool calledFromExit)
160 QThread *thread = data->thread.loadAcquire();
165 currentThreadData = data;
168 if (data->isAdopted) {
172 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
173 thread_p->finish(calledFromExit);
174 if constexpr (!QT_CONFIG(broken_threadlocal_dtors))
176 }
else if constexpr (!QT_CONFIG(broken_threadlocal_dtors)) {
180 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
188static void deref_current_thread_data(QThreadData *data)
195 currentThreadData =
nullptr;
198static void destroy_auxiliary_thread_data(
void *p)
200 auto data =
static_cast<QThreadData *>(p);
201 destroy_current_thread_data(data,
false);
202 deref_current_thread_data(data);
206static QThreadData *get_thread_data()
208 return currentThreadData;
212struct QThreadDataDestroyer
215 QThreadDataDestroyer()
noexcept
217 pthread_key_create(&key, &destroy_auxiliary_thread_data);
219 ~QThreadDataDestroyer()
222 if (QThreadData *data = get_thread_data())
223 deref_current_thread_data(data);
224 pthread_key_delete(key);
227 struct EarlyMainThread {
228 EarlyMainThread() { QThreadStoragePrivate::init(); }
232 if (QThreadData *data = get_thread_data())
233 destroy_current_thread_data(data,
true);
238#if QT_SUPPORTS_INIT_PRIORITY
239Q_DECL_INIT_PRIORITY(10)
241static QThreadDataDestroyer threadDataDestroyer;
243static void set_thread_data(QThreadData *data)
noexcept
249 static QThreadDataDestroyer::EarlyMainThread currentThreadCleanup;
250 pthread_setspecific(threadDataDestroyer.key, data);
252 currentThreadData = data;
256static typename std::enable_if<std::is_integral_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
258 return reinterpret_cast<Qt::HANDLE>(
static_cast<intptr_t>(id));
262static typename std::enable_if<std::is_integral_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
264 return static_cast<T>(
reinterpret_cast<intptr_t>(id));
268static typename std::enable_if<std::is_pointer_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
274static typename std::enable_if<std::is_pointer_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
276 return static_cast<T>(id);
279void QThreadData::clearCurrentThreadData()
281 set_thread_data(
nullptr);
284QThreadData *QThreadData::currentThreadData()
noexcept
286 return get_thread_data();
289QThreadData *QThreadData::createCurrentThreadData()
291 Q_ASSERT(!currentThreadData());
293 QThreadData *data =
new QThreadData();
297 set_thread_data(data);
300 data->thread.storeRelease(
new QAdoptedThread(data));
302 deref_current_thread_data(data);
308void QAdoptedThread::init()
313
314
317typedef void *(*QtThreadCallback)(
void *);
325#if defined(Q_OS_DARWIN)
327 int value = qEnvironmentVariableIntValue(
"QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
329 return new QEventDispatcherCoreFoundation;
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;
341 return new QEventDispatcherUNIX;
343 return new QEventDispatcherUNIX;
349template <
typename String>
350static void setCurrentThreadName(QThread *thr, String &objectName)
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)
366 qstrncpy(vxName, name,
sizeof(vxName));
367 pthread_setname_np(pthread_self(), vxName);
372 if (Q_LIKELY(objectName.isEmpty()))
373 setit(thr->metaObject()->className());
375 setit(std::exchange(objectName, {}).toLocal8Bit());
413static void setCancellationEnabled(
bool enable)
415#ifdef PTHREAD_CANCEL_DISABLE
418 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,
nullptr);
419 pthread_testcancel();
422 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
nullptr);
429void *QThreadPrivate::start(
void *arg)
431 setCancellationEnabled(
false);
433 QThread *thr =
reinterpret_cast<QThread *>(arg);
434 QThreadData *data = QThreadData::get2(thr);
437 set_thread_data(data);
440 data->reuseBindingStatusForNewNativeThread();
442 pthread_cleanup_push([](
void *arg) {
static_cast<QThread *>(arg)->d_func()->finish(); }, arg);
448 QMutexLocker locker(&thr->d_func()->mutex);
451 if (thr->d_func()->priority & ThreadPriorityResetFlag) {
452 thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
456 Q_ASSERT(data->threadId.loadRelaxed() == QThread::currentThreadId());
459 data->quitNow = thr->d_func()->exited;
465 setCurrentThreadName(thr, thr->d_func()->objectName);
472 setCancellationEnabled(
true);
474 data->ensureEventDispatcher();
475 data->eventDispatcher.loadRelaxed()->startingUp();
477 emit thr->started(QThread::QPrivateSignal());
484 pthread_cleanup_pop(1);
488void QThreadPrivate::finish(
bool calledFromExit)
490 QThreadPrivate *d =
this;
491 QThread *thr = q_func();
496 setCancellationEnabled(
false);
498 QMutexLocker locker(&d->mutex);
500 d->threadState = QThreadPrivate::Finishing;
502 emit thr->finished(QThread::QPrivateSignal());
503 QCoreApplication::sendPostedEvents(
nullptr, QEvent::DeferredDelete);
505 QThreadStoragePrivate::finish(&d->data->tls, calledFromExit);
507 if constexpr (QT_CONFIG(broken_threadlocal_dtors))
511void QThreadPrivate::cleanup()
513 QThreadPrivate *d =
this;
517 setCancellationEnabled(
false);
519 QMutexLocker locker(&d->mutex);
520 d->priority = QThread::InheritPriority;
522 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
523 if (eventDispatcher) {
524 d->data->eventDispatcher =
nullptr;
526 eventDispatcher->closingDown();
527 delete eventDispatcher;
531 d->interruptionRequested.store(
false, std::memory_order_relaxed);
538
539
542
543
544
545
546
547
548
549
550
551
552
553
554
555Qt::HANDLE QThread::currentThreadIdImpl()
noexcept
557 return to_HANDLE(pthread_self());
560#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
562# define _SC_NPROCESSORS_ONLN 84
566int QThreadPrivate::idealThreadCount = 1;
569#if QT_CONFIG(trivial_auto_var_init_pattern) && defined(Q_CC_GNU_ONLY)
572__attribute__((optimize(
"trivial-auto-var-init=uninitialized")))
574int QThread::idealThreadCount()
noexcept
578#if defined(Q_OS_HPUX)
580 struct pst_dynamic psd;
581 if (pstat_getdynamic(&psd,
sizeof(psd), 1, 0) == -1) {
582 perror(
"pstat_getdynamic");
584 cores = (
int)psd.psd_proc_cnt;
586#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
588# if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1800
589 QT_WARNING_DISABLE_CLANG(
"-Wvla-cxx-extension")
593 constexpr qsizetype MaxCpuCount = 1024 * 1024;
594 constexpr qsizetype MaxCpuSetArraySize = MaxCpuCount /
sizeof(cpu_set_t) / 8;
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);
603 }
while (size < MaxCpuSetArraySize);
605#elif defined(Q_OS_BSD4)
607 size_t len =
sizeof(cores);
611 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
614#elif defined(Q_OS_INTEGRITY)
615#if (__INTEGRITY_MAJOR_VERSION >= 10
)
617 Value processorCount;
618 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
619 cores = processorCount;
624#elif defined(Q_OS_VXWORKS)
625 cpuset_t cpus = vxCpuEnabledGet();
629 for (
int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
630 if (CPUSET_ISSET(cpus, i)) {
635#elif defined(Q_OS_WASM)
636 cores = QThreadPrivate::idealThreadCount;
639 cores = (
int)sysconf(_SC_NPROCESSORS_ONLN);
646void QThread::yieldCurrentThread()
664 QT_EINTR_LOOP(r, nanosleep(&amount, &amount));
667void QThread::sleep(
unsigned long secs)
669 sleep(std::chrono::seconds{secs});
672void QThread::msleep(
unsigned long msecs)
674 sleep(std::chrono::milliseconds{msecs});
677void QThread::usleep(
unsigned long usecs)
679 sleep(std::chrono::microseconds{usecs});
682void QThread::sleep(std::chrono::nanoseconds nsec)
684 qt_nanosleep(durationToTimespec(nsec));
689#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
691static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
700 int priority_norm = 10;
703 struct _sched_info info;
704 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
707 if (priority == QThread::IdlePriority) {
708 *sched_priority = info.priority_min;
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;
718 int from_min, from_max;
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;
726 to_min = priority_norm;
727 to_max = info.priority_priv;
728 from_min = QThread::NormalPriority;
729 from_max = QThread::TimeCriticalPriority;
732 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
733 prio = qBound(to_min, prio, to_max);
735 *sched_priority = prio;
742static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
745 if (priority == QThread::IdlePriority) {
746 *sched_policy = SCHED_IDLE;
750 const int lowestPriority = QThread::LowestPriority;
752 const int lowestPriority = QThread::IdlePriority;
754 const int highestPriority = QThread::TimeCriticalPriority;
758#if defined(Q_OS_VXWORKS)
760 prio_min = SCHED_FIFO_LOW_PRI;
761 prio_max = SCHED_FIFO_HIGH_PRI;
763 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
766 prio_min = sched_get_priority_min(*sched_policy);
767 prio_max = sched_get_priority_max(*sched_policy);
770 if (prio_min == -1 || prio_max == -1)
775 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
776 prio = qMax(prio_min, qMin(prio_max, prio));
778 *sched_priority = prio;
784void QThread::start(Priority priority)
787 QMutexLocker locker(&d->mutex);
789 if (d->threadState == QThreadPrivate::Finishing)
790 d->wait(locker, QDeadlineTimer::Forever);
792 if (d->threadState == QThreadPrivate::Running)
795 d->threadState = QThreadPrivate::Running;
798 d->interruptionRequested.store(
false, std::memory_order_relaxed);
799 d->terminated =
false;
802 pthread_attr_init(&attr);
803 if constexpr (!UsingPThreadTimedJoin)
804 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
805 if (d->serviceLevel != QThread::QualityOfService::Auto) {
807 pthread_attr_set_qos_class_np(&attr, d->nativeQualityOfServiceClass(), 0);
814 d->priority = priority;
816#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
818 case InheritPriority:
820 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
827 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
830 qWarning(
"QThread::start: Cannot determine default scheduler policy");
835 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
838 qWarning(
"QThread::start: Cannot determine scheduler priority range");
843 sp.sched_priority = prio;
845 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
846 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
847 || pthread_attr_setschedparam(&attr, &sp) != 0) {
850 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
851 d->priority = qToUnderlying(priority) | ThreadPriorityResetFlag;
859 if (d->stackSize > 0) {
860#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0
> 0
)
861 int code = pthread_attr_setstacksize(&attr, d->stackSize);
867 qErrnoWarning(code,
"QThread::start: Thread stack size error");
871 d->threadState = QThreadPrivate::NotStarted;
877 if (Q_LIKELY(objectName().isEmpty()))
878 pthread_attr_setthreadname(&attr, metaObject()->className());
880 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
883 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
888 int code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
892#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
893 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
895 code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
897 d->data->threadId.storeRelaxed(to_HANDLE(threadId));
899 pthread_attr_destroy(&attr);
902 qErrnoWarning(code,
"QThread::start: Thread creation error");
904 d->threadState = QThreadPrivate::NotStarted;
905 d->data->threadId.storeRelaxed(
nullptr);
909void QThread::terminate()
911#if !defined(Q_OS_ANDROID) && !defined(Q_OS_HARMONY)
913 QMutexLocker locker(&d->mutex);
915 const auto id = d->data->threadId.loadRelaxed();
922 d->terminated =
true;
924 const bool selfCancelling = d->data == get_thread_data();
925 if (selfCancelling) {
933 if (
int code = pthread_cancel(from_HANDLE<pthread_t>(id))) {
936 d->terminated =
false;
937 qErrnoWarning(code,
"QThread::start: Thread termination error");
942static void wakeAllInternal(QThreadPrivate *d)
944 d->threadState = QThreadPrivate::Finished;
946 d->thread_done.wakeAll();
949inline void QThreadPrivate::wakeAll()
951 if (data->isAdopted || !UsingPThreadTimedJoin)
952 wakeAllInternal(
this);
955bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
957 constexpr int HasJoinerBit =
int(0x8000'0000);
958 struct timespec ts, *pts =
nullptr;
959 if (!deadline.isForever()) {
960 ts = deadlineToAbstime(deadline);
968 QMutexLocker<QMutex> *locker;
969 int joinResult = ETIMEDOUT;
970 static void run(
void *arg) {
static_cast<CancelState *>(arg)->run(); }
974 if (joinResult == ETIMEDOUT && d->waiters)
975 d->thread_done.wakeOne();
976 else if (joinResult == 0)
978 d->waiters &= ~HasJoinerBit;
980 } nocancel = {
this, &locker };
981 int &r = nocancel.joinResult;
984 waiters |= HasJoinerBit;
987 pthread_cleanup_push(&CancelState::run, &nocancel);
988 pthread_t thrId = from_HANDLE<pthread_t>(data->threadId.loadRelaxed());
989 if constexpr (QT_CONFIG(pthread_clockjoin))
990 r = pthread_clockjoin_np(thrId,
nullptr, QSteadyClockClockId, pts);
992 r = pthread_timedjoin_np(thrId,
nullptr, pts);
993 Q_ASSERT(r == 0 || r == ETIMEDOUT);
994 pthread_cleanup_pop(1);
996 Q_ASSERT(waiters >= 0);
997 return r != ETIMEDOUT;
999 Q_ASSERT(threadState != QThreadPrivate::Finished);
1000 Q_ASSERT(locker.isLocked());
1002 bool result =
false;
1006 bool mustJoin = (waiters & HasJoinerBit) == 0;
1007 pthread_cleanup_push([](
void *ptr) {
1008 --(*
static_cast<
decltype(waiters) *>(ptr));
1011 if (UsingPThreadTimedJoin && mustJoin && !data->isAdopted) {
1015 if (!thread_done.wait(locker.mutex(), deadline))
1017 result = threadState == QThreadPrivate::Finished;
1020 mustJoin = (waiters & HasJoinerBit) == 0;
1022 pthread_cleanup_pop(1);
1027void QThread::setTerminationEnabled(
bool enabled)
1029 QThread *thr = currentThread();
1030 Q_ASSERT_X(thr !=
nullptr,
"QThread::setTerminationEnabled()",
1031 "Current thread was not started with QThread.");
1034 setCancellationEnabled(enabled);
1038void QThreadPrivate::setPriority(QThread::Priority threadPriority)
1040 priority = threadPriority;
1044#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
1048 if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m) != 0) {
1051 qWarning(
"QThread::setPriority: Cannot get scheduler parameters");
1056 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
1059 qWarning(
"QThread::setPriority: Cannot determine scheduler priority range");
1063 param.sched_priority = prio;
1064 int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1068 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
1070 pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m);
1071 param.sched_priority = sched_get_priority_min(sched_policy);
1072 pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1080void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
1084 serviceLevel = qosLevel;
1086 qCDebug(lcQThread) <<
"Setting thread QoS class to" << serviceLevel <<
"for thread" << q;
1087 pthread_set_qos_class_self_np(nativeQualityOfServiceClass(), 0);
1092qos_class_t QThreadPrivate::nativeQualityOfServiceClass()
const
1101 switch (serviceLevel) {
1102 case QThread::QualityOfService::Auto:
1103 return QOS_CLASS_DEFAULT;
1104 case QThread::QualityOfService::High:
1105 return QOS_CLASS_USER_INTERACTIVE;
1106 case QThread::QualityOfService::Eco:
1107 return QOS_CLASS_UTILITY;
1109 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)