9#include <private/qcoreapplication_p.h>
10#include <private/qeventdispatcher_win_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;
51Q_CONSTINIT
static thread_local QThreadData *currentThreadData =
nullptr;
53static void destroy_current_thread_data(
void *p)
55 QThreadData *data =
static_cast<QThreadData *>(p);
56 QThread *thread = data->thread.loadAcquire();
58 if (data->isAdopted) {
62 QThreadPrivate *thread_p =
static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
74 currentThreadData =
nullptr;
77static QThreadData *get_thread_data()
79 return currentThreadData;
82static void set_thread_data(QThreadData *data)
noexcept
86 Cleanup() { QThreadStoragePrivate::init(); }
87 ~Cleanup() { destroy_current_thread_data(currentThreadData); }
89 static thread_local Cleanup currentThreadCleanup;
91 currentThreadData = data;
95
96
97void QThreadData::clearCurrentThreadData()
99 set_thread_data(
nullptr);
102QThreadData *QThreadData::currentThreadData()
noexcept
104 return get_thread_data();
107QThreadData *QThreadData::createCurrentThreadData()
109 Q_ASSERT(!currentThreadData());
110 std::unique_ptr data = std::make_unique<QThreadData>();
114 set_thread_data(data.get());
117 data->thread.storeRelease(
new QAdoptedThread(data.get()));
119 clearCurrentThreadData();
122 return data.release();
125void QAdoptedThread::init()
127 d_func()->handle = GetCurrentThread();
131
132
139 return new QEventDispatcherWin32;
144unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(
void *arg)
noexcept
146 QThread *thr =
reinterpret_cast<QThread *>(arg);
147 QThreadData *data = QThreadData::get2(thr);
149 data->reuseBindingStatusForNewNativeThread();
152 set_thread_data(data);
153 data->threadId.storeRelaxed(QThread::currentThreadId());
155 QThread::setTerminationEnabled(
false);
158 QMutexLocker locker(&thr->d_func()->mutex);
159 data->quitNow = thr->d_func()->exited;
161 if (thr->d_func()->serviceLevel != QThread::QualityOfService::Auto)
162 thr->d_func()->setQualityOfServiceLevel(thr->d_func()->serviceLevel);
165 data->ensureEventDispatcher();
166 data->eventDispatcher.loadRelaxed()->startingUp();
169 QString threadName = std::exchange(thr->d_func()->objectName, {});
170 if (Q_LIKELY(threadName.isEmpty()))
171 threadName = QString::fromUtf8(thr->metaObject()->className());
172#ifndef QT_WIN_SERVER_2016_COMPAT
173 SetThreadDescription(GetCurrentThread(),
reinterpret_cast<
const wchar_t *>(threadName.utf16()));
175 HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
176 if (kernelbase != NULL) {
177 typedef HRESULT (WINAPI *DESCFUNC)(HANDLE, PCWSTR);
179 DESCFUNC setThreadDescription =
180 (DESCFUNC)GetProcAddress(kernelbase,
"SetThreadDescription");
181 if (setThreadDescription != NULL) {
182 setThreadDescription(GetCurrentThread(),
183 reinterpret_cast<
const wchar_t *>(threadName.utf16()));
188 emit thr->started(QThread::QPrivateSignal());
189 QThread::setTerminationEnabled(
true);
192 thr->d_func()->finish();
196void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
199 serviceLevel = qosLevel;
201#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS3)
202 qCDebug(lcQThread) <<
"Setting thread QoS class to" << qosLevel <<
"for thread" << q;
204 THREAD_POWER_THROTTLING_STATE state;
205 memset(&state, 0,
sizeof(state));
206 state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
209 case QThread::QualityOfService::Auto:
210 state.ControlMask = 0;
213 case QThread::QualityOfService::Eco:
214 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
215 state.StateMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
217 case QThread::QualityOfService::High:
218 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
222 if (!SetThreadInformation(::GetCurrentThread(), THREAD_INFORMATION_CLASS::ThreadPowerThrottling,
223 &state,
sizeof(state))) {
224 qErrnoWarning(
"Failed to set thread power throttling state");
230
231
232
233
234
235
236
237
238
239
240void QThreadPrivate::finish(
bool lockAnyway)
noexcept
242 QThreadPrivate *d =
this;
243 QThread *thr = q_func();
245 QMutexLocker locker(lockAnyway ? &d->mutex :
nullptr);
246 d->threadState = QThreadPrivate::Finishing;
247 d->priority = QThread::InheritPriority;
250 emit thr->finished(QThread::QPrivateSignal());
251 QCoreApplicationPrivate::sendPostedEvents(
nullptr, QEvent::DeferredDelete, d->data);
252 QThreadStoragePrivate::finish(&d->data->tls);
256 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
257 if (eventDispatcher) {
258 d->data->eventDispatcher = 0;
261 eventDispatcher->closingDown();
262 delete eventDispatcher;
267 d->threadState = QThreadPrivate::Finished;
268 d->interruptionRequested.store(
false, std::memory_order_relaxed);
271 CloseHandle(d->handle);
277
278
280Qt::HANDLE QThread::currentThreadIdImpl()
noexcept
282 return reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId()));
285int QThread::idealThreadCount()
noexcept
288 GetSystemInfo(&sysinfo);
289 return sysinfo.dwNumberOfProcessors;
292void QThread::yieldCurrentThread()
299void QThread::sleep(std::chrono::nanoseconds nsecs)
301 using namespace std::chrono;
302 ::Sleep(DWORD(duration_cast<milliseconds>(nsecs).count()));
305void QThread::sleep(
unsigned long secs)
307 ::Sleep(secs * 1000);
310void QThread::msleep(
unsigned long msecs)
315void QThread::usleep(
unsigned long usecs)
317 ::Sleep((usecs / 1000) + 1);
322void QThread::start(Priority priority)
325 QMutexLocker locker(&d->mutex);
327 if (d->threadState == QThreadPrivate::Finishing) {
333 if (d->threadState == QThreadPrivate::Running)
337 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
339 d->threadState = QThreadPrivate::Running;
342 d->interruptionRequested.store(
false, std::memory_order_relaxed);
345
346
347
348
349
350
351
352
353
354#if defined(Q_CC_MSVC) && !defined(_DLL)
356 d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
357 this, CREATE_SUSPENDED,
nullptr);
360 d->handle = CreateThread(
nullptr, d->stackSize,
361 reinterpret_cast<LPTHREAD_START_ROUTINE>(QThreadPrivate::start),
362 this, CREATE_SUSPENDED,
nullptr);
366 qErrnoWarning(
"QThread::start: Failed to create thread");
367 d->threadState = QThreadPrivate::NotStarted;
372 d->priority = priority;
375 prio = THREAD_PRIORITY_IDLE;
379 prio = THREAD_PRIORITY_LOWEST;
383 prio = THREAD_PRIORITY_BELOW_NORMAL;
387 prio = THREAD_PRIORITY_NORMAL;
391 prio = THREAD_PRIORITY_ABOVE_NORMAL;
394 case HighestPriority:
395 prio = THREAD_PRIORITY_HIGHEST;
398 case TimeCriticalPriority:
399 prio = THREAD_PRIORITY_TIME_CRITICAL;
402 case InheritPriority:
404 prio = GetThreadPriority(GetCurrentThread());
408 if (!SetThreadPriority(d->handle, prio)) {
409 qErrnoWarning(
"QThread::start: Failed to set thread priority");
412 if (ResumeThread(d->handle) == (DWORD) -1) {
413 qErrnoWarning(
"QThread::start: Failed to resume new thread");
417void QThread::terminate()
420 QMutexLocker locker(&d->mutex);
421 if (d->threadState != QThreadPrivate::Running)
423 if (!d->terminationEnabled) {
424 d->terminatePending =
true;
428 TerminateThread(d->handle, 0);
432bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
434 Q_ASSERT(threadState != QThreadPrivate::Finished);
435 Q_ASSERT(locker.isLocked());
436 QThreadPrivate *d =
this;
439 locker.mutex()->unlock();
442 switch (WaitForSingleObject(d->handle, deadline.remainingTime())) {
447 qErrnoWarning(
"QThread::wait: Thread wait failure");
455 locker.mutex()->lock();
458 if (ret && d->threadState < QThreadPrivate::Finished) {
464 if (d->threadState == QThreadPrivate::Finished && !d->waiters) {
465 CloseHandle(d->handle);
472void QThread::setTerminationEnabled(
bool enabled)
474 QThread *thr = currentThread();
475 Q_ASSERT_X(thr != 0,
"QThread::setTerminationEnabled()",
476 "Current thread was not started with QThread.");
477 QThreadPrivate *d = thr->d_func();
478 QMutexLocker locker(&d->mutex);
479 d->terminationEnabled = enabled;
480 if (enabled && d->terminatePending) {
488void QThreadPrivate::setPriority(QThread::Priority threadPriority)
493 priority = threadPriority;
494 switch (threadPriority) {
495 case QThread::IdlePriority:
496 prio = THREAD_PRIORITY_IDLE;
499 case QThread::LowestPriority:
500 prio = THREAD_PRIORITY_LOWEST;
503 case QThread::LowPriority:
504 prio = THREAD_PRIORITY_BELOW_NORMAL;
507 case QThread::NormalPriority:
508 prio = THREAD_PRIORITY_NORMAL;
511 case QThread::HighPriority:
512 prio = THREAD_PRIORITY_ABOVE_NORMAL;
515 case QThread::HighestPriority:
516 prio = THREAD_PRIORITY_HIGHEST;
519 case QThread::TimeCriticalPriority:
520 prio = THREAD_PRIORITY_TIME_CRITICAL;
527 if (!SetThreadPriority(handle, prio)) {
528 qErrnoWarning(
"QThread::setPriority: Failed to set thread priority");
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
#define Q_STATIC_LOGGING_CATEGORY(name,...)