Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qthread_unix.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Intel Corporation.
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include "qthread.h"
6
7#include "qplatformdefs.h"
8
9#include <private/qcoreapplication_p.h>
10#include <private/qcore_unix_p.h>
11#include <private/qtools_p.h>
12
13#if defined(Q_OS_DARWIN)
14# include <private/qeventdispatcher_cf_p.h>
15#elif defined(Q_OS_WASM)
16# include <private/qeventdispatcher_wasm_p.h>
17#else
18# if !defined(QT_NO_GLIB)
20# endif
21#endif
22
23#if !defined(Q_OS_WASM)
24# include <private/qeventdispatcher_unix_p.h>
25#endif
26
27#include "qthreadstorage.h"
28
29#include "qthread_p.h"
30
31#include "qdebug.h"
32
33#ifdef __GLIBCXX__
34#include <cxxabi.h>
35#endif
36
37#include <sched.h>
38#include <errno.h>
39
40#if defined(Q_OS_FREEBSD)
41# include <sys/cpuset.h>
42#elif defined(Q_OS_BSD4)
43# include <sys/sysctl.h>
44#endif
45#ifdef Q_OS_VXWORKS
46# if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
47# include <vxCpuLib.h>
48# include <cpuset.h>
49# define QT_VXWORKS_HAS_CPUSET
50# endif
51#endif
52
53#ifdef Q_OS_HPUX
54#include <sys/pstat.h>
55#endif
56
57#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
58#include <sys/prctl.h>
59#endif
60
61#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE)
62// from linux/sched.h
63# define SCHED_IDLE 5
64#endif
65
66#if defined(Q_OS_DARWIN) || !defined(Q_OS_ANDROID) && !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
67#define QT_HAS_THREAD_PRIORITY_SCHEDULING
68#endif
69
70#if defined(Q_OS_QNX)
71#include <sys/neutrino.h>
72#endif
73
75
76using namespace QtMiscUtils;
77
78#if QT_CONFIG(thread)
79
80static_assert(sizeof(pthread_t) <= sizeof(Qt::HANDLE));
81
82enum { ThreadPriorityResetFlag = 0x80000000 };
83
84
85Q_CONSTINIT static thread_local QThreadData *currentThreadData = nullptr;
86
87Q_CONSTINIT static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT;
88Q_CONSTINIT static pthread_key_t current_thread_data_key;
89
90static void destroy_current_thread_data(void *p)
91{
92 QThreadData *data = static_cast<QThreadData *>(p);
93 // thread_local variables are set to zero before calling this destructor function,
94 // if they are internally using pthread-specific data management,
95 // so we need to set it back to the right value...
96 currentThreadData = data;
97 if (data->isAdopted) {
98 QThread *thread = data->thread.loadAcquire();
99 Q_ASSERT(thread);
100 QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
101 Q_ASSERT(!thread_p->finished);
102 thread_p->finish(thread);
103 }
104 data->deref();
105
106 // ... but we must reset it to zero before returning so we aren't
107 // leaving a dangling pointer.
108 currentThreadData = nullptr;
109}
110
111static void create_current_thread_data_key()
112{
113 pthread_key_create(&current_thread_data_key, destroy_current_thread_data);
114}
115
116static void destroy_current_thread_data_key()
117{
118 pthread_once(&current_thread_data_once, create_current_thread_data_key);
119 pthread_key_delete(current_thread_data_key);
120
121 // Reset current_thread_data_once in case we end up recreating
122 // the thread-data in the rare case of QObject construction
123 // after destroying the QThreadData.
124 pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT;
125 current_thread_data_once = pthread_once_init;
126}
127Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)
128
129
130// Utility functions for getting, setting and clearing thread specific data.
131static QThreadData *get_thread_data()
132{
133 return currentThreadData;
134}
135
136static void set_thread_data(QThreadData *data)
137{
138 currentThreadData = data;
139 pthread_once(&current_thread_data_once, create_current_thread_data_key);
140 pthread_setspecific(current_thread_data_key, data);
141}
142
143static void clear_thread_data()
144{
145 set_thread_data(nullptr);
146}
147
148template <typename T>
149static typename std::enable_if<std::is_integral_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
150{
151 return reinterpret_cast<Qt::HANDLE>(static_cast<intptr_t>(id));
152}
153
154template <typename T>
155static typename std::enable_if<std::is_integral_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
156{
157 return static_cast<T>(reinterpret_cast<intptr_t>(id));
158}
159
160template <typename T>
161static typename std::enable_if<std::is_pointer_v<T>, Qt::HANDLE>::type to_HANDLE(T id)
162{
163 return id;
164}
165
166template <typename T>
167static typename std::enable_if<std::is_pointer_v<T>, T>::type from_HANDLE(Qt::HANDLE id)
168{
169 return static_cast<T>(id);
170}
171
173{
174 clear_thread_data();
175}
176
177QThreadData *QThreadData::current(bool createIfNecessary)
178{
179 QThreadData *data = get_thread_data();
180 if (!data && createIfNecessary) {
181 data = new QThreadData;
182 QT_TRY {
183 set_thread_data(data);
184 data->thread = new QAdoptedThread(data);
185 } QT_CATCH(...) {
186 clear_thread_data();
187 data->deref();
188 data = nullptr;
190 }
191 data->deref();
192 data->isAdopted = true;
193 data->threadId.storeRelaxed(to_HANDLE(pthread_self()));
194 if (!QCoreApplicationPrivate::theMainThreadId.loadAcquire()) {
195 QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed());
196 QCoreApplicationPrivate::theMainThreadId.storeRelaxed(data->threadId.loadRelaxed());
197 }
198 }
199 return data;
200}
201
202
204{
205}
206
207/*
208 QThreadPrivate
209*/
210
211extern "C" {
212typedef void *(*QtThreadCallback)(void *);
213}
214
215#endif // QT_CONFIG(thread)
216
218{
219 Q_UNUSED(data);
220#if defined(Q_OS_DARWIN)
221 bool ok = false;
222 int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
223 if (ok && value > 0)
225 else
226 return new QEventDispatcherUNIX;
227#elif defined(Q_OS_WASM)
228 return new QEventDispatcherWasm();
229#elif !defined(QT_NO_GLIB)
230 const bool isQtMainThread = data->thread.loadAcquire() == QCoreApplicationPrivate::mainThread();
231 if (qEnvironmentVariableIsEmpty("QT_NO_GLIB")
232 && (isQtMainThread || qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB"))
234 return new QEventDispatcherGlib;
235 else
236 return new QEventDispatcherUNIX;
237#else
238 return new QEventDispatcherUNIX;
239#endif
240}
241
242#if QT_CONFIG(thread)
243
244#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX))
245static void setCurrentThreadName(const char *name)
246{
247# if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
248 prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
249# elif defined(Q_OS_DARWIN)
250 pthread_setname_np(name);
251# elif defined(Q_OS_QNX)
252 pthread_setname_np(pthread_self(), name);
253# endif
254}
255#endif
256
257namespace {
258template <typename T>
259void terminate_on_exception(T &&t)
260{
261#ifndef QT_NO_EXCEPTIONS
262 try {
263#endif
264 std::forward<T>(t)();
265#ifndef QT_NO_EXCEPTIONS
266#ifdef __GLIBCXX__
267 // POSIX thread cancellation under glibc is implemented by throwing an exception
268 // of this type. Do what libstdc++ is doing and handle it specially in order not to
269 // abort the application if user's code calls a cancellation function.
270 } catch (abi::__forced_unwind &) {
271 throw;
272#endif // __GLIBCXX__
273 } catch (...) {
274 qTerminate();
275 }
276#endif // QT_NO_EXCEPTIONS
277}
278} // unnamed namespace
279
280void *QThreadPrivate::start(void *arg)
281{
282#ifdef PTHREAD_CANCEL_DISABLE
283 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, nullptr);
284#endif
285#if !defined(Q_OS_QNX) && !defined(Q_OS_VXWORKS)
286 // On QNX, calling finish() from a thread_local destructor causes the C
287 // library to hang.
288 // On VxWorks, its pthread implementation fails on call to `pthead_setspecific` which is made
289 // by first QObject constructor during `finish()`. This causes call to QThread::current, since
290 // QObject doesn't have parent, and since the pthread is already removed, it tries to set
291 // QThreadData for current pthread key, which crashes.
292 static thread_local
293#endif
294 auto cleanup = qScopeGuard([=] { finish(arg); });
295 terminate_on_exception([&] {
296 QThread *thr = reinterpret_cast<QThread *>(arg);
298
299 {
300 QMutexLocker locker(&thr->d_func()->mutex);
301
302 // do we need to reset the thread priority?
303 if (thr->d_func()->priority & ThreadPriorityResetFlag) {
304 thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
305 }
306
307 // threadId is set in QThread::start()
308 Q_ASSERT(pthread_equal(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()),
309 pthread_self()));
310 set_thread_data(data);
311
312 data->ref();
313 data->quitNow = thr->d_func()->exited;
314 }
315
316 data->ensureEventDispatcher();
317 data->eventDispatcher.loadRelaxed()->startingUp();
318
319#if (defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_OS_QNX))
320 {
321 // Sets the name of the current thread. We can only do this
322 // when the thread is starting, as we don't have a cross
323 // platform way of setting the name of an arbitrary thread.
324 if (Q_LIKELY(thr->d_func()->objectName.isEmpty()))
325 setCurrentThreadName(thr->metaObject()->className());
326 else
327 setCurrentThreadName(std::exchange(thr->d_func()->objectName, {}).toLocal8Bit());
328 }
329#endif
330
331 emit thr->started(QThread::QPrivateSignal());
332#ifdef PTHREAD_CANCEL_DISABLE
333 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, nullptr);
334 pthread_testcancel();
335#endif
336 thr->run();
337 });
338
339 // The qScopeGuard above call runs finish() below.
340 return nullptr;
341}
342
343void QThreadPrivate::finish(void *arg)
344{
345 terminate_on_exception([&] {
346 QThread *thr = reinterpret_cast<QThread *>(arg);
347 QThreadPrivate *d = thr->d_func();
348
349 QMutexLocker locker(&d->mutex);
350
351 d->isInFinish = true;
352 d->priority = QThread::InheritPriority;
353 void *data = &d->data->tls;
354 locker.unlock();
355 emit thr->finished(QThread::QPrivateSignal());
356 qCDebug(lcDeleteLater) << "Sending deferred delete events as part of finishing thread" << thr;
358 QThreadStorageData::finish((void **)data);
359 locker.relock();
360
361 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
362 if (eventDispatcher) {
363 d->data->eventDispatcher = nullptr;
364 locker.unlock();
365 eventDispatcher->closingDown();
366 delete eventDispatcher;
367 locker.relock();
368 }
369
370 d->running = false;
371 d->finished = true;
372 d->interruptionRequested.store(false, std::memory_order_relaxed);
373
374 d->isInFinish = false;
375 d->data->threadId.storeRelaxed(nullptr);
376
377 d->thread_done.wakeAll();
378 });
379}
380
381
382/**************************************************************************
383 ** QThread
384 *************************************************************************/
385
386/*
387 CI tests fails on ARM architectures if we try to use the assembler, so
388 stick to the pthread version there. The assembler would be
389
390 // http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0344k/Babeihid.html
391 asm volatile ("mrc p15, 0, %0, c13, c0, 3" : "=r" (tid));
392
393 and
394
395 // see glibc/sysdeps/aarch64/nptl/tls.h
396 asm volatile ("mrs %0, tpidr_el0" : "=r" (tid));
397
398 for 32 and 64bit versions, respectively.
399*/
400Qt::HANDLE QThread::currentThreadIdImpl() noexcept
401{
402 return to_HANDLE(pthread_self());
403}
404
405#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
406// LSB doesn't define _SC_NPROCESSORS_ONLN.
407# define _SC_NPROCESSORS_ONLN 84
408#endif
409
410#ifdef Q_OS_WASM
411int QThreadPrivate::idealThreadCount = 1;
412#endif
413
414int QThread::idealThreadCount() noexcept
415{
416 int cores = 1;
417
418#if defined(Q_OS_HPUX)
419 // HP-UX
420 struct pst_dynamic psd;
421 if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
422 perror("pstat_getdynamic");
423 } else {
424 cores = (int)psd.psd_proc_cnt;
425 }
426#elif (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_FREEBSD)
427# if defined(Q_OS_FREEBSD) && !defined(CPU_COUNT_S)
428# define CPU_COUNT_S(setsize, cpusetp) ((int)BIT_COUNT(setsize, cpusetp))
429 // match the Linux API for simplicity
430 using cpu_set_t = cpuset_t;
431 auto sched_getaffinity = [](pid_t, size_t cpusetsize, cpu_set_t *mask) {
432 return cpuset_getaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, -1, cpusetsize, mask);
433 };
434# endif
435
436 // get the number of threads we're assigned, not the total in the system
437 QVarLengthArray<cpu_set_t, 1> cpuset(1);
438 int size = 1;
439 if (Q_UNLIKELY(sched_getaffinity(0, sizeof(cpu_set_t), cpuset.data()) < 0)) {
440 for (size = 2; size <= 4; size *= 2) {
441 cpuset.resize(size);
442 if (sched_getaffinity(0, sizeof(cpu_set_t) * size, cpuset.data()) == 0)
443 break;
444 }
445 if (size > 4)
446 return 1;
447 }
448 cores = CPU_COUNT_S(sizeof(cpu_set_t) * size, cpuset.data());
449#elif defined(Q_OS_BSD4)
450 // OpenBSD, NetBSD, BSD/OS, Darwin (macOS, iOS, etc.)
451 size_t len = sizeof(cores);
452 int mib[2];
453 mib[0] = CTL_HW;
454 mib[1] = HW_NCPU;
455 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
456 perror("sysctl");
457 }
458#elif defined(Q_OS_INTEGRITY)
459#if (__INTEGRITY_MAJOR_VERSION >= 10)
460 // Integrity V10+ does support multicore CPUs
461 Value processorCount;
462 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
463 cores = processorCount;
464 else
465#endif
466 // as of aug 2008 Integrity only supports one single core CPU
467 cores = 1;
468#elif defined(Q_OS_VXWORKS)
469 // VxWorks
470# if defined(QT_VXWORKS_HAS_CPUSET)
471 cpuset_t cpus = vxCpuEnabledGet();
472 cores = 0;
473
474 // 128 cores should be enough for everyone ;)
475 for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
476 if (CPUSET_ISSET(cpus, i)) {
477 CPUSET_CLR(cpus, i);
478 cores++;
479 }
480 }
481# else
482 // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
483 cores = 1;
484# endif
485#elif defined(Q_OS_WASM)
486 cores = QThreadPrivate::idealThreadCount;
487#else
488 // the rest: Solaris, AIX, Tru64
489 cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
490 if (cores == -1)
491 return 1;
492#endif
493 return cores;
494}
495
497{
498 sched_yield();
499}
500
501#endif // QT_CONFIG(thread)
502
503static void qt_nanosleep(timespec amount)
504{
505 // We'd like to use clock_nanosleep.
506 //
507 // But clock_nanosleep is from POSIX.1-2001 and both are *not*
508 // affected by clock changes when using relative sleeps, even for
509 // CLOCK_REALTIME.
510 //
511 // nanosleep is POSIX.1-1993
512
513 int r;
514 QT_EINTR_LOOP(r, nanosleep(&amount, &amount));
515}
516
517void QThread::sleep(unsigned long secs)
518{
519 sleep(std::chrono::seconds{secs});
520}
521
522void QThread::msleep(unsigned long msecs)
523{
524 sleep(std::chrono::milliseconds{msecs});
525}
526
527void QThread::usleep(unsigned long usecs)
528{
529 sleep(std::chrono::microseconds{usecs});
530}
531
532void QThread::sleep(std::chrono::nanoseconds nsec)
533{
535}
536
537#if QT_CONFIG(thread)
538
539#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
540#if defined(Q_OS_QNX)
541static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
542{
543 // On QNX, NormalPriority is mapped to 10. A QNX system could use a value different
544 // than 10 for the "normal" priority but it's difficult to achieve this so we'll
545 // assume that no one has ever created such a system. This makes the mapping from
546 // Qt priorities to QNX priorities lopsided. There's usually more space available
547 // to map into above the "normal" priority than below it. QNX also has a privileged
548 // priority range (for threads that assist the kernel). We'll assume that no Qt
549 // thread needs to use priorities in that range.
550 int priority_norm = 10;
551 // _sched_info::priority_priv isn't documented. You'd think that it's the start of the
552 // privileged priority range but it's actually the end of the unpriviledged range.
553 struct _sched_info info;
554 if (SchedInfo_r(0, *sched_policy, &info) != EOK)
555 return false;
556
557 if (priority == QThread::IdlePriority) {
558 *sched_priority = info.priority_min;
559 return true;
560 }
561
562 if (priority_norm < info.priority_min)
563 priority_norm = info.priority_min;
564 if (priority_norm > info.priority_priv)
565 priority_norm = info.priority_priv;
566
567 int to_min, to_max;
568 int from_min, from_max;
569 int prio;
570 if (priority < QThread::NormalPriority) {
571 to_min = info.priority_min;
572 to_max = priority_norm;
573 from_min = QThread::LowestPriority;
574 from_max = QThread::NormalPriority;
575 } else {
576 to_min = priority_norm;
577 to_max = info.priority_priv;
578 from_min = QThread::NormalPriority;
580 }
581
582 prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
583 prio = qBound(to_min, prio, to_max);
584
585 *sched_priority = prio;
586 return true;
587}
588#else
589// Does some magic and calculate the Unix scheduler priorities
590// sched_policy is IN/OUT: it must be set to a valid policy before calling this function
591// sched_priority is OUT only
592static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
593{
594#ifdef SCHED_IDLE
595 if (priority == QThread::IdlePriority) {
596 *sched_policy = SCHED_IDLE;
597 *sched_priority = 0;
598 return true;
599 }
600 const int lowestPriority = QThread::LowestPriority;
601#else
602 const int lowestPriority = QThread::IdlePriority;
603#endif
604 const int highestPriority = QThread::TimeCriticalPriority;
605
606 int prio_min;
607 int prio_max;
608#if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM)
609 // for other scheduling policies than SCHED_RR or SCHED_FIFO
610 prio_min = SCHED_FIFO_LOW_PRI;
611 prio_max = SCHED_FIFO_HIGH_PRI;
612
613 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
614#endif
615 {
616 prio_min = sched_get_priority_min(*sched_policy);
617 prio_max = sched_get_priority_max(*sched_policy);
618 }
619
620 if (prio_min == -1 || prio_max == -1)
621 return false;
622
623 int prio;
624 // crudely scale our priority enum values to the prio_min/prio_max
625 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
626 prio = qMax(prio_min, qMin(prio_max, prio));
627
628 *sched_priority = prio;
629 return true;
630}
631#endif
632#endif
633
634void QThread::start(Priority priority)
635{
636 Q_D(QThread);
637 QMutexLocker locker(&d->mutex);
638
639 if (d->isInFinish)
640 d->thread_done.wait(locker.mutex());
641
642 if (d->running)
643 return;
644
645 d->running = true;
646 d->finished = false;
647 d->returnCode = 0;
648 d->exited = false;
649 d->interruptionRequested.store(false, std::memory_order_relaxed);
650
651 pthread_attr_t attr;
652 pthread_attr_init(&attr);
653 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
654
655 d->priority = priority;
656
657#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
658 switch (priority) {
659 case InheritPriority:
660 {
661 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
662 break;
663 }
664
665 default:
666 {
667 int sched_policy;
668 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
669 // failed to get the scheduling policy, don't bother
670 // setting the priority
671 qWarning("QThread::start: Cannot determine default scheduler policy");
672 break;
673 }
674
675 int prio;
676 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
677 // failed to get the scheduling parameters, don't
678 // bother setting the priority
679 qWarning("QThread::start: Cannot determine scheduler priority range");
680 break;
681 }
682
683 sched_param sp;
684 sp.sched_priority = prio;
685
686 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
687 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
688 || pthread_attr_setschedparam(&attr, &sp) != 0) {
689 // could not set scheduling hints, fallback to inheriting them
690 // we'll try again from inside the thread
691 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
692 d->priority = qToUnderlying(priority) | ThreadPriorityResetFlag;
693 }
694 break;
695 }
696 }
697#endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
698
699
700 if (d->stackSize > 0) {
701#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
702 int code = pthread_attr_setstacksize(&attr, d->stackSize);
703#else
704 int code = ENOSYS; // stack size not supported, automatically fail
705#endif // _POSIX_THREAD_ATTR_STACKSIZE
706
707 if (code) {
708 qErrnoWarning(code, "QThread::start: Thread stack size error");
709
710 // we failed to set the stacksize, and as the documentation states,
711 // the thread will fail to run...
712 d->running = false;
713 d->finished = false;
714 return;
715 }
716 }
717
718#ifdef Q_OS_INTEGRITY
719 if (Q_LIKELY(objectName().isEmpty()))
720 pthread_attr_setthreadname(&attr, metaObject()->className());
721 else
722 pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
723#else
724 // avoid interacting with the binding system
725 d->objectName = d->extraData ? d->extraData->objectName.valueBypassingBindings()
726 : QString();
727#endif
728
729 pthread_t threadId;
730 int code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
731 if (code == EPERM) {
732 // caller does not have permission to set the scheduling
733 // parameters/policy
734#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
735 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
736#endif
737 code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
738 }
739 d->data->threadId.storeRelaxed(to_HANDLE(threadId));
740
741 pthread_attr_destroy(&attr);
742
743 if (code) {
744 qErrnoWarning(code, "QThread::start: Thread creation error");
745
746 d->running = false;
747 d->finished = false;
748 d->data->threadId.storeRelaxed(nullptr);
749 }
750}
751
753{
754#if !defined(Q_OS_ANDROID)
755 Q_D(QThread);
756 QMutexLocker locker(&d->mutex);
757
758 if (!d->data->threadId.loadRelaxed())
759 return;
760
761 int code = pthread_cancel(from_HANDLE<pthread_t>(d->data->threadId.loadRelaxed()));
762 if (code) {
763 qErrnoWarning(code, "QThread::start: Thread termination error");
764 }
765#endif
766}
767
769{
770 Q_D(QThread);
771 QMutexLocker locker(&d->mutex);
772
773 if (from_HANDLE<pthread_t>(d->data->threadId.loadRelaxed()) == pthread_self()) {
774 qWarning("QThread::wait: Thread tried to wait on itself");
775 return false;
776 }
777
778 if (d->finished || !d->running)
779 return true;
780
781 while (d->running) {
782 if (!d->thread_done.wait(locker.mutex(), deadline))
783 return false;
784 }
785 Q_ASSERT(d->data->threadId.loadRelaxed() == nullptr);
786
787 return true;
788}
789
791{
792 QThread *thr = currentThread();
793 Q_ASSERT_X(thr != nullptr, "QThread::setTerminationEnabled()",
794 "Current thread was not started with QThread.");
795
796 Q_UNUSED(thr);
797#if defined(Q_OS_ANDROID)
799#else
800 pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, nullptr);
801 if (enabled)
802 pthread_testcancel();
803#endif
804}
805
806// Caller must lock the mutex
807void QThreadPrivate::setPriority(QThread::Priority threadPriority)
808{
809 priority = threadPriority;
810
811 // copied from start() with a few modifications:
812
813#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
814 int sched_policy;
815 sched_param param;
816
817 if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, &param) != 0) {
818 // failed to get the scheduling policy, don't bother setting
819 // the priority
820 qWarning("QThread::setPriority: Cannot get scheduler parameters");
821 return;
822 }
823
824 int prio;
825 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
826 // failed to get the scheduling parameters, don't
827 // bother setting the priority
828 qWarning("QThread::setPriority: Cannot determine scheduler priority range");
829 return;
830 }
831
832 param.sched_priority = prio;
833 int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, &param);
834
835# ifdef SCHED_IDLE
836 // were we trying to set to idle priority and failed?
837 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
838 // reset to lowest priority possible
839 pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, &param);
840 param.sched_priority = sched_get_priority_min(sched_policy);
841 pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, &param);
842 }
843# else
844 Q_UNUSED(status);
845# endif // SCHED_IDLE
846#endif
847}
848
849#endif // QT_CONFIG(thread)
850
852
static QBasicAtomicPointer< void > theMainThreadId
static QThread * mainThread()
static QBasicAtomicPointer< QThread > theMainThread
static void sendPostedEvents(QObject *receiver=nullptr, int event_type=0)
Immediately dispatches all events which have been previously queued with QCoreApplication::postEvent(...
\inmodule QtCore
@ DeferredDelete
Definition qcoreevent.h:100
\inmodule QtCore
Definition qmutex.h:313
static QObjectPrivate * get(QObject *o)
Definition qobject_p.h:150
QString objectName
the name of this object
Definition qobject.h:107
QThread * thread() const
Returns the thread in which the object lives.
Definition qobject.cpp:1598
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
static Q_AUTOTEST_EXPORT QThreadData * current(bool createIfNecessary=true)
Definition qthread.cpp:1087
QThreadData(int initialRefCount=1)
Definition qthread.cpp:48
static void clearCurrentThreadData()
Definition qthread.cpp:1103
static QThreadData * get2(QThread *thread)
Definition qthread_p.h:291
static QAbstractEventDispatcher * createEventDispatcher(QThreadData *data)
void terminate()
Definition qthread.cpp:1003
void start(Priority=InheritPriority)
Definition qthread.cpp:996
static int idealThreadCount() noexcept
Definition qthread.cpp:1049
static QThread * currentThread()
Definition qthread.cpp:1039
static void setTerminationEnabled(bool enabled=true)
Definition qthread.cpp:1080
@ LowestPriority
Definition qthread.h:43
@ TimeCriticalPriority
Definition qthread.h:49
@ InheritPriority
Definition qthread.h:51
@ IdlePriority
Definition qthread.h:41
@ NormalPriority
Definition qthread.h:45
static void yieldCurrentThread()
Definition qthread.cpp:1054
bool wait(QDeadlineTimer deadline=QDeadlineTimer(QDeadlineTimer::Forever))
Definition qthread.cpp:1023
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.
void * HANDLE
#define Q_UNLIKELY(x)
#define Q_LIKELY(x)
#define QT_EINTR_LOOP(var, cmd)
timespec durationToTimespec(std::chrono::nanoseconds timeout) noexcept
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
QT_BEGIN_NAMESPACE Q_NORETURN void qTerminate() noexcept
#define QT_RETHROW
#define QT_CATCH(A)
#define QT_TRY
INT_PTR intptr_t
#define qWarning
Definition qlogging.h:166
#define qCDebug(category,...)
constexpr const T & qMin(const T &a, const T &b)
Definition qminmax.h:40
constexpr const T & qBound(const T &min, const T &val, const T &max)
Definition qminmax.h:44
constexpr const T & qMax(const T &a, const T &b)
Definition qminmax.h:42
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLboolean r
[2]
GLenum GLuint id
[7]
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLenum GLsizei const GLuint GLboolean enabled
GLenum type
GLenum const GLint * param
GLuint name
GLint GLint GLint GLint GLint GLint GLint GLbitfield mask
GLdouble GLdouble t
Definition qopenglext.h:243
GLfloat GLfloat p
[1]
GLenum GLsizei len
#define Q_ASSERT(cond)
Definition qrandom.cpp:47
#define Q_ASSERT_X(cond, x, msg)
Definition qrandom.cpp:48
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
Definition qscopeguard.h:60
SSL_CTX int void * arg
static char * toLocal8Bit(char *out, QStringView in, QStringConverter::State *state)
#define sp
Q_CORE_EXPORT bool qEnvironmentVariableIsEmpty(const char *varName) noexcept
Q_CORE_EXPORT int qEnvironmentVariableIntValue(const char *varName, bool *ok=nullptr) noexcept
static void qt_nanosleep(timespec amount)
#define emit
#define Q_UNUSED(x)
QT_BEGIN_NAMESPACE constexpr std::underlying_type_t< Enum > qToUnderlying(Enum e) noexcept
const char className[16]
[1]
Definition qwizard.cpp:100
QDeadlineTimer deadline(30s)
obj metaObject() -> className()
QObject::connect nullptr
QHostInfo info
[0]