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

source code of qtbase/src/corelib/thread/qthread_unix.cpp