9#include <private/qcoreapplication_p.h>
10#include <private/qeventdispatcher_win_p.h>
13#include <private/quniquehandle_types_p.h>
15#include <qt_windows.h>
29 _In_ PCWSTR lpThreadDescription
33#ifndef THREAD_POWER_THROTTLING_EXECUTION_SPEED
34#define THREAD_POWER_THROTTLING_EXECUTION_SPEED 0x1
35#define THREAD_POWER_THROTTLING_CURRENT_VERSION 1
41} THREAD_POWER_THROTTLING_STATE;
44#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
45#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x2
54Q_CONSTINIT
static thread_local QThreadData *currentThreadData =
nullptr;
56static void deref_current_thread_data(QThreadData *data);
57static void destroy_current_thread_data(
void *p)
59 QThreadData *data =
static_cast<QThreadData *>(p);
60 QThread *thread = data->thread.loadAcquire();
62 if (data->isAdopted) {
66 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
73 deref_current_thread_data(data);
77void deref_current_thread_data(QThreadData *data)
84 currentThreadData =
nullptr;
87static QThreadData *get_thread_data()
89 return currentThreadData;
92static void set_thread_data(QThreadData *data)
noexcept
96 Cleanup() { QThreadStoragePrivate::init(); }
97 ~Cleanup() { destroy_current_thread_data(currentThreadData); }
99 static thread_local Cleanup currentThreadCleanup;
101 currentThreadData = data;
105
106
107void QThreadData::clearCurrentThreadData()
109 set_thread_data(
nullptr);
112QThreadData *QThreadData::currentThreadData()
noexcept
114 return get_thread_data();
117QThreadData *QThreadData::createCurrentThreadData()
119 Q_ASSERT(!currentThreadData());
121 QThreadData *data =
new QThreadData();
125 set_thread_data(data);
128 data->thread.storeRelease(
new QAdoptedThread(data));
130 deref_current_thread_data(data);
136void QAdoptedThread::init()
138 d_func()->handle = GetCurrentThread();
142
143
150 return new QEventDispatcherWin32;
155unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(
void *arg)
noexcept
157 QThread *thr =
reinterpret_cast<QThread *>(arg);
158 QThreadData *data = QThreadData::get2(thr);
161 set_thread_data(data);
162 data->threadId.storeRelaxed(QThread::currentThreadId());
165 data->reuseBindingStatusForNewNativeThread();
167 QThread::setTerminationEnabled(
false);
170 QMutexLocker locker(&thr->d_func()->mutex);
171 data->quitNow = thr->d_func()->exited;
173 if (thr->d_func()->serviceLevel != QThread::QualityOfService::Auto)
174 thr->d_func()->setQualityOfServiceLevel(thr->d_func()->serviceLevel);
177 data->ensureEventDispatcher();
178 data->eventDispatcher.loadRelaxed()->startingUp();
181 QString threadName = std::exchange(thr->d_func()->objectName, {});
182 if (Q_LIKELY(threadName.isEmpty()))
183 threadName = QString::fromUtf8(thr->metaObject()->className());
184#ifndef QT_WIN_SERVER_2016_COMPAT
185 SetThreadDescription(GetCurrentThread(),
reinterpret_cast<
const wchar_t *>(threadName.utf16()));
187 HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
188 if (kernelbase != NULL) {
189 typedef HRESULT (WINAPI *DESCFUNC)(HANDLE, PCWSTR);
191 DESCFUNC setThreadDescription =
192 (DESCFUNC)GetProcAddress(kernelbase,
"SetThreadDescription");
193 if (setThreadDescription != NULL) {
194 setThreadDescription(GetCurrentThread(),
195 reinterpret_cast<
const wchar_t *>(threadName.utf16()));
200 emit thr->started(QThread::QPrivateSignal());
201 QThread::setTerminationEnabled(
true);
204 thr->d_func()->finish();
208void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
211 serviceLevel = qosLevel;
213#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS3)
214 qCDebug(lcQThread) <<
"Setting thread QoS class to" << qosLevel <<
"for thread" << q;
216 THREAD_POWER_THROTTLING_STATE state;
217 memset(&state, 0,
sizeof(state));
218 state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
221 case QThread::QualityOfService::Auto:
222 state.ControlMask = 0;
225 case QThread::QualityOfService::Eco:
226 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
227 state.StateMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
229 case QThread::QualityOfService::High:
230 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
234 if (!SetThreadInformation(::GetCurrentThread(), THREAD_INFORMATION_CLASS::ThreadPowerThrottling,
235 &state,
sizeof(state))) {
236 qErrnoWarning(
"Failed to set thread power throttling state");
242
243
244
245
246
247
248
249
250
251
252void QThreadPrivate::finish(
bool lockAnyway)
noexcept
254 QThreadPrivate *d =
this;
255 QThread *thr = q_func();
257 QMutexLocker locker(lockAnyway ? &d->mutex :
nullptr);
258 d->threadState = QThreadPrivate::Finishing;
259 d->priority = QThread::InheritPriority;
262 emit thr->finished(QThread::QPrivateSignal());
263 QCoreApplicationPrivate::sendPostedEvents(
nullptr, QEvent::DeferredDelete, d->data);
264 QThreadStoragePrivate::finish(&d->data->tls);
268 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
269 if (eventDispatcher) {
270 d->data->eventDispatcher = 0;
273 eventDispatcher->closingDown();
274 delete eventDispatcher;
279 d->threadState = QThreadPrivate::Finished;
280 d->interruptionRequested.store(
false, std::memory_order_relaxed);
283 CloseHandle(d->handle);
289
290
292Qt::HANDLE QThread::currentThreadIdImpl()
noexcept
294 return reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId()));
297int QThread::idealThreadCount()
noexcept
306 auto countArray = [](QSpan<
const USHORT> groups) {
308 for (USHORT group : groups)
309 total += GetActiveProcessorCount(group);
316 USHORT groupCount = std::size(groups);
317 if (Q_LIKELY(GetProcessGroupAffinity(HANDLE(-1), &groupCount, groups))) {
318 return countArray({ groups, groupCount });
319 }
else if (groupCount > std::size(groups)) {
321 auto buffer =
static_cast<USHORT *>(alloca(
sizeof(USHORT) * groupCount));
322 if (GetProcessGroupAffinity(HANDLE(-1), &groupCount, buffer))
323 return countArray({ buffer, groupCount });
329 GetSystemInfo(&sysinfo);
330 return sysinfo.dwNumberOfProcessors;
333void QThread::yieldCurrentThread()
340void QThread::sleep(std::chrono::nanoseconds nsecs)
342 using namespace std::chrono;
344 QUniqueWin32NullHandle waitableTimerHandle;
345 waitableTimerHandle.reset(CreateWaitableTimerEx(
347 if (waitableTimerHandle) {
348 using namespace std::chrono_literals;
350 using hundredsOfNano = std::ratio<1, 10'000'000>;
351 using hundredsOfNanoseconds = std::chrono::duration<
long long, hundredsOfNano>;
352 const auto ticks100ns = duration_cast<hundredsOfNanoseconds>(nsecs);
355 i.QuadPart = std::min(-(ticks100ns.count()), -1ll);
356 BOOL timerResult = SetWaitableTimerEx(
357 waitableTimerHandle.get(), &i,
363 if (timerResult == TRUE) {
364 if (WaitForSingleObject(waitableTimerHandle.get(), INFINITE) == ERROR_SUCCESS)
370 ::Sleep(DWORD(duration_cast<milliseconds>(nsecs).count()));
373void QThread::sleep(
unsigned long secs)
375 ::Sleep(secs * 1000);
378void QThread::msleep(
unsigned long msecs)
383void QThread::usleep(
unsigned long usecs)
385 sleep(std::chrono::microseconds(usecs));
390void QThread::start(Priority priority)
393 QMutexLocker locker(&d->mutex);
395 if (d->threadState == QThreadPrivate::Finishing) {
401 if (d->threadState == QThreadPrivate::Running)
405 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
407 d->threadState = QThreadPrivate::Running;
410 d->interruptionRequested.store(
false, std::memory_order_relaxed);
413
414
415
416
417
418
419
420
421
422#if defined(Q_CC_MSVC) && !defined(_DLL)
424 d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
425 this, CREATE_SUSPENDED,
nullptr);
428 d->handle = CreateThread(
nullptr, d->stackSize,
429 reinterpret_cast<LPTHREAD_START_ROUTINE>(QThreadPrivate::start),
430 this, CREATE_SUSPENDED,
nullptr);
434 qErrnoWarning(
"QThread::start: Failed to create thread");
435 d->threadState = QThreadPrivate::NotStarted;
440 d->priority = priority;
443 prio = THREAD_PRIORITY_IDLE;
447 prio = THREAD_PRIORITY_LOWEST;
451 prio = THREAD_PRIORITY_BELOW_NORMAL;
455 prio = THREAD_PRIORITY_NORMAL;
459 prio = THREAD_PRIORITY_ABOVE_NORMAL;
462 case HighestPriority:
463 prio = THREAD_PRIORITY_HIGHEST;
466 case TimeCriticalPriority:
467 prio = THREAD_PRIORITY_TIME_CRITICAL;
470 case InheritPriority:
472 prio = GetThreadPriority(GetCurrentThread());
476 if (!SetThreadPriority(d->handle, prio)) {
477 qErrnoWarning(
"QThread::start: Failed to set thread priority");
480 if (ResumeThread(d->handle) == (DWORD) -1) {
481 qErrnoWarning(
"QThread::start: Failed to resume new thread");
485void QThread::terminate()
488 QMutexLocker locker(&d->mutex);
489 if (d->threadState != QThreadPrivate::Running)
491 if (!d->terminationEnabled) {
492 d->terminatePending =
true;
496 TerminateThread(d->handle, 0);
500bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
502 Q_ASSERT(threadState != QThreadPrivate::Finished);
503 Q_ASSERT(locker.isLocked());
504 QThreadPrivate *d =
this;
507 locker.mutex()->unlock();
510 switch (WaitForSingleObject(d->handle, deadline.remainingTime())) {
515 qErrnoWarning(
"QThread::wait: Thread wait failure");
523 locker.mutex()->lock();
526 if (ret && d->threadState < QThreadPrivate::Finished) {
532 if (d->threadState == QThreadPrivate::Finished && !d->waiters) {
533 CloseHandle(d->handle);
540void QThread::setTerminationEnabled(
bool enabled)
542 QThread *thr = currentThread();
543 Q_ASSERT_X(thr != 0,
"QThread::setTerminationEnabled()",
544 "Current thread was not started with QThread.");
545 QThreadPrivate *d = thr->d_func();
546 QMutexLocker locker(&d->mutex);
547 d->terminationEnabled = enabled;
548 if (enabled && d->terminatePending) {
556void QThreadPrivate::setPriority(QThread::Priority threadPriority)
561 priority = threadPriority;
562 switch (threadPriority) {
563 case QThread::IdlePriority:
564 prio = THREAD_PRIORITY_IDLE;
567 case QThread::LowestPriority:
568 prio = THREAD_PRIORITY_LOWEST;
571 case QThread::LowPriority:
572 prio = THREAD_PRIORITY_BELOW_NORMAL;
575 case QThread::NormalPriority:
576 prio = THREAD_PRIORITY_NORMAL;
579 case QThread::HighPriority:
580 prio = THREAD_PRIORITY_ABOVE_NORMAL;
583 case QThread::HighestPriority:
584 prio = THREAD_PRIORITY_HIGHEST;
587 case QThread::TimeCriticalPriority:
588 prio = THREAD_PRIORITY_TIME_CRITICAL;
595 if (!SetThreadPriority(handle, prio)) {
596 qErrnoWarning(
"QThread::setPriority: Failed to set thread priority");
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
#define Q_STATIC_LOGGING_CATEGORY(name,...)
#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION