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();
169 QMutexLocker locker(&thr->d_func()->mutex);
170 data->quitNow = thr->d_func()->exited;
172 if (thr->d_func()->serviceLevel != QThread::QualityOfService::Auto)
173 thr->d_func()->setQualityOfServiceLevel(thr->d_func()->serviceLevel);
176 data->ensureEventDispatcher();
177 data->eventDispatcher.loadRelaxed()->startingUp();
180 QString threadName = std::exchange(thr->d_func()->objectName, {});
181 if (Q_LIKELY(threadName.isEmpty()))
182 threadName = QString::fromUtf8(thr->metaObject()->className());
183 SetThreadDescription(GetCurrentThread(),
reinterpret_cast<
const wchar_t *>(threadName.utf16()));
185 emit thr->started(QThread::QPrivateSignal());
186 QThread::setTerminationEnabled(
true);
189 thr->d_func()->finish();
193void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
196 serviceLevel = qosLevel;
198#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS3)
199 qCDebug(lcQThread) <<
"Setting thread QoS class to" << qosLevel <<
"for thread" << q;
201 THREAD_POWER_THROTTLING_STATE state;
202 memset(&state, 0,
sizeof(state));
203 state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
206 case QThread::QualityOfService::Auto:
207 state.ControlMask = 0;
210 case QThread::QualityOfService::Eco:
211 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
212 state.StateMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
214 case QThread::QualityOfService::High:
215 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
219 if (!SetThreadInformation(::GetCurrentThread(), THREAD_INFORMATION_CLASS::ThreadPowerThrottling,
220 &state,
sizeof(state))) {
221 qErrnoWarning(
"Failed to set thread power throttling state");
227
228
229
230
231
232
233
234
235
236
237void QThreadPrivate::finish(
bool lockAnyway)
noexcept
239 QThreadPrivate *d =
this;
240 QThread *thr = q_func();
242 QMutexLocker locker(lockAnyway ? &d->mutex :
nullptr);
243 d->threadState = QThreadPrivate::Finishing;
244 d->priority = QThread::InheritPriority;
247 emit thr->finished(QThread::QPrivateSignal());
248 QCoreApplicationPrivate::sendPostedEvents(
nullptr, QEvent::DeferredDelete, d->data);
249 QThreadStoragePrivate::finish(&d->data->tls);
253 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
254 if (eventDispatcher) {
255 d->data->eventDispatcher = 0;
258 eventDispatcher->closingDown();
259 delete eventDispatcher;
264 d->threadState = QThreadPrivate::Finished;
265 d->interruptionRequested.store(
false, std::memory_order_relaxed);
268 CloseHandle(d->handle);
274
275
277Qt::HANDLE QThread::currentThreadIdImpl()
noexcept
279 return reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId()));
282int QThread::idealThreadCount()
noexcept
291 auto countArray = [](QSpan<
const USHORT> groups) {
293 for (USHORT group : groups)
294 total += GetActiveProcessorCount(group);
301 USHORT groupCount = std::size(groups);
302 if (Q_LIKELY(GetProcessGroupAffinity(HANDLE(-1), &groupCount, groups))) {
303 return countArray({ groups, groupCount });
304 }
else if (groupCount > std::size(groups)) {
306 auto buffer =
static_cast<USHORT *>(alloca(
sizeof(USHORT) * groupCount));
307 if (GetProcessGroupAffinity(HANDLE(-1), &groupCount, buffer))
308 return countArray({ buffer, groupCount });
314 GetSystemInfo(&sysinfo);
315 return sysinfo.dwNumberOfProcessors;
318void QThread::yieldCurrentThread()
325void QThread::sleep(std::chrono::nanoseconds nsecs)
327 using namespace std::chrono;
329 QUniqueWin32NullHandle waitableTimerHandle;
330 waitableTimerHandle.reset(CreateWaitableTimerEx(
332 if (waitableTimerHandle) {
333 using namespace std::chrono_literals;
335 const auto ticks100ns = ceil<QtPrivate::win32_ticks>(nsecs);
338 i.QuadPart = std::min(-(ticks100ns.count()), -1ll);
339 BOOL timerResult = SetWaitableTimerEx(
340 waitableTimerHandle.get(), &i,
346 if (timerResult == TRUE) {
347 if (WaitForSingleObject(waitableTimerHandle.get(), INFINITE) == ERROR_SUCCESS)
353 ::Sleep(DWORD(ceil<milliseconds>(nsecs).count()));
356void QThread::sleep(
unsigned long secs)
358 ::Sleep(secs * 1000);
361void QThread::msleep(
unsigned long msecs)
366void QThread::usleep(
unsigned long usecs)
368 sleep(std::chrono::microseconds(usecs));
373void QThread::start(Priority priority)
376 QMutexLocker locker(&d->mutex);
378 if (d->threadState == QThreadPrivate::Finishing) {
384 if (d->threadState == QThreadPrivate::Running)
388 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
390 d->threadState = QThreadPrivate::Running;
393 d->interruptionRequested.store(
false, std::memory_order_relaxed);
396
397
398
399
400
401
402
403
404
405#if defined(Q_CC_MSVC) && !defined(_DLL)
407 d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
408 this, CREATE_SUSPENDED,
nullptr);
411 d->handle = CreateThread(
nullptr, d->stackSize,
412 reinterpret_cast<LPTHREAD_START_ROUTINE>(QThreadPrivate::start),
413 this, CREATE_SUSPENDED,
nullptr);
417 qErrnoWarning(
"QThread::start: Failed to create thread");
418 d->threadState = QThreadPrivate::NotStarted;
423 d->priority = priority;
426 prio = THREAD_PRIORITY_IDLE;
430 prio = THREAD_PRIORITY_LOWEST;
434 prio = THREAD_PRIORITY_BELOW_NORMAL;
438 prio = THREAD_PRIORITY_NORMAL;
442 prio = THREAD_PRIORITY_ABOVE_NORMAL;
445 case HighestPriority:
446 prio = THREAD_PRIORITY_HIGHEST;
449 case TimeCriticalPriority:
450 prio = THREAD_PRIORITY_TIME_CRITICAL;
453 case InheritPriority:
455 prio = GetThreadPriority(GetCurrentThread());
459 if (!SetThreadPriority(d->handle, prio)) {
460 qErrnoWarning(
"QThread::start: Failed to set thread priority");
463 if (ResumeThread(d->handle) == (DWORD) -1) {
464 qErrnoWarning(
"QThread::start: Failed to resume new thread");
468void QThread::terminate()
471 QMutexLocker locker(&d->mutex);
472 if (d->threadState != QThreadPrivate::Running)
474 if (!d->terminationEnabled) {
475 d->terminatePending =
true;
479 TerminateThread(d->handle, 0);
483bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
485 Q_ASSERT(threadState != QThreadPrivate::Finished);
486 Q_ASSERT(locker.isLocked());
487 QThreadPrivate *d =
this;
490 locker.mutex()->unlock();
493 switch (WaitForSingleObject(d->handle, deadline.remainingTime())) {
498 qErrnoWarning(
"QThread::wait: Thread wait failure");
506 locker.mutex()->lock();
509 if (ret && d->threadState < QThreadPrivate::Finished) {
515 if (d->threadState == QThreadPrivate::Finished && !d->waiters) {
516 CloseHandle(d->handle);
523void QThread::setTerminationEnabled(
bool enabled)
525 QThreadData *thr = QThreadData::currentThreadData();
526 Q_ASSERT_X(thr && !thr->isAdopted,
"QThread::setTerminationEnabled()",
527 "Current thread was not started with QThread.");
528 QThreadPrivate *d = thr->thread.loadRelaxed()->d_func();
529 QMutexLocker locker(&d->mutex);
530 d->terminationEnabled = enabled;
531 if (enabled && d->terminatePending) {
539void QThreadPrivate::setPriority(QThread::Priority threadPriority)
544 priority = threadPriority;
545 switch (threadPriority) {
546 case QThread::IdlePriority:
547 prio = THREAD_PRIORITY_IDLE;
550 case QThread::LowestPriority:
551 prio = THREAD_PRIORITY_LOWEST;
554 case QThread::LowPriority:
555 prio = THREAD_PRIORITY_BELOW_NORMAL;
558 case QThread::NormalPriority:
559 prio = THREAD_PRIORITY_NORMAL;
562 case QThread::HighPriority:
563 prio = THREAD_PRIORITY_ABOVE_NORMAL;
566 case QThread::HighestPriority:
567 prio = THREAD_PRIORITY_HIGHEST;
570 case QThread::TimeCriticalPriority:
571 prio = THREAD_PRIORITY_TIME_CRITICAL;
578 if (!SetThreadPriority(handle, prio)) {
579 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