9#include <private/qcoreapplication_p.h>
10#include <private/qeventdispatcher_win_p.h>
13#include <private/quniquehandle_types_p.h>
14#include <private/qwin32ticks_p.h>
16#include <qt_windows.h>
30 _In_ PCWSTR lpThreadDescription
34#ifndef THREAD_POWER_THROTTLING_EXECUTION_SPEED
35#define THREAD_POWER_THROTTLING_EXECUTION_SPEED 0x1
36#define THREAD_POWER_THROTTLING_CURRENT_VERSION 1
42} THREAD_POWER_THROTTLING_STATE;
45#ifndef CREATE_WAITABLE_TIMER_HIGH_RESOLUTION
46#define CREATE_WAITABLE_TIMER_HIGH_RESOLUTION 0x2
55Q_CONSTINIT
static thread_local QThreadData *currentThreadData =
nullptr;
57static void deref_current_thread_data(QThreadData *data);
58static void destroy_current_thread_data(
void *p)
60 QThreadData *data =
static_cast<QThreadData *>(p);
61 QThread *thread = data->thread.loadAcquire();
63 if (data->isAdopted) {
67 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
74 deref_current_thread_data(data);
78void deref_current_thread_data(QThreadData *data)
85 currentThreadData =
nullptr;
88static QThreadData *get_thread_data()
90 return currentThreadData;
93static void set_thread_data(QThreadData *data)
noexcept
97 Cleanup() { QThreadStoragePrivate::init(); }
98 ~Cleanup() { destroy_current_thread_data(currentThreadData); }
100 static thread_local Cleanup currentThreadCleanup;
102 currentThreadData = data;
106
107
108void QThreadData::clearCurrentThreadData()
110 set_thread_data(
nullptr);
113QThreadData *QThreadData::currentThreadData()
noexcept
115 return get_thread_data();
118QThreadData *QThreadData::createCurrentThreadData()
120 Q_ASSERT(!currentThreadData());
122 QThreadData *data =
new QThreadData();
126 set_thread_data(data);
129 data->thread.storeRelease(
new QAdoptedThread(data));
131 deref_current_thread_data(data);
137void QAdoptedThread::init()
139 d_func()->handle = GetCurrentThread();
143
144
151 return new QEventDispatcherWin32;
156unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(
void *arg)
noexcept
158 QThread *thr =
reinterpret_cast<QThread *>(arg);
159 QThreadData *data = QThreadData::get2(thr);
162 set_thread_data(data);
163 data->threadId.storeRelaxed(QThread::currentThreadId());
166 data->reuseBindingStatusForNewNativeThread();
168 QThread::setTerminationEnabled(
false);
171 QMutexLocker locker(&thr->d_func()->mutex);
172 data->quitNow = thr->d_func()->exited;
174 if (thr->d_func()->serviceLevel != QThread::QualityOfService::Auto)
175 thr->d_func()->setQualityOfServiceLevel(thr->d_func()->serviceLevel);
178 data->ensureEventDispatcher();
179 data->eventDispatcher.loadRelaxed()->startingUp();
182 QString threadName = std::exchange(thr->d_func()->objectName, {});
183 if (Q_LIKELY(threadName.isEmpty()))
184 threadName = QString::fromUtf8(thr->metaObject()->className());
185#ifndef QT_WIN_SERVER_2016_COMPAT
186 SetThreadDescription(GetCurrentThread(),
reinterpret_cast<
const wchar_t *>(threadName.utf16()));
188 HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
189 if (kernelbase != NULL) {
190 typedef HRESULT (WINAPI *DESCFUNC)(HANDLE, PCWSTR);
192 DESCFUNC setThreadDescription =
193 (DESCFUNC)GetProcAddress(kernelbase,
"SetThreadDescription");
194 if (setThreadDescription != NULL) {
195 setThreadDescription(GetCurrentThread(),
196 reinterpret_cast<
const wchar_t *>(threadName.utf16()));
201 emit thr->started(QThread::QPrivateSignal());
202 QThread::setTerminationEnabled(
true);
205 thr->d_func()->finish();
209void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
212 serviceLevel = qosLevel;
214#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS3)
215 qCDebug(lcQThread) <<
"Setting thread QoS class to" << qosLevel <<
"for thread" << q;
217 THREAD_POWER_THROTTLING_STATE state;
218 memset(&state, 0,
sizeof(state));
219 state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
222 case QThread::QualityOfService::Auto:
223 state.ControlMask = 0;
226 case QThread::QualityOfService::Eco:
227 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
228 state.StateMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
230 case QThread::QualityOfService::High:
231 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
235 if (!SetThreadInformation(::GetCurrentThread(), THREAD_INFORMATION_CLASS::ThreadPowerThrottling,
236 &state,
sizeof(state))) {
237 qErrnoWarning(
"Failed to set thread power throttling state");
243
244
245
246
247
248
249
250
251
252
253void QThreadPrivate::finish(
bool lockAnyway)
noexcept
255 QThreadPrivate *d =
this;
256 QThread *thr = q_func();
258 QMutexLocker locker(lockAnyway ? &d->mutex :
nullptr);
259 d->threadState = QThreadPrivate::Finishing;
260 d->priority = QThread::InheritPriority;
263 emit thr->finished(QThread::QPrivateSignal());
264 QCoreApplicationPrivate::sendPostedEvents(
nullptr, QEvent::DeferredDelete, d->data);
265 QThreadStoragePrivate::finish(&d->data->tls);
269 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
270 if (eventDispatcher) {
271 d->data->eventDispatcher = 0;
274 eventDispatcher->closingDown();
275 delete eventDispatcher;
280 d->threadState = QThreadPrivate::Finished;
281 d->interruptionRequested.store(
false, std::memory_order_relaxed);
284 CloseHandle(d->handle);
290
291
293Qt::HANDLE QThread::currentThreadIdImpl()
noexcept
295 return reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId()));
298int QThread::idealThreadCount()
noexcept
307 auto countArray = [](QSpan<
const USHORT> groups) {
309 for (USHORT group : groups)
310 total += GetActiveProcessorCount(group);
317 USHORT groupCount = std::size(groups);
318 if (Q_LIKELY(GetProcessGroupAffinity(HANDLE(-1), &groupCount, groups))) {
319 return countArray({ groups, groupCount });
320 }
else if (groupCount > std::size(groups)) {
322 auto buffer =
static_cast<USHORT *>(alloca(
sizeof(USHORT) * groupCount));
323 if (GetProcessGroupAffinity(HANDLE(-1), &groupCount, buffer))
324 return countArray({ buffer, groupCount });
330 GetSystemInfo(&sysinfo);
331 return sysinfo.dwNumberOfProcessors;
334void QThread::yieldCurrentThread()
341void QThread::sleep(std::chrono::nanoseconds nsecs)
343 using namespace std::chrono;
345 QUniqueWin32NullHandle waitableTimerHandle;
346 waitableTimerHandle.reset(CreateWaitableTimerEx(
348 if (waitableTimerHandle) {
349 using namespace std::chrono_literals;
351 const auto ticks100ns = ceil<QtPrivate::win32_ticks>(nsecs);
354 i.QuadPart = std::min(-(ticks100ns.count()), -1ll);
355 BOOL timerResult = SetWaitableTimerEx(
356 waitableTimerHandle.get(), &i,
362 if (timerResult == TRUE) {
363 if (WaitForSingleObject(waitableTimerHandle.get(), INFINITE) == ERROR_SUCCESS)
369 ::Sleep(DWORD(ceil<milliseconds>(nsecs).count()));
372void QThread::sleep(
unsigned long secs)
374 ::Sleep(secs * 1000);
377void QThread::msleep(
unsigned long msecs)
382void QThread::usleep(
unsigned long usecs)
384 sleep(std::chrono::microseconds(usecs));
389void QThread::start(Priority priority)
392 QMutexLocker locker(&d->mutex);
394 if (d->threadState == QThreadPrivate::Finishing) {
400 if (d->threadState == QThreadPrivate::Running)
404 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
406 d->threadState = QThreadPrivate::Running;
409 d->interruptionRequested.store(
false, std::memory_order_relaxed);
412
413
414
415
416
417
418
419
420
421#if defined(Q_CC_MSVC) && !defined(_DLL)
423 d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
424 this, CREATE_SUSPENDED,
nullptr);
427 d->handle = CreateThread(
nullptr, d->stackSize,
428 reinterpret_cast<LPTHREAD_START_ROUTINE>(QThreadPrivate::start),
429 this, CREATE_SUSPENDED,
nullptr);
433 qErrnoWarning(
"QThread::start: Failed to create thread");
434 d->threadState = QThreadPrivate::NotStarted;
439 d->priority = priority;
442 prio = THREAD_PRIORITY_IDLE;
446 prio = THREAD_PRIORITY_LOWEST;
450 prio = THREAD_PRIORITY_BELOW_NORMAL;
454 prio = THREAD_PRIORITY_NORMAL;
458 prio = THREAD_PRIORITY_ABOVE_NORMAL;
461 case HighestPriority:
462 prio = THREAD_PRIORITY_HIGHEST;
465 case TimeCriticalPriority:
466 prio = THREAD_PRIORITY_TIME_CRITICAL;
469 case InheritPriority:
471 prio = GetThreadPriority(GetCurrentThread());
475 if (!SetThreadPriority(d->handle, prio)) {
476 qErrnoWarning(
"QThread::start: Failed to set thread priority");
479 if (ResumeThread(d->handle) == (DWORD) -1) {
480 qErrnoWarning(
"QThread::start: Failed to resume new thread");
484void QThread::terminate()
487 QMutexLocker locker(&d->mutex);
488 if (d->threadState != QThreadPrivate::Running)
490 if (!d->terminationEnabled) {
491 d->terminatePending =
true;
495 TerminateThread(d->handle, 0);
499bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
501 Q_ASSERT(threadState != QThreadPrivate::Finished);
502 Q_ASSERT(locker.isLocked());
503 QThreadPrivate *d =
this;
506 locker.mutex()->unlock();
509 switch (WaitForSingleObject(d->handle, deadline.remainingTime())) {
514 qErrnoWarning(
"QThread::wait: Thread wait failure");
522 locker.mutex()->lock();
525 if (ret && d->threadState < QThreadPrivate::Finished) {
531 if (d->threadState == QThreadPrivate::Finished && !d->waiters) {
532 CloseHandle(d->handle);
539void QThread::setTerminationEnabled(
bool enabled)
541 QThread *thr = currentThread();
542 Q_ASSERT_X(thr != 0,
"QThread::setTerminationEnabled()",
543 "Current thread was not started with QThread.");
544 QThreadPrivate *d = thr->d_func();
545 QMutexLocker locker(&d->mutex);
546 d->terminationEnabled = enabled;
547 if (enabled && d->terminatePending) {
555void QThreadPrivate::setPriority(QThread::Priority threadPriority)
560 priority = threadPriority;
561 switch (threadPriority) {
562 case QThread::IdlePriority:
563 prio = THREAD_PRIORITY_IDLE;
566 case QThread::LowestPriority:
567 prio = THREAD_PRIORITY_LOWEST;
570 case QThread::LowPriority:
571 prio = THREAD_PRIORITY_BELOW_NORMAL;
574 case QThread::NormalPriority:
575 prio = THREAD_PRIORITY_NORMAL;
578 case QThread::HighPriority:
579 prio = THREAD_PRIORITY_ABOVE_NORMAL;
582 case QThread::HighestPriority:
583 prio = THREAD_PRIORITY_HIGHEST;
586 case QThread::TimeCriticalPriority:
587 prio = THREAD_PRIORITY_TIME_CRITICAL;
594 if (!SetThreadPriority(handle, prio)) {
595 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