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>
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);
365 if (Q_LIKELY(objectName.isEmpty()))
366 setit(thr->metaObject()->className());
368 setit(std::exchange(objectName, {}).toLocal8Bit());
406static void setCancellationEnabled(
bool enable)
408#ifdef PTHREAD_CANCEL_DISABLE
411 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,
nullptr);
412 pthread_testcancel();
415 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
nullptr);
422void *QThreadPrivate::start(
void *arg)
424 setCancellationEnabled(
false);
426 QThread *thr =
reinterpret_cast<QThread *>(arg);
427 QThreadData *data = QThreadData::get2(thr);
430 set_thread_data(data);
433 data->reuseBindingStatusForNewNativeThread();
435 pthread_cleanup_push([](
void *arg) {
static_cast<QThread *>(arg)->d_func()->finish(); }, arg);
441 QMutexLocker locker(&thr->d_func()->mutex);
444 if (thr->d_func()->priority & ThreadPriorityResetFlag) {
445 thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
449 Q_ASSERT(data->threadId.loadRelaxed() == QThread::currentThreadId());
452 data->quitNow = thr->d_func()->exited;
458 setCurrentThreadName(thr, thr->d_func()->objectName);
465 setCancellationEnabled(
true);
467 data->ensureEventDispatcher();
468 data->eventDispatcher.loadRelaxed()->startingUp();
470 emit thr->started(QThread::QPrivateSignal());
477 pthread_cleanup_pop(1);
481void QThreadPrivate::finish(
bool calledFromExit)
483 QThreadPrivate *d =
this;
484 QThread *thr = q_func();
489 setCancellationEnabled(
false);
491 QMutexLocker locker(&d->mutex);
493 d->threadState = QThreadPrivate::Finishing;
495 emit thr->finished(QThread::QPrivateSignal());
496 QCoreApplication::sendPostedEvents(
nullptr, QEvent::DeferredDelete);
498 QThreadStoragePrivate::finish(&d->data->tls, calledFromExit);
500 if constexpr (QT_CONFIG(broken_threadlocal_dtors))
504void QThreadPrivate::cleanup()
506 QThreadPrivate *d =
this;
510 setCancellationEnabled(
false);
512 QMutexLocker locker(&d->mutex);
513 d->priority = QThread::InheritPriority;
515 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
516 if (eventDispatcher) {
517 d->data->eventDispatcher =
nullptr;
519 eventDispatcher->closingDown();
520 delete eventDispatcher;
524 d->interruptionRequested.store(
false, std::memory_order_relaxed);
531
532
535
536
537
538
539
540
541
542
543
544
545
546
547
548Qt::HANDLE QThread::currentThreadIdImpl()
noexcept
550 return to_HANDLE(pthread_self());
553#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
555# define _SC_NPROCESSORS_ONLN 84
559int QThreadPrivate::idealThreadCount = 1;
562#if QT_CONFIG(trivial_auto_var_init_pattern) && defined(Q_CC_GNU_ONLY)
565__attribute__((optimize(
"trivial-auto-var-init=uninitialized")))
567int QThread::idealThreadCount()
noexcept
571#if defined(Q_OS_HPUX)
573 struct pst_dynamic psd;
574 if (pstat_getdynamic(&psd,
sizeof(psd), 1, 0) == -1) {
575 perror(
"pstat_getdynamic");
577 cores = (
int)psd.psd_proc_cnt;
579#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
581# if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1800
582 QT_WARNING_DISABLE_CLANG(
"-Wvla-cxx-extension")
586 constexpr qsizetype MaxCpuCount = 1024 * 1024;
587 constexpr qsizetype MaxCpuSetArraySize = MaxCpuCount /
sizeof(cpu_set_t) / 8;
590 cpu_set_t cpuset[size];
591 if (sched_getaffinity(0,
sizeof(cpu_set_t) * size, cpuset) == 0) {
592 cores = CPU_COUNT_S(
sizeof(cpu_set_t) * size, cpuset);
596 }
while (size < MaxCpuSetArraySize);
598#elif defined(Q_OS_BSD4)
600 size_t len =
sizeof(cores);
604 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
607#elif defined(Q_OS_INTEGRITY)
608#if (__INTEGRITY_MAJOR_VERSION >= 10
)
610 Value processorCount;
611 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
612 cores = processorCount;
617#elif defined(Q_OS_VXWORKS)
618 cpuset_t cpus = vxCpuEnabledGet();
622 for (
int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
623 if (CPUSET_ISSET(cpus, i)) {
628#elif defined(Q_OS_WASM)
629 cores = QThreadPrivate::idealThreadCount;
632 cores = (
int)sysconf(_SC_NPROCESSORS_ONLN);
639void QThread::yieldCurrentThread()
657 QT_EINTR_LOOP(r, nanosleep(&amount, &amount));
660void QThread::sleep(
unsigned long secs)
662 sleep(std::chrono::seconds{secs});
665void QThread::msleep(
unsigned long msecs)
667 sleep(std::chrono::milliseconds{msecs});
670void QThread::usleep(
unsigned long usecs)
672 sleep(std::chrono::microseconds{usecs});
675void QThread::sleep(std::chrono::nanoseconds nsec)
677 qt_nanosleep(durationToTimespec(nsec));
682#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
684static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
693 int priority_norm = 10;
696 struct _sched_info info;
697 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
700 if (priority == QThread::IdlePriority) {
701 *sched_priority = info.priority_min;
705 if (priority_norm < info.priority_min)
706 priority_norm = info.priority_min;
707 if (priority_norm > info.priority_priv)
708 priority_norm = info.priority_priv;
711 int from_min, from_max;
713 if (priority < QThread::NormalPriority) {
714 to_min = info.priority_min;
715 to_max = priority_norm;
716 from_min = QThread::LowestPriority;
717 from_max = QThread::NormalPriority;
719 to_min = priority_norm;
720 to_max = info.priority_priv;
721 from_min = QThread::NormalPriority;
722 from_max = QThread::TimeCriticalPriority;
725 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
726 prio = qBound(to_min, prio, to_max);
728 *sched_priority = prio;
735static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
738 if (priority == QThread::IdlePriority) {
739 *sched_policy = SCHED_IDLE;
743 const int lowestPriority = QThread::LowestPriority;
745 const int lowestPriority = QThread::IdlePriority;
747 const int highestPriority = QThread::TimeCriticalPriority;
751#if defined(Q_OS_VXWORKS)
753 prio_min = SCHED_FIFO_LOW_PRI;
754 prio_max = SCHED_FIFO_HIGH_PRI;
756 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
759 prio_min = sched_get_priority_min(*sched_policy);
760 prio_max = sched_get_priority_max(*sched_policy);
763 if (prio_min == -1 || prio_max == -1)
768 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
769 prio = qMax(prio_min, qMin(prio_max, prio));
771 *sched_priority = prio;
777void QThread::start(Priority priority)
780 QMutexLocker locker(&d->mutex);
782 if (d->threadState == QThreadPrivate::Finishing)
783 d->wait(locker, QDeadlineTimer::Forever);
785 if (d->threadState == QThreadPrivate::Running)
788 d->threadState = QThreadPrivate::Running;
791 d->interruptionRequested.store(
false, std::memory_order_relaxed);
792 d->terminated =
false;
795 pthread_attr_init(&attr);
796 if constexpr (!UsingPThreadTimedJoin)
797 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
798 if (d->serviceLevel != QThread::QualityOfService::Auto) {
800 pthread_attr_set_qos_class_np(&attr, d->nativeQualityOfServiceClass(), 0);
807 d->priority = priority;
809#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
811 case InheritPriority:
813 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
820 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
823 qWarning(
"QThread::start: Cannot determine default scheduler policy");
828 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
831 qWarning(
"QThread::start: Cannot determine scheduler priority range");
836 sp.sched_priority = prio;
838 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
839 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
840 || pthread_attr_setschedparam(&attr, &sp) != 0) {
843 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
844 d->priority = qToUnderlying(priority) | ThreadPriorityResetFlag;
852 if (d->stackSize > 0) {
853#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0
> 0
)
854 int code = pthread_attr_setstacksize(&attr, d->stackSize);
860 qErrnoWarning(code,
"QThread::start: Thread stack size error");
864 d->threadState = QThreadPrivate::NotStarted;
870 if (Q_LIKELY(objectName().isEmpty()))
871 pthread_attr_setthreadname(&attr, metaObject()->className());
873 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
876 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
881 int code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
885#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
886 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
888 code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
890 d->data->threadId.storeRelaxed(to_HANDLE(threadId));
892 pthread_attr_destroy(&attr);
895 qErrnoWarning(code,
"QThread::start: Thread creation error");
897 d->threadState = QThreadPrivate::NotStarted;
898 d->data->threadId.storeRelaxed(
nullptr);
902void QThread::terminate()
904#if !defined(Q_OS_ANDROID) && !defined(Q_OS_OHOS)
906 QMutexLocker locker(&d->mutex);
908 const auto id = d->data->threadId.loadRelaxed();
915 d->terminated =
true;
917 const bool selfCancelling = d->data == get_thread_data();
918 if (selfCancelling) {
926 if (
int code = pthread_cancel(from_HANDLE<pthread_t>(id))) {
929 d->terminated =
false;
930 qErrnoWarning(code,
"QThread::start: Thread termination error");
935static void wakeAllInternal(QThreadPrivate *d)
937 d->threadState = QThreadPrivate::Finished;
939 d->thread_done.wakeAll();
942inline void QThreadPrivate::wakeAll()
944 if (data->isAdopted || !UsingPThreadTimedJoin)
945 wakeAllInternal(
this);
948bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
950 constexpr int HasJoinerBit =
int(0x8000'0000);
951 struct timespec ts, *pts =
nullptr;
952 if (!deadline.isForever()) {
953 ts = deadlineToAbstime(deadline);
961 QMutexLocker<QMutex> *locker;
962 int joinResult = ETIMEDOUT;
963 static void run(
void *arg) {
static_cast<CancelState *>(arg)->run(); }
967 if (joinResult == ETIMEDOUT && d->waiters)
968 d->thread_done.wakeOne();
969 else if (joinResult == 0)
971 d->waiters &= ~HasJoinerBit;
973 } nocancel = {
this, &locker };
974 int &r = nocancel.joinResult;
977 waiters |= HasJoinerBit;
980 pthread_cleanup_push(&CancelState::run, &nocancel);
981 pthread_t thrId = from_HANDLE<pthread_t>(data->threadId.loadRelaxed());
982 if constexpr (QT_CONFIG(pthread_clockjoin))
983 r = pthread_clockjoin_np(thrId,
nullptr, QSteadyClockClockId, pts);
985 r = pthread_timedjoin_np(thrId,
nullptr, pts);
986 Q_ASSERT(r == 0 || r == ETIMEDOUT);
987 pthread_cleanup_pop(1);
989 Q_ASSERT(waiters >= 0);
990 return r != ETIMEDOUT;
992 Q_ASSERT(threadState != QThreadPrivate::Finished);
993 Q_ASSERT(locker.isLocked());
999 bool mustJoin = (waiters & HasJoinerBit) == 0;
1000 pthread_cleanup_push([](
void *ptr) {
1001 --(*
static_cast<
decltype(waiters) *>(ptr));
1004 if (UsingPThreadTimedJoin && mustJoin && !data->isAdopted) {
1008 if (!thread_done.wait(locker.mutex(), deadline))
1010 result = threadState == QThreadPrivate::Finished;
1013 mustJoin = (waiters & HasJoinerBit) == 0;
1015 pthread_cleanup_pop(1);
1020void QThread::setTerminationEnabled(
bool enabled)
1022 QThread *thr = currentThread();
1023 Q_ASSERT_X(thr !=
nullptr,
"QThread::setTerminationEnabled()",
1024 "Current thread was not started with QThread.");
1027 setCancellationEnabled(enabled);
1031void QThreadPrivate::setPriority(QThread::Priority threadPriority)
1033 priority = threadPriority;
1037#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
1041 if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m) != 0) {
1044 qWarning(
"QThread::setPriority: Cannot get scheduler parameters");
1049 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
1052 qWarning(
"QThread::setPriority: Cannot determine scheduler priority range");
1056 param.sched_priority = prio;
1057 int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1061 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
1063 pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m);
1064 param.sched_priority = sched_get_priority_min(sched_policy);
1065 pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1073void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
1077 serviceLevel = qosLevel;
1079 qCDebug(lcQThread) <<
"Setting thread QoS class to" << serviceLevel <<
"for thread" << q;
1080 pthread_set_qos_class_self_np(nativeQualityOfServiceClass(), 0);
1085qos_class_t QThreadPrivate::nativeQualityOfServiceClass()
const
1094 switch (serviceLevel) {
1095 case QThread::QualityOfService::Auto:
1096 return QOS_CLASS_DEFAULT;
1097 case QThread::QualityOfService::High:
1098 return QOS_CLASS_USER_INTERACTIVE;
1099 case QThread::QualityOfService::Eco:
1100 return QOS_CLASS_UTILITY;
1102 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)