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