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
149 data->ref();
150 set_thread_data(data);
151 data->threadId.storeRelaxed(QThread::currentThreadId());
152
153 // If a QThread is restarted, reuse the QBindingStatus, too
154 data->reuseBindingStatusForNewNativeThread();
155
156 QThread::setTerminationEnabled(false);
157
158 {
159 QMutexLocker locker(&thr->d_func()->mutex);
160 data->quitNow = thr->d_func()->exited;
161
162 if (thr->d_func()->serviceLevel != QThread::QualityOfService::Auto)
163 thr->d_func()->setQualityOfServiceLevel(thr->d_func()->serviceLevel);
164 }
165
166 data->ensureEventDispatcher();
167 data->eventDispatcher.loadRelaxed()->startingUp();
168
169 // sets the name of the current thread.
170 QString threadName = std::exchange(thr->d_func()->objectName, {});
171 if (Q_LIKELY(threadName.isEmpty()))
172 threadName = QString::fromUtf8(thr->metaObject()->className());
173#ifndef QT_WIN_SERVER_2016_COMPAT
174 SetThreadDescription(GetCurrentThread(), reinterpret_cast<const wchar_t *>(threadName.utf16()));
175#else
176 HMODULE kernelbase = GetModuleHandleW(L"kernelbase.dll");
177 if (kernelbase != NULL) {
178 typedef HRESULT (WINAPI *DESCFUNC)(HANDLE, PCWSTR);
179
180 DESCFUNC setThreadDescription =
181 (DESCFUNC)GetProcAddress(kernelbase, "SetThreadDescription");
182 if (setThreadDescription != NULL) {
183 setThreadDescription(GetCurrentThread(),
184 reinterpret_cast<const wchar_t *>(threadName.utf16()));
185 }
186 }
187#endif
188
189 emit thr->started(QThread::QPrivateSignal());
190 QThread::setTerminationEnabled(true);
191 thr->run();
192
193 thr->d_func()->finish();
194 return 0;
195}
196
197void QThreadPrivate::setQualityOfServiceLevel(QThread::QualityOfService qosLevel)
198{
199 Q_Q(QThread);
200 serviceLevel = qosLevel;
201
202#if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS3)
203 qCDebug(lcQThread) << "Setting thread QoS class to" << qosLevel << "for thread" << q;
204
205 THREAD_POWER_THROTTLING_STATE state;
206 memset(&state, 0, sizeof(state));
207 state.Version = THREAD_POWER_THROTTLING_CURRENT_VERSION;
208
209 switch (qosLevel) {
210 case QThread::QualityOfService::Auto:
211 state.ControlMask = 0; // Unset control of QoS
212 state.StateMask = 0;
213 break;
214 case QThread::QualityOfService::Eco:
215 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
216 state.StateMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
217 break;
218 case QThread::QualityOfService::High:
219 state.ControlMask = THREAD_POWER_THROTTLING_EXECUTION_SPEED;
220 state.StateMask = 0; // Ask to disable throttling
221 break;
222 }
223 if (!SetThreadInformation(::GetCurrentThread(), THREAD_INFORMATION_CLASS::ThreadPowerThrottling,
224 &state, sizeof(state))) {
225 qErrnoWarning("Failed to set thread power throttling state");
226 }
227#endif
228}
229
230/*
231 For regularly terminating threads, this will be called and executed by the thread as the
232 last code before the thread exits. In that case, \a arg is the current QThread.
233
234 However, this function will also be called by QThread::terminate (as well as wait() and
235 setTerminationEnabled) to give Qt a chance to update the terminated thread's state and
236 process pending DeleteLater events for objects that live in the terminated thread. And for
237 adopted thread, this method is called by the thread watcher.
238
239 In those cases, \a arg will not be the current thread.
240*/
241void QThreadPrivate::finish(bool lockAnyway) noexcept
242{
243 QThreadPrivate *d = this;
244 QThread *thr = q_func();
245
246 QMutexLocker locker(lockAnyway ? &d->mutex : nullptr);
247 d->threadState = QThreadPrivate::Finishing;
248 d->priority = QThread::InheritPriority;
249 if (lockAnyway)
250 locker.unlock();
251 emit thr->finished(QThread::QPrivateSignal());
252 QCoreApplicationPrivate::sendPostedEvents(nullptr, QEvent::DeferredDelete, d->data);
253 QThreadStoragePrivate::finish(&d->data->tls);
254 if (lockAnyway)
255 locker.relock();
256
257 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
258 if (eventDispatcher) {
259 d->data->eventDispatcher = 0;
260 if (lockAnyway)
261 locker.unlock();
262 eventDispatcher->closingDown();
263 delete eventDispatcher;
264 if (lockAnyway)
265 locker.relock();
266 }
267
268 d->threadState = QThreadPrivate::Finished;
269 d->interruptionRequested.store(false, std::memory_order_relaxed);
270
271 if (!d->waiters) {
272 CloseHandle(d->handle);
273 d->handle = 0;
274 }
275}
276
277/**************************************************************************
278 ** QThread
279 *************************************************************************/
280
281Qt::HANDLE QThread::currentThreadIdImpl() noexcept
282{
283 return reinterpret_cast<Qt::HANDLE>(quintptr(GetCurrentThreadId()));
284}
285
286int QThread::idealThreadCount() noexcept
287{
288 SYSTEM_INFO sysinfo;
289 GetSystemInfo(&sysinfo);
290 return sysinfo.dwNumberOfProcessors;
291}
292
293void QThread::yieldCurrentThread()
294{
295 SwitchToThread();
296}
297
298#endif // QT_CONFIG(thread)
299
300void QThread::sleep(std::chrono::nanoseconds nsecs)
301{
302 using namespace std::chrono;
303 ::Sleep(DWORD(duration_cast<milliseconds>(nsecs).count()));
304}
305
306void QThread::sleep(unsigned long secs)
307{
308 ::Sleep(secs * 1000);
309}
310
311void QThread::msleep(unsigned long msecs)
312{
313 ::Sleep(msecs);
314}
315
316void QThread::usleep(unsigned long usecs)
317{
318 ::Sleep((usecs / 1000) + 1);
319}
320
321#if QT_CONFIG(thread)
322
323void QThread::start(Priority priority)
324{
325 Q_D(QThread);
326 QMutexLocker locker(&d->mutex);
327
328 if (d->threadState == QThreadPrivate::Finishing) {
329 locker.unlock();
330 wait();
331 locker.relock();
332 }
333
334 if (d->threadState == QThreadPrivate::Running)
335 return;
336
337 // avoid interacting with the binding system
338 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
339 : QString();
340 d->threadState = QThreadPrivate::Running;
341 d->exited = false;
342 d->returnCode = 0;
343 d->interruptionRequested.store(false, std::memory_order_relaxed);
344
345 /*
346 NOTE: we create the thread in the suspended state, set the
347 priority and then resume the thread.
348
349 since threads are created with normal priority by default, we
350 could get into a case where a thread (with priority less than
351 NormalPriority) tries to create a new thread (also with priority
352 less than NormalPriority), but the newly created thread preempts
353 its 'parent' and runs at normal priority.
354 */
355#if defined(Q_CC_MSVC) && !defined(_DLL)
356 // MSVC -MT or -MTd build
357 d->handle = (Qt::HANDLE) _beginthreadex(NULL, d->stackSize, QThreadPrivate::start,
358 this, CREATE_SUSPENDED, nullptr);
359#else
360 // MSVC -MD or -MDd or MinGW build
361 d->handle = CreateThread(nullptr, d->stackSize,
362 reinterpret_cast<LPTHREAD_START_ROUTINE>(QThreadPrivate::start),
363 this, CREATE_SUSPENDED, nullptr);
364#endif
365
366 if (!d->handle) {
367 qErrnoWarning("QThread::start: Failed to create thread");
368 d->threadState = QThreadPrivate::NotStarted;
369 return;
370 }
371
372 int prio;
373 d->priority = priority;
374 switch (priority) {
375 case IdlePriority:
376 prio = THREAD_PRIORITY_IDLE;
377 break;
378
379 case LowestPriority:
380 prio = THREAD_PRIORITY_LOWEST;
381 break;
382
383 case LowPriority:
384 prio = THREAD_PRIORITY_BELOW_NORMAL;
385 break;
386
387 case NormalPriority:
388 prio = THREAD_PRIORITY_NORMAL;
389 break;
390
391 case HighPriority:
392 prio = THREAD_PRIORITY_ABOVE_NORMAL;
393 break;
394
395 case HighestPriority:
396 prio = THREAD_PRIORITY_HIGHEST;
397 break;
398
399 case TimeCriticalPriority:
400 prio = THREAD_PRIORITY_TIME_CRITICAL;
401 break;
402
403 case InheritPriority:
404 default:
405 prio = GetThreadPriority(GetCurrentThread());
406 break;
407 }
408
409 if (!SetThreadPriority(d->handle, prio)) {
410 qErrnoWarning("QThread::start: Failed to set thread priority");
411 }
412
413 if (ResumeThread(d->handle) == (DWORD) -1) {
414 qErrnoWarning("QThread::start: Failed to resume new thread");
415 }
416}
417
418void QThread::terminate()
419{
420 Q_D(QThread);
421 QMutexLocker locker(&d->mutex);
422 if (d->threadState != QThreadPrivate::Running)
423 return;
424 if (!d->terminationEnabled) {
425 d->terminatePending = true;
426 return;
427 }
428
429 TerminateThread(d->handle, 0);
430 d->finish(false);
431}
432
433bool QThreadPrivate::wait(QMutexLocker<QMutex> &locker, QDeadlineTimer deadline)
434{
435 Q_ASSERT(threadState != QThreadPrivate::Finished);
436 Q_ASSERT(locker.isLocked());
437 QThreadPrivate *d = this;
438
439 ++d->waiters;
440 locker.mutex()->unlock();
441
442 bool ret = false;
443 switch (WaitForSingleObject(d->handle, deadline.remainingTime())) {
444 case WAIT_OBJECT_0:
445 ret = true;
446 break;
447 case WAIT_FAILED:
448 qErrnoWarning("QThread::wait: Thread wait failure");
449 break;
450 case WAIT_ABANDONED:
451 case WAIT_TIMEOUT:
452 default:
453 break;
454 }
455
456 locker.mutex()->lock();
457 --d->waiters;
458
459 if (ret && d->threadState < QThreadPrivate::Finished) {
460 // thread was terminated by someone else
461
462 d->finish(false);
463 }
464
465 if (d->threadState == QThreadPrivate::Finished && !d->waiters) {
466 CloseHandle(d->handle);
467 d->handle = 0;
468 }
469
470 return ret;
471}
472
473void QThread::setTerminationEnabled(bool enabled)
474{
475 QThread *thr = currentThread();
476 Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
477 "Current thread was not started with QThread.");
478 QThreadPrivate *d = thr->d_func();
479 QMutexLocker locker(&d->mutex);
480 d->terminationEnabled = enabled;
481 if (enabled && d->terminatePending) {
482 d->finish(false);
483 locker.unlock(); // don't leave the mutex locked!
484 _endthreadex(0);
485 }
486}
487
488// Caller must hold the mutex
489void QThreadPrivate::setPriority(QThread::Priority threadPriority)
490{
491 // copied from start() with a few modifications:
492
493 int prio;
494 priority = threadPriority;
495 switch (threadPriority) {
496 case QThread::IdlePriority:
497 prio = THREAD_PRIORITY_IDLE;
498 break;
499
500 case QThread::LowestPriority:
501 prio = THREAD_PRIORITY_LOWEST;
502 break;
503
504 case QThread::LowPriority:
505 prio = THREAD_PRIORITY_BELOW_NORMAL;
506 break;
507
508 case QThread::NormalPriority:
509 prio = THREAD_PRIORITY_NORMAL;
510 break;
511
512 case QThread::HighPriority:
513 prio = THREAD_PRIORITY_ABOVE_NORMAL;
514 break;
515
516 case QThread::HighestPriority:
517 prio = THREAD_PRIORITY_HIGHEST;
518 break;
519
520 case QThread::TimeCriticalPriority:
521 prio = THREAD_PRIORITY_TIME_CRITICAL;
522 break;
523
524 default:
525 return;
526 }
527
528 if (!SetThreadPriority(handle, prio)) {
529 qErrnoWarning("QThread::setPriority: Failed to set thread priority");
530 }
531}
532
533#endif // QT_CONFIG(thread)
534
535QT_END_NAMESPACE
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
#define Q_STATIC_LOGGING_CATEGORY(name,...)