Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qthread_win.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
5#include "qthread.h"
6#include "qthread_p.h"
7
9#include <private/qcoreapplication_p.h>
10#include <private/qeventdispatcher_win_p.h>
12#include "qmutex.h"
13#include "qthreadstorage.h"
14
15#include <qt_windows.h>
16
17#ifndef _MT
18# define _MT
19#endif // _MT
20#include <process.h>
21
22extern "C" {
23// MinGW is missing the declaration of SetThreadDescription:
24WINBASEAPI
25HRESULT
26WINAPI
27SetThreadDescription(
28 _In_ HANDLE hThread,
29 _In_ PCWSTR lpThreadDescription
30 );
31}
32
33#ifndef THREAD_POWER_THROTTLING_EXECUTION_SPEED
34#define THREAD_POWER_THROTTLING_EXECUTION_SPEED 0x1
35#define THREAD_POWER_THROTTLING_CURRENT_VERSION 1
36
41} THREAD_POWER_THROTTLING_STATE;
42#endif
43
44
45QT_BEGIN_NAMESPACE
46
47Q_STATIC_LOGGING_CATEGORY(lcQThread, "qt.core.thread", QtWarningMsg)
48
49#if QT_CONFIG(thread)
50
51Q_CONSTINIT static thread_local QThreadData *currentThreadData = nullptr;
52
53static void destroy_current_thread_data(void *p)
54{
55 QThreadData *data = static_cast<QThreadData *>(p);
56 QThread *thread = data->thread.loadAcquire();
57
58 if (data->isAdopted) {
59 // If this is an adopted thread, then QThreadData owns the QThread and
60 // this is very likely the last reference. These pointers cannot be
61 // null and there is no race.
62 QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
63 thread_p->finish();
64 } else {
65 // We may be racing the QThread destructor in another thread and it may
66 // have begun destruction; we must not dereference the QThread pointer.
67 }
68
69 // the QThread object may still have a reference, so this may not delete
70 data->deref();
71
72 // ... but we must reset it to zero before returning so we aren't
73 // leaving a dangling pointer.
74 currentThreadData = nullptr;
75}
76
77static QThreadData *get_thread_data()
78{
79 return currentThreadData;
80}
81
82static void set_thread_data(QThreadData *data) noexcept
83{
84 if (data) {
85 struct Cleanup {
86 Cleanup() { QThreadStoragePrivate::init(); }
87 ~Cleanup() { destroy_current_thread_data(currentThreadData); }
88 };
89 static thread_local Cleanup currentThreadCleanup;
90 }
91 currentThreadData = data;
92}
93
94/*
95 QThreadData
96*/
97void QThreadData::clearCurrentThreadData()
98{
99 set_thread_data(nullptr);
100}
101
102QThreadData *QThreadData::currentThreadData() noexcept
103{
104 return get_thread_data();
105}
106
107QThreadData *QThreadData::createCurrentThreadData()
108{
109 Q_ASSERT(!currentThreadData());
110 std::unique_ptr data = std::make_unique<QThreadData>();
111
112 // This needs to be called prior to new QAdoptedThread() to avoid
113 // recursion (see qobject.cpp).
114 set_thread_data(data.get());
115
116 QT_TRY {
117 data->thread.storeRelease(new QAdoptedThread(data.get()));
118 } QT_CATCH(...) {
119 clearCurrentThreadData();
120 QT_RETHROW;
121 }
122 return data.release();
123}
124
125void QAdoptedThread::init()
126{
127 d_func()->handle = GetCurrentThread();
128}
129
130/**************************************************************************
131 ** QThreadPrivate
132 *************************************************************************/
133
134#endif // QT_CONFIG(thread)
135
136QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *data)
137{
138 Q_UNUSED(data);
139 return new QEventDispatcherWin32;
140}
141
142#if QT_CONFIG(thread)
143
144unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(void *arg) noexcept
145{
146 QThread *thr = reinterpret_cast<QThread *>(arg);
147 QThreadData *data = QThreadData::get2(thr);
148 // If a QThread is restarted, reuse the QBindingStatus, too
149 data->reuseBindingStatusForNewNativeThread();
150
151 data->ref();
152 set_thread_data(data);
153 data->threadId.storeRelaxed(QThread::currentThreadId());
154
155 QThread::setTerminationEnabled(false);
156
157 {
158 QMutexLocker locker(&thr->d_func()->mutex);
159 data->quitNow = thr->d_func()->exited;
160
161 if (thr->d_func()->serviceLevel != QThread::QualityOfService::Auto)
162 thr->d_func()->setQualityOfServiceLevel(thr->d_func()->serviceLevel);
163 }
164
165 data->ensureEventDispatcher();
166 data->eventDispatcher.loadRelaxed()->startingUp();
167
168 // sets the name of the current thread.
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()));
174#else
175 HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
176 if (kernelbase != NULL) {
177 typedef HRESULT (WINAPI *DESCFUNC)(HANDLE, PCWSTR);
178
179 DESCFUNC setThreadDescription =
180 (DESCFUNC)GetProcAddress(kernelbase, "SetThreadDescription");
181 if (setThreadDescription != NULL) {
182 setThreadDescription(GetCurrentThread(),
183 reinterpret_cast<const wchar_t *>(threadName.utf16()));
184 }
185 }
186#endif
187
188 emit thr->started(QThread::QPrivateSignal());
189 QThread::setTerminationEnabled(true);
190 thr->run();
191
192 thr->d_func()->finish();
193 return 0;
194}
195
196void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
197{
198 Q_Q(QThread);
199 serviceLevel = qosLevel;
200
201#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS3)
202 qCDebug(lcQThread) << "Setting thread QoS class to" << qosLevel << "for thread" << q;
203
204 THREAD_POWER_THROTTLING_STATE state;
205 memset(&state, 0, sizeof(state));
206 state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
207
208 switch (qosLevel) {
209 case QThread::QualityOfService::Auto:
210 state.ControlMask = 0; // Unset control of QoS
211 state.StateMask = 0;
212 break;
213 case QThread::QualityOfService::Eco:
214 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
215 state.StateMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
216 break;
217 case QThread::QualityOfService::High:
218 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
219 state.StateMask = 0; // Ask to disable throttling
220 break;
221 }
222 if (!SetThreadInformation(::GetCurrentThread(), THREAD_INFORMATION_CLASS::ThreadPowerThrottling,
223 &state, sizeof(state))) {
224 qErrnoWarning("Failed to set thread power throttling state");
225 }
226#endif
227}
228
229/*
230 For regularly terminating threads, this will be called and executed by the thread as the
231 last code before the thread exits. In that case, \a arg is the current QThread.
232
233 However, this function will also be called by QThread::terminate (as well as wait() and
234 setTerminationEnabled) to give Qt a chance to update the terminated thread's state and
235 process pending DeleteLater events for objects that live in the terminated thread. And for
236 adopted thread, this method is called by the thread watcher.
237
238 In those cases, \a arg will not be the current thread.
239*/
240void QThreadPrivate::finish(bool lockAnyway) noexcept
241{
242 QThreadPrivate *d = this;
243 QThread *thr = q_func();
244
245 QMutexLocker locker(lockAnyway ? &d->mutex : nullptr);
246 d->threadState = QThreadPrivate::Finishing;
247 d->priority = QThread::InheritPriority;
248 if (lockAnyway)
249 locker.unlock();
250 emit thr->finished(QThread::QPrivateSignal());
251 QCoreApplicationPrivate::sendPostedEvents(nullptr, QEvent::DeferredDelete, d->data);
252 QThreadStoragePrivate::finish(&d->data->tls);
253 if (lockAnyway)
254 locker.relock();
255
256 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
257 if (eventDispatcher) {
258 d->data->eventDispatcher = 0;
259 if (lockAnyway)
260 locker.unlock();
261 eventDispatcher->closingDown();
262 delete eventDispatcher;
263 if (lockAnyway)
264 locker.relock();
265 }
266
267 d->threadState = QThreadPrivate::Finished;
268 d->interruptionRequested.store(false, std::memory_order_relaxed);
269
270 if (!d->waiters) {
271 CloseHandle(d->handle);
272 d->handle = 0;
273 }
274}
275
276/**************************************************************************
277 ** QThread
278 *************************************************************************/
279
280Qt::HANDLE QThread::currentThreadIdImpl() noexcept
281{
282 return reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId()));
283}
284
285int QThread::idealThreadCount() noexcept
286{
287 SYSTEM_INFO sysinfo;
288 GetSystemInfo(&sysinfo);
289 return sysinfo.dwNumberOfProcessors;
290}
291
292void QThread::yieldCurrentThread()
293{
294 SwitchToThread();
295}
296
297#endif // QT_CONFIG(thread)
298
299void QThread::sleep(std::chrono::nanoseconds nsecs)
300{
301 using namespace std::chrono;
302 ::Sleep(DWORD(duration_cast<milliseconds>(nsecs).count()));
303}
304
305void QThread::sleep(unsigned long secs)
306{
307 ::Sleep(secs * 1000);
308}
309
310void QThread::msleep(unsigned long msecs)
311{
312 ::Sleep(msecs);
313}
314
315void QThread::usleep(unsigned long usecs)
316{
317 ::Sleep((usecs / 1000) + 1);
318}
319
320#if QT_CONFIG(thread)
321
322void QThread::start(Priority priority)
323{
324 Q_D(QThread);
325 QMutexLocker locker(&d->mutex);
326
327 if (d->threadState == QThreadPrivate::Finishing) {
328 locker.unlock();
329 wait();
330 locker.relock();
331 }
332
333 if (d->threadState == QThreadPrivate::Running)
334 return;
335
336 // avoid interacting with the binding system
337 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
338 : QString();
339 d->threadState = QThreadPrivate::Running;
340 d->exited = false;
341 d->returnCode = 0;
342 d->interruptionRequested.store(false, std::memory_order_relaxed);
343
344 /*
345 NOTE: we create the thread in the suspended state, set the
346 priority and then resume the thread.
347
348 since threads are created with normal priority by default, we
349 could get into a case where a thread (with priority less than
350 NormalPriority) tries to create a new thread (also with priority
351 less than NormalPriority), but the newly created thread preempts
352 its 'parent' and runs at normal priority.
353 */
354#if defined(Q_CC_MSVC) && !defined(_DLL)
355 // MSVC -MT or -MTd build
356 d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
357 this, CREATE_SUSPENDED, nullptr);
358#else
359 // MSVC -MD or -MDd or MinGW build
360 d->handle = CreateThread(nullptr, d->stackSize,
361 reinterpret_cast<LPTHREAD_START_ROUTINE>(QThreadPrivate::start),
362 this, CREATE_SUSPENDED, nullptr);
363#endif
364
365 if (!d->handle) {
366 qErrnoWarning("QThread::start: Failed to create thread");
367 d->threadState = QThreadPrivate::NotStarted;
368 return;
369 }
370
371 int prio;
372 d->priority = priority;
373 switch (priority) {
374 case IdlePriority:
375 prio = THREAD_PRIORITY_IDLE;
376 break;
377
378 case LowestPriority:
379 prio = THREAD_PRIORITY_LOWEST;
380 break;
381
382 case LowPriority:
383 prio = THREAD_PRIORITY_BELOW_NORMAL;
384 break;
385
386 case NormalPriority:
387 prio = THREAD_PRIORITY_NORMAL;
388 break;
389
390 case HighPriority:
391 prio = THREAD_PRIORITY_ABOVE_NORMAL;
392 break;
393
394 case HighestPriority:
395 prio = THREAD_PRIORITY_HIGHEST;
396 break;
397
398 case TimeCriticalPriority:
399 prio = THREAD_PRIORITY_TIME_CRITICAL;
400 break;
401
402 case InheritPriority:
403 default:
404 prio = GetThreadPriority(GetCurrentThread());
405 break;
406 }
407
408 if (!SetThreadPriority(d->handle, prio)) {
409 qErrnoWarning("QThread::start: Failed to set thread priority");
410 }
411
412 if (ResumeThread(d->handle) == (DWORD) -1) {
413 qErrnoWarning("QThread::start: Failed to resume new thread");
414 }
415}
416
417void QThread::terminate()
418{
419 Q_D(QThread);
420 QMutexLocker locker(&d->mutex);
421 if (d->threadState != QThreadPrivate::Running)
422 return;
423 if (!d->terminationEnabled) {
424 d->terminatePending = true;
425 return;
426 }
427
428 TerminateThread(d->handle, 0);
429 d->finish(false);
430}
431
432bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
433{
434 Q_ASSERT(threadState != QThreadPrivate::Finished);
435 Q_ASSERT(locker.isLocked());
436 QThreadPrivate *d = this;
437
438 ++d->waiters;
439 locker.mutex()->unlock();
440
441 bool ret = false;
442 switch (WaitForSingleObject(d->handle, deadline.remainingTime())) {
443 case WAIT_OBJECT_0:
444 ret = true;
445 break;
446 case WAIT_FAILED:
447 qErrnoWarning("QThread::wait: Thread wait failure");
448 break;
449 case WAIT_ABANDONED:
450 case WAIT_TIMEOUT:
451 default:
452 break;
453 }
454
455 locker.mutex()->lock();
456 --d->waiters;
457
458 if (ret && d->threadState < QThreadPrivate::Finished) {
459 // thread was terminated by someone else
460
461 d->finish(false);
462 }
463
464 if (d->threadState == QThreadPrivate::Finished && !d->waiters) {
465 CloseHandle(d->handle);
466 d->handle = 0;
467 }
468
469 return ret;
470}
471
472void QThread::setTerminationEnabled(bool enabled)
473{
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) {
481 d->finish(false);
482 locker.unlock(); // don't leave the mutex locked!
483 _endthreadex(0);
484 }
485}
486
487// Caller must hold the mutex
488void QThreadPrivate::setPriority(QThread::Priority threadPriority)
489{
490 // copied from start() with a few modifications:
491
492 int prio;
493 priority = threadPriority;
494 switch (threadPriority) {
495 case QThread::IdlePriority:
496 prio = THREAD_PRIORITY_IDLE;
497 break;
498
499 case QThread::LowestPriority:
500 prio = THREAD_PRIORITY_LOWEST;
501 break;
502
503 case QThread::LowPriority:
504 prio = THREAD_PRIORITY_BELOW_NORMAL;
505 break;
506
507 case QThread::NormalPriority:
508 prio = THREAD_PRIORITY_NORMAL;
509 break;
510
511 case QThread::HighPriority:
512 prio = THREAD_PRIORITY_ABOVE_NORMAL;
513 break;
514
515 case QThread::HighestPriority:
516 prio = THREAD_PRIORITY_HIGHEST;
517 break;
518
519 case QThread::TimeCriticalPriority:
520 prio = THREAD_PRIORITY_TIME_CRITICAL;
521 break;
522
523 default:
524 return;
525 }
526
527 if (!SetThreadPriority(handle, prio)) {
528 qErrnoWarning("QThread::setPriority: Failed to set thread priority");
529 }
530}
531
532#endif // QT_CONFIG(thread)
533
534QT_END_NAMESPACE
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
#define Q_STATIC_LOGGING_CATEGORY(name,...)