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>
34# include <pthread_np.h>
37#if defined(Q_OS_FREEBSD)
38# include <sys/cpuset.h>
39#elif defined(Q_OS_BSD4)
40# include <sys/sysctl.h>
51#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
55#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE
)
60#if defined(Q_OS_DARWIN) || !defined(Q_OS_ANDROID) && !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0
>= 0
)
61#define QT_HAS_THREAD_PRIORITY_SCHEDULING
65#include <sys/neutrino.h>
73using namespace QtMiscUtils;
77static_assert(
sizeof(pthread_t) <=
sizeof(Qt::HANDLE));
79enum { ThreadPriorityResetFlag = 0x80000000 };
99static constexpr bool UsingPThreadTimedJoin = QT_CONFIG(pthread_clockjoin)
100 || (QT_CONFIG(pthread_timedjoin) && QWaitConditionClockId == CLOCK_REALTIME);
101#if !QT_CONFIG(pthread_clockjoin)
102int pthread_clockjoin_np(...) {
return ENOSYS; }
104#if !QT_CONFIG(pthread_timedjoin)
105int pthread_timedjoin_np(...) {
return ENOSYS; }
108#if QT_CONFIG(broken_threadlocal_dtors)
155Q_CONSTINIT
static thread_local QThreadData *currentThreadData =
nullptr;
157static void destroy_current_thread_data(QThreadData *data)
159 QThread *thread = data->thread.loadAcquire();
164 currentThreadData = data;
167 if (data->isAdopted) {
171 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
173 if constexpr (!QT_CONFIG(broken_threadlocal_dtors))
175 }
else if constexpr (!QT_CONFIG(broken_threadlocal_dtors)) {
179 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
187static void deref_current_thread_data(QThreadData *data)
194 currentThreadData =
nullptr;
197static void destroy_auxiliary_thread_data(
void *p)
199 auto data =
static_cast<QThreadData *>(p);
200 destroy_current_thread_data(data);
201 deref_current_thread_data(data);
205static QThreadData *get_thread_data()
207 return currentThreadData;
211struct QThreadDataDestroyer
214 QThreadDataDestroyer()
noexcept
216 pthread_key_create(&key, &destroy_auxiliary_thread_data);
218 ~QThreadDataDestroyer()
221 if (QThreadData *data = get_thread_data())
222 deref_current_thread_data(data);
223 pthread_key_delete(key);
226 struct EarlyMainThread {
227 EarlyMainThread() { QThreadStoragePrivate::init(); }
231 if (QThreadData *data = get_thread_data())
232 destroy_current_thread_data(data);
237#if QT_SUPPORTS_INIT_PRIORITY
238Q_DECL_INIT_PRIORITY(10)
240static QThreadDataDestroyer threadDataDestroyer;
242static void set_thread_data(QThreadData *data)
noexcept
248 static QThreadDataDestroyer::EarlyMainThread currentThreadCleanup;
249 pthread_setspecific(threadDataDestroyer.key, data);
251 currentThreadData = data;
255static typename std::enable_if<std::is_integral_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
257 return reinterpret_cast<Qt::HANDLE>(
static_cast<intptr_t>(id));
261static typename std::enable_if<std::is_integral_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
263 return static_cast<T>(
reinterpret_cast<intptr_t>(id));
267static typename std::enable_if<std::is_pointer_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
273static typename std::enable_if<std::is_pointer_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
275 return static_cast<T>(id);
278void QThreadData::clearCurrentThreadData()
280 set_thread_data(
nullptr);
283QThreadData *QThreadData::currentThreadData()
noexcept
285 return get_thread_data();
288QThreadData *QThreadData::createCurrentThreadData()
290 Q_ASSERT(!currentThreadData());
291 std::unique_ptr data = std::make_unique<QThreadData>();
295 set_thread_data(data.get());
298 data->thread.storeRelease(
new QAdoptedThread(data.get()));
300 clearCurrentThreadData();
303 return data.release();
306void QAdoptedThread::init()
311
312
315typedef void *(*QtThreadCallback)(
void *);
323#if defined(Q_OS_DARWIN)
325 int value = qEnvironmentVariableIntValue(
"QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
327 return new QEventDispatcherCoreFoundation;
329 return new QEventDispatcherUNIX;
330#elif defined(Q_OS_WASM)
331 return new QEventDispatcherWasm();
332#elif !defined(QT_NO_GLIB)
333 const bool isQtMainThread = data->thread.loadAcquire() == QCoreApplicationPrivate::mainThread();
334 if (qEnvironmentVariableIsEmpty(
"QT_NO_GLIB")
335 && (isQtMainThread || qEnvironmentVariableIsEmpty(
"QT_NO_THREADED_GLIB"))
336 && QEventDispatcherGlib::versionSupported())
337 return new QEventDispatcherGlib;
339 return new QEventDispatcherUNIX;
341 return new QEventDispatcherUNIX;
347#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX))
348static void setCurrentThreadName(
const char *name)
350# if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
351 prctl(PR_SET_NAME, (
unsigned long)name, 0, 0, 0);
352# elif defined(Q_OS_DARWIN)
353 pthread_setname_np(name);
354# elif defined(Q_OS_QNX)
355 pthread_setname_np(pthread_self(), name);
362void terminate_on_exception(T &&t)
364#ifndef QT_NO_EXCEPTIONS
367 std::forward<T>(t)();
368#ifndef QT_NO_EXCEPTIONS
373 }
catch (abi::__forced_unwind &) {
383void *QThreadPrivate::start(
void *arg)
385#ifdef PTHREAD_CANCEL_DISABLE
386 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
nullptr);
388 QThread *thr =
reinterpret_cast<QThread *>(arg);
389 QThreadData *data = QThreadData::get2(thr);
391 data->reuseBindingStatusForNewNativeThread();
394 set_thread_data(data);
396 pthread_cleanup_push([](
void *arg) {
static_cast<QThread *>(arg)->d_func()->finish(); }, arg);
397 terminate_on_exception([&] {
399 QMutexLocker locker(&thr->d_func()->mutex);
402 if (thr->d_func()->priority & ThreadPriorityResetFlag) {
403 thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
406 if (thr->d_func()->serviceLevel != QThread::QualityOfService::Auto)
407 thr->d_func()->setQualityOfServiceLevel(thr->d_func()->serviceLevel);
411 Q_ASSERT(data->threadId.loadRelaxed() == QThread::currentThreadId());
414 data->quitNow = thr->d_func()->exited;
417 data->ensureEventDispatcher();
418 data->eventDispatcher.loadRelaxed()->startingUp();
420#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX))
425 if (Q_LIKELY(thr->d_func()->objectName.isEmpty()))
426 setCurrentThreadName(thr->metaObject()->className());
428 setCurrentThreadName(std::exchange(thr->d_func()->objectName, {}).toLocal8Bit());
432 emit thr->started(QThread::QPrivateSignal());
433#ifdef PTHREAD_CANCEL_DISABLE
434 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE,
nullptr);
435 pthread_testcancel();
442 pthread_cleanup_pop(1);
446void QThreadPrivate::finish()
448 terminate_on_exception([&] {
449 QThreadPrivate *d =
this;
450 QThread *thr = q_func();
455#ifdef PTHREAD_CANCEL_DISABLE
456 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
nullptr);
459 QMutexLocker locker(&d->mutex);
461 d->threadState = QThreadPrivate::Finishing;
463 emit thr->finished(QThread::QPrivateSignal());
464 QCoreApplication::sendPostedEvents(
nullptr, QEvent::DeferredDelete);
466 QThreadStoragePrivate::finish(&d->data->tls);
469 if constexpr (QT_CONFIG(broken_threadlocal_dtors))
473void QThreadPrivate::cleanup()
475 terminate_on_exception([&] {
476 QThreadPrivate *d =
this;
480#ifdef PTHREAD_CANCEL_DISABLE
481 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE,
nullptr);
484 QMutexLocker locker(&d->mutex);
485 d->priority = QThread::InheritPriority;
487 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
488 if (eventDispatcher) {
489 d->data->eventDispatcher =
nullptr;
491 eventDispatcher->closingDown();
492 delete eventDispatcher;
496 d->interruptionRequested.store(
false, std::memory_order_relaxed);
504
505
508
509
510
511
512
513
514
515
516
517
518
519
520
521Qt::HANDLE QThread::currentThreadIdImpl()
noexcept
523 return to_HANDLE(pthread_self());
526#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
528# define _SC_NPROCESSORS_ONLN 84
532int QThreadPrivate::idealThreadCount = 1;
535#if QT_CONFIG(trivial_auto_var_init_pattern) && defined(Q_CC_GNU_ONLY)
538__attribute__((optimize(
"trivial-auto-var-init=uninitialized")))
540int QThread::idealThreadCount()
noexcept
544#if defined(Q_OS_HPUX)
546 struct pst_dynamic psd;
547 if (pstat_getdynamic(&psd,
sizeof(psd), 1, 0) == -1) {
548 perror(
"pstat_getdynamic");
550 cores = (
int)psd.psd_proc_cnt;
552#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
554# if defined(Q_CC_CLANG) && Q_CC_CLANG >= 1800
555 QT_WARNING_DISABLE_CLANG(
"-Wvla-cxx-extension")
559 constexpr qsizetype MaxCpuCount = 1024 * 1024;
560 constexpr qsizetype MaxCpuSetArraySize = MaxCpuCount /
sizeof(cpu_set_t) / 8;
563 cpu_set_t cpuset[size];
564 if (sched_getaffinity(0,
sizeof(cpu_set_t) * size, cpuset) == 0) {
565 cores = CPU_COUNT_S(
sizeof(cpu_set_t) * size, cpuset);
569 }
while (size < MaxCpuSetArraySize);
571#elif defined(Q_OS_BSD4)
573 size_t len =
sizeof(cores);
577 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
580#elif defined(Q_OS_INTEGRITY)
581#if (__INTEGRITY_MAJOR_VERSION >= 10
)
583 Value processorCount;
584 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
585 cores = processorCount;
590#elif defined(Q_OS_VXWORKS)
591 cpuset_t cpus = vxCpuEnabledGet();
595 for (
int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
596 if (CPUSET_ISSET(cpus, i)) {
601#elif defined(Q_OS_WASM)
602 cores = QThreadPrivate::idealThreadCount;
605 cores = (
int)sysconf(_SC_NPROCESSORS_ONLN);
612void QThread::yieldCurrentThread()
630 QT_EINTR_LOOP(r, nanosleep(&amount, &amount));
633void QThread::sleep(
unsigned long secs)
635 sleep(std::chrono::seconds{secs});
638void QThread::msleep(
unsigned long msecs)
640 sleep(std::chrono::milliseconds{msecs});
643void QThread::usleep(
unsigned long usecs)
645 sleep(std::chrono::microseconds{usecs});
648void QThread::sleep(std::chrono::nanoseconds nsec)
650 qt_nanosleep(durationToTimespec(nsec));
655#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
657static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
666 int priority_norm = 10;
669 struct _sched_info info;
670 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
673 if (priority == QThread::IdlePriority) {
674 *sched_priority = info.priority_min;
678 if (priority_norm < info.priority_min)
679 priority_norm = info.priority_min;
680 if (priority_norm > info.priority_priv)
681 priority_norm = info.priority_priv;
684 int from_min, from_max;
686 if (priority < QThread::NormalPriority) {
687 to_min = info.priority_min;
688 to_max = priority_norm;
689 from_min = QThread::LowestPriority;
690 from_max = QThread::NormalPriority;
692 to_min = priority_norm;
693 to_max = info.priority_priv;
694 from_min = QThread::NormalPriority;
695 from_max = QThread::TimeCriticalPriority;
698 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
699 prio = qBound(to_min, prio, to_max);
701 *sched_priority = prio;
708static bool calculateUnixPriority(
int priority,
int *sched_policy,
int *sched_priority)
711 if (priority == QThread::IdlePriority) {
712 *sched_policy = SCHED_IDLE;
716 const int lowestPriority = QThread::LowestPriority;
718 const int lowestPriority = QThread::IdlePriority;
720 const int highestPriority = QThread::TimeCriticalPriority;
724#if defined(Q_OS_VXWORKS)
726 prio_min = SCHED_FIFO_LOW_PRI;
727 prio_max = SCHED_FIFO_HIGH_PRI;
729 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
732 prio_min = sched_get_priority_min(*sched_policy);
733 prio_max = sched_get_priority_max(*sched_policy);
736 if (prio_min == -1 || prio_max == -1)
741 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
742 prio = qMax(prio_min, qMin(prio_max, prio));
744 *sched_priority = prio;
750void QThread::start(Priority priority)
753 QMutexLocker locker(&d->mutex);
755 if (d->threadState == QThreadPrivate::Finishing)
756 d->wait(locker, QDeadlineTimer::Forever);
758 if (d->threadState == QThreadPrivate::Running)
761 d->threadState = QThreadPrivate::Running;
764 d->interruptionRequested.store(
false, std::memory_order_relaxed);
765 d->terminated =
false;
768 pthread_attr_init(&attr);
769 if constexpr (!UsingPThreadTimedJoin)
770 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
772 if (d->serviceLevel != QThread::QualityOfService::Auto)
773 pthread_attr_set_qos_class_np(&attr, d->nativeQualityOfServiceClass(), 0);
776 d->priority = priority;
778#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
780 case InheritPriority:
782 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
789 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
792 qWarning(
"QThread::start: Cannot determine default scheduler policy");
797 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
800 qWarning(
"QThread::start: Cannot determine scheduler priority range");
805 sp.sched_priority = prio;
807 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
808 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
809 || pthread_attr_setschedparam(&attr, &sp) != 0) {
812 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
813 d->priority = qToUnderlying(priority) | ThreadPriorityResetFlag;
821 if (d->stackSize > 0) {
822#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0
> 0
)
823 int code = pthread_attr_setstacksize(&attr, d->stackSize);
829 qErrnoWarning(code,
"QThread::start: Thread stack size error");
833 d->threadState = QThreadPrivate::NotStarted;
839 if (Q_LIKELY(objectName().isEmpty()))
840 pthread_attr_setthreadname(&attr, metaObject()->className());
842 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
845 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
850 int code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
854#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
855 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
857 code = pthread_create(&threadId, &attr, QThreadPrivate::start,
this);
859 d->data->threadId.storeRelaxed(to_HANDLE(threadId));
861 pthread_attr_destroy(&attr);
864 qErrnoWarning(code,
"QThread::start: Thread creation error");
866 d->threadState = QThreadPrivate::NotStarted;
867 d->data->threadId.storeRelaxed(
nullptr);
871void QThread::terminate()
873#if !defined(Q_OS_ANDROID)
875 QMutexLocker locker(&d->mutex);
877 const auto id = d->data->threadId.loadRelaxed();
884 d->terminated =
true;
886 const bool selfCancelling = d->data == get_thread_data();
887 if (selfCancelling) {
895 if (
int code = pthread_cancel(from_HANDLE<pthread_t>(id))) {
898 d->terminated =
false;
899 qErrnoWarning(code,
"QThread::start: Thread termination error");
904static void wakeAllInternal(QThreadPrivate *d)
906 d->threadState = QThreadPrivate::Finished;
908 d->thread_done.wakeAll();
911inline void QThreadPrivate::wakeAll()
913 if (data->isAdopted || !UsingPThreadTimedJoin)
914 wakeAllInternal(
this);
917bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
919 constexpr int HasJoinerBit =
int(0x8000'0000);
920 struct timespec ts, *pts =
nullptr;
921 if (!deadline.isForever()) {
922 ts = deadlineToAbstime(deadline);
930 QMutexLocker<QMutex> *locker;
931 int joinResult = ETIMEDOUT;
932 static void run(
void *arg) {
static_cast<CancelState *>(arg)->run(); }
936 if (joinResult == ETIMEDOUT && d->waiters)
937 d->thread_done.wakeOne();
938 else if (joinResult == 0)
940 d->waiters &= ~HasJoinerBit;
942 } nocancel = {
this, &locker };
943 int &r = nocancel.joinResult;
946 waiters |= HasJoinerBit;
949 pthread_cleanup_push(&CancelState::run, &nocancel);
950 pthread_t thrId = from_HANDLE<pthread_t>(data->threadId.loadRelaxed());
951 if constexpr (QT_CONFIG(pthread_clockjoin))
952 r = pthread_clockjoin_np(thrId,
nullptr, SteadyClockClockId, pts);
954 r = pthread_timedjoin_np(thrId,
nullptr, pts);
955 Q_ASSERT(r == 0 || r == ETIMEDOUT);
956 pthread_cleanup_pop(1);
958 Q_ASSERT(waiters >= 0);
959 return r != ETIMEDOUT;
961 Q_ASSERT(threadState != QThreadPrivate::Finished);
962 Q_ASSERT(locker.isLocked());
968 bool mustJoin = (waiters & HasJoinerBit) == 0;
969 pthread_cleanup_push([](
void *ptr) {
970 --(*
static_cast<
decltype(waiters) *>(ptr));
973 if (UsingPThreadTimedJoin && mustJoin && !data->isAdopted) {
977 if (!thread_done.wait(locker.mutex(), deadline))
979 result = threadState == QThreadPrivate::Finished;
982 mustJoin = (waiters & HasJoinerBit) == 0;
984 pthread_cleanup_pop(1);
989void QThread::setTerminationEnabled(
bool enabled)
991 QThread *thr = currentThread();
992 Q_ASSERT_X(thr !=
nullptr,
"QThread::setTerminationEnabled()",
993 "Current thread was not started with QThread.");
996#if defined(Q_OS_ANDROID)
999 pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE,
nullptr);
1001 pthread_testcancel();
1006void QThreadPrivate::setPriority(QThread::Priority threadPriority)
1008 priority = threadPriority;
1012#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
1016 if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m) != 0) {
1019 qWarning(
"QThread::setPriority: Cannot get scheduler parameters");
1024 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
1027 qWarning(
"QThread::setPriority: Cannot determine scheduler priority range");
1031 param.sched_priority = prio;
1032 int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1036 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
1038 pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, ¶m);
1039 param.sched_priority = sched_get_priority_min(sched_policy);
1040 pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, ¶m);
1048void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
1052 serviceLevel = qosLevel;
1054 qCDebug(lcQThread) <<
"Setting thread QoS class to" << serviceLevel <<
"for thread" << q;
1055 pthread_set_qos_class_self_np(nativeQualityOfServiceClass(), 0);
1060qos_class_t QThreadPrivate::nativeQualityOfServiceClass()
const
1069 switch (serviceLevel) {
1070 case QThread::QualityOfService::Auto:
1071 return QOS_CLASS_DEFAULT;
1072 case QThread::QualityOfService::High:
1073 return QOS_CLASS_USER_INTERACTIVE;
1074 case QThread::QualityOfService::Eco:
1075 return QOS_CLASS_UTILITY;
1077 Q_UNREACHABLE_RETURN(QOS_CLASS_DEFAULT);
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
static void qt_nanosleep(timespec amount)