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