12#include <private/qcoreapplication_p.h>
13#include <private/qeventdispatcher_win_p.h>
29 _In_ PCWSTR lpThreadDescription
37void qt_watch_adopted_thread(
const HANDLE adoptedThreadHandle,
QThread *qthread);
38DWORD WINAPI qt_adopted_thread_watcher_function(LPVOID);
40static DWORD qt_current_thread_data_tls_index = TLS_OUT_OF_INDEXES;
43 if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES)
47 if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES)
49 qt_current_thread_data_tls_index = TlsAlloc();
52static void qt_free_tls()
54 if (qt_current_thread_data_tls_index != TLS_OUT_OF_INDEXES) {
55 TlsFree(qt_current_thread_data_tls_index);
56 qt_current_thread_data_tls_index = TLS_OUT_OF_INDEXES;
59Q_DESTRUCTOR_FUNCTION(qt_free_tls)
66 TlsSetValue(qt_current_thread_data_tls_index, 0);
73 if (!threadData && createIfNecessary) {
77 TlsSetValue(qt_current_thread_data_tls_index, threadData);
81 TlsSetValue(qt_current_thread_data_tls_index, 0);
94 HANDLE realHandle = INVALID_HANDLE_VALUE;
95 DuplicateHandle(GetCurrentProcess(),
101 DUPLICATE_SAME_ACCESS);
102 qt_watch_adopted_thread(realHandle, threadData->
thread);
110 d_func()->handle = GetCurrentThread();
111 d_func()->id = GetCurrentThreadId();
114static QList<HANDLE> qt_adopted_thread_handles;
115static QList<QThread *> qt_adopted_qthreads;
116Q_CONSTINIT
static QBasicMutex qt_adopted_thread_watcher_mutex;
117static DWORD qt_adopted_thread_watcher_id = 0;
118static HANDLE qt_adopted_thread_wakeup = 0;
126void qt_watch_adopted_thread(
const HANDLE adoptedThreadHandle,
QThread *qthread)
130 if (GetCurrentThreadId() == qt_adopted_thread_watcher_id) {
131 CloseHandle(adoptedThreadHandle);
135 qt_adopted_thread_handles.append(adoptedThreadHandle);
136 qt_adopted_qthreads.append(qthread);
139 if (qt_adopted_thread_watcher_id == 0) {
140 if (qt_adopted_thread_wakeup == 0) {
141 qt_adopted_thread_wakeup = CreateEvent(0,
false,
false, 0);
142 qt_adopted_thread_handles.prepend(qt_adopted_thread_wakeup);
145 CloseHandle(CreateThread(0, 0, qt_adopted_thread_watcher_function, 0, 0, &qt_adopted_thread_watcher_id));
147 SetEvent(qt_adopted_thread_wakeup);
156DWORD WINAPI qt_adopted_thread_watcher_function(LPVOID)
159 qt_adopted_thread_watcher_mutex.lock();
161 if (qt_adopted_thread_handles.count() == 1) {
162 qt_adopted_thread_watcher_id = 0;
163 qt_adopted_thread_watcher_mutex.unlock();
167 QList<HANDLE> handlesCopy = qt_adopted_thread_handles;
168 qt_adopted_thread_watcher_mutex.unlock();
170 DWORD
ret = WAIT_TIMEOUT;
173 int loops = handlesCopy.size() / MAXIMUM_WAIT_OBJECTS;
174 if (handlesCopy.size() % MAXIMUM_WAIT_OBJECTS)
179 count = handlesCopy.count();
180 ret = WaitForMultipleObjects(handlesCopy.count(), handlesCopy.constData(),
false, INFINITE);
184 offset = loop * MAXIMUM_WAIT_OBJECTS;
186 ret = WaitForMultipleObjects(
count, handlesCopy.constData() +
offset,
false, 100);
187 loop = (loop + 1) % loops;
188 }
while (
ret == WAIT_TIMEOUT);
192 qWarning(
"QThread internal error while waiting for adopted threads: %d",
int(GetLastError()));
196 const int handleIndex =
offset +
ret - WAIT_OBJECT_0;
197 if (handleIndex == 0)
199 const int qthreadIndex = handleIndex - 1;
201 qt_adopted_thread_watcher_mutex.lock();
203 qt_adopted_thread_watcher_mutex.unlock();
204 if (
data->isAdopted) {
210 QThreadPrivate::finish(thread);
215 CloseHandle(qt_adopted_thread_handles.at(handleIndex));
216 qt_adopted_thread_handles.remove(handleIndex);
217 qt_adopted_qthreads.remove(qthreadIndex);
241unsigned int __stdcall QT_ENSURE_STACK_ALIGNED_FOR_SSE QThreadPrivate::start(
void *
arg)
noexcept
247 TlsSetValue(qt_current_thread_data_tls_index,
data);
254 data->quitNow = thr->d_func()->exited;
257 data->ensureEventDispatcher();
258 data->eventDispatcher.loadRelaxed()->startingUp();
261 QString threadName = std::exchange(thr->d_func()->objectName, {});
266 emit thr->started(QThread::QPrivateSignal());
285void QThreadPrivate::finish(
void *
arg,
bool lockAnyway)
noexcept
291 d->isInFinish =
true;
293 void **tls_data =
reinterpret_cast<void **
>(&
d->data->tls);
296 emit thr->finished(QThread::QPrivateSignal());
297 qCDebug(lcDeleteLater) <<
"Sending deferred delete events as part of finishing thread" << thr;
299 QThreadStorageData::finish(tls_data);
304 if (eventDispatcher) {
305 d->data->eventDispatcher = 0;
309 delete eventDispatcher;
316 d->isInFinish =
false;
317 d->interruptionRequested.store(
false, std::memory_order_relaxed);
320 CloseHandle(
d->handle);
331Qt::HANDLE QThread::currentThreadIdImpl() noexcept
339 GetSystemInfo(&sysinfo);
340 return sysinfo.dwNumberOfProcessors;
352 using namespace std::chrono;
353 ::Sleep(DWORD(duration_cast<milliseconds>(nsecs).
count()));
358 ::Sleep(secs * 1000);
368 ::Sleep((usecs / 1000) + 1);
388 d->objectName =
d->extraData ?
d->extraData->objectName.valueBypassingBindings()
394 d->interruptionRequested.store(
false, std::memory_order_relaxed);
406#if defined(Q_CC_MSVC) && !defined(_DLL)
408 d->handle = (
Qt::HANDLE) _beginthreadex(NULL,
d->stackSize, QThreadPrivate::start,
409 this, CREATE_SUSPENDED, &(
d->id));
412 d->handle = CreateThread(
nullptr,
d->stackSize,
413 reinterpret_cast<LPTHREAD_START_ROUTINE
>(QThreadPrivate::start),
414 this, CREATE_SUSPENDED,
reinterpret_cast<LPDWORD
>(&
d->id));
428 prio = THREAD_PRIORITY_IDLE;
432 prio = THREAD_PRIORITY_LOWEST;
436 prio = THREAD_PRIORITY_BELOW_NORMAL;
440 prio = THREAD_PRIORITY_NORMAL;
444 prio = THREAD_PRIORITY_ABOVE_NORMAL;
448 prio = THREAD_PRIORITY_HIGHEST;
452 prio = THREAD_PRIORITY_TIME_CRITICAL;
457 prio = GetThreadPriority(GetCurrentThread());
461 if (!SetThreadPriority(
d->handle, prio)) {
462 qErrnoWarning(
"QThread::start: Failed to set thread priority");
465 if (ResumeThread(
d->handle) == (DWORD) -1) {
466 qErrnoWarning(
"QThread::start: Failed to resume new thread");
476 if (!
d->terminationEnabled) {
477 d->terminatePending =
true;
481 TerminateThread(
d->handle, 0);
482 QThreadPrivate::finish(
this,
false);
490 if (
d->id == GetCurrentThreadId()) {
491 qWarning(
"QThread::wait: Thread tried to wait on itself");
494 if (
d->finished || !
d->running)
498 locker.mutex()->unlock();
514 locker.mutex()->lock();
517 if (
ret && !
d->finished) {
520 QThreadPrivate::finish(
this,
false);
523 if (
d->finished && !
d->waiters) {
524 CloseHandle(
d->handle);
534 Q_ASSERT_X(thr != 0,
"QThread::setTerminationEnabled()",
535 "Current thread was not started with QThread.");
539 if (
enabled &&
d->terminatePending) {
540 QThreadPrivate::finish(thr,
false);
552 priority = threadPriority;
553 switch (threadPriority) {
555 prio = THREAD_PRIORITY_IDLE;
559 prio = THREAD_PRIORITY_LOWEST;
563 prio = THREAD_PRIORITY_BELOW_NORMAL;
567 prio = THREAD_PRIORITY_NORMAL;
571 prio = THREAD_PRIORITY_ABOVE_NORMAL;
575 prio = THREAD_PRIORITY_HIGHEST;
579 prio = THREAD_PRIORITY_TIME_CRITICAL;
586 if (!SetThreadPriority(
handle, prio)) {
587 qErrnoWarning(
"QThread::setPriority: Failed to set thread priority");
virtual void closingDown()
Type loadRelaxed() const noexcept
void storeRelaxed(Type newValue) noexcept
static void sendPostedEvents(QObject *receiver, int event_type, QThreadData *data)
static QBasicAtomicPointer< void > theMainThreadId
static QBasicAtomicPointer< QThread > theMainThread
qint64 remainingTime() const noexcept
Returns the remaining time in this QDeadlineTimer object in milliseconds.
void unlock() noexcept
Unlocks this mutex locker.
static QObjectPrivate * get(QObject *o)
QThread * thread() const
Returns the thread in which the object lives.
\macro QT_RESTRICTED_CAST_FROM_ASCII
const ushort * utf16() const
Returns the QString as a '\0\'-terminated array of unsigned shorts.
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
QThreadData(int initialRefCount=1)
static void clearCurrentThreadData()
QAtomicPointer< void > threadId
static QThreadData * get2(QThread *thread)
QAtomicPointer< QThread > thread
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
void start(Priority=InheritPriority)
static int idealThreadCount() noexcept
static QThread * currentThread()
static void setTerminationEnabled(bool enabled=true)
static void yieldCurrentThread()
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
static void usleep(unsigned long)
Priority priority() const
static void msleep(unsigned long)
static void sleep(unsigned long)
void qErrnoWarning(const char *msg,...)
Combined button and popup list for selecting options.
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
GLuint64 GLenum void * handle
GLenum GLenum GLsizei count
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLenum GLuint GLintptr offset
#define Q_ASSERT_X(cond, x, msg)
WINBASEAPI HRESULT WINAPI SetThreadDescription(_In_ HANDLE hThread, _In_ PCWSTR lpThreadDescription)
QDeadlineTimer deadline(30s)