1/****************************************************************************
2**
3** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4** Contact: http://www.qt-project.org/legal
5**
6** This file is part of the QtCore module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Digia. For licensing terms and
14** conditions see http://qt.digia.com/licensing. For further information
15** use the contact form at http://qt.digia.com/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 2.1 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 2.1 requirements
23** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24**
25** In addition, as a special exception, Digia gives you certain additional
26** rights. These rights are described in the Digia Qt LGPL Exception
27** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28**
29** GNU General Public License Usage
30** Alternatively, this file may be used under the terms of the GNU
31** General Public License version 3.0 as published by the Free Software
32** Foundation and appearing in the file LICENSE.GPL included in the
33** packaging of this file. Please review the following information to
34** ensure the GNU General Public License version 3.0 requirements will be
35** met: http://www.gnu.org/copyleft/gpl.html.
36**
37**
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include "qthread.h"
43
44#include "qplatformdefs.h"
45
46#include <private/qcoreapplication_p.h>
47
48#if defined(Q_OS_BLACKBERRY)
49# include <private/qeventdispatcher_blackberry_p.h>
50#else
51# if !defined(QT_NO_GLIB)
52# include "../kernel/qeventdispatcher_glib_p.h"
53# endif
54# include <private/qeventdispatcher_unix_p.h>
55#endif
56
57#include "qthreadstorage.h"
58
59#include "qthread_p.h"
60
61#include "qdebug.h"
62
63#include <sched.h>
64#include <errno.h>
65
66#ifdef Q_OS_BSD4
67#include <sys/sysctl.h>
68#endif
69#ifdef Q_OS_VXWORKS
70# if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
71# include <vxCpuLib.h>
72# include <cpuset.h>
73# define QT_VXWORKS_HAS_CPUSET
74# endif
75#endif
76
77#ifdef Q_OS_HPUX
78#include <sys/pstat.h>
79#endif
80
81#if defined(Q_OS_MAC)
82# ifdef qDebug
83# define old_qDebug qDebug
84# undef qDebug
85# endif
86#if !defined(Q_OS_IOS)
87# include <CoreServices/CoreServices.h>
88#endif // !defined(Q_OS_IOS)
89
90# ifdef old_qDebug
91# undef qDebug
92# define qDebug QT_NO_QDEBUG_MACRO
93# undef old_qDebug
94# endif
95#endif
96
97#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
98#include <sys/prctl.h>
99#endif
100
101#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE)
102// from linux/sched.h
103# define SCHED_IDLE 5
104#endif
105
106#if defined(Q_OS_DARWIN) || !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
107#define QT_HAS_THREAD_PRIORITY_SCHEDULING
108#endif
109
110
111QT_BEGIN_NAMESPACE
112
113#ifndef QT_NO_THREAD
114
115enum { ThreadPriorityResetFlag = 0x80000000 };
116
117#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL))
118#define HAVE_TLS
119#endif
120#if defined(Q_CC_XLC) || defined (Q_CC_SUN)
121#define HAVE_TLS
122#endif
123
124#ifdef HAVE_TLS
125static __thread QThreadData *currentThreadData = 0;
126#endif
127
128static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT;
129static pthread_key_t current_thread_data_key;
130
131static void destroy_current_thread_data(void *p)
132{
133#if defined(Q_OS_VXWORKS)
134 // Calling setspecific(..., 0) sets the value to 0 for ALL threads.
135 // The 'set to 1' workaround adds a bit of an overhead though,
136 // since this function is called twice now.
137 if (p == (void *)1)
138 return;
139#endif
140 // POSIX says the value in our key is set to zero before calling
141 // this destructor function, so we need to set it back to the
142 // right value...
143 pthread_setspecific(current_thread_data_key, p);
144 QThreadData *data = static_cast<QThreadData *>(p);
145 if (data->isAdopted) {
146 QThread *thread = data->thread;
147 Q_ASSERT(thread);
148 QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
149 Q_ASSERT(!thread_p->finished);
150 thread_p->finish(thread);
151 }
152 data->deref();
153
154 // ... but we must reset it to zero before returning so we aren't
155 // called again (POSIX allows implementations to call destructor
156 // functions repeatedly until all values are zero)
157 pthread_setspecific(current_thread_data_key,
158#if defined(Q_OS_VXWORKS)
159 (void *)1);
160#else
161 0);
162#endif
163}
164
165static void create_current_thread_data_key()
166{
167 pthread_key_create(&current_thread_data_key, destroy_current_thread_data);
168}
169
170static void destroy_current_thread_data_key()
171{
172 pthread_once(&current_thread_data_once, create_current_thread_data_key);
173 pthread_key_delete(current_thread_data_key);
174
175 // Reset current_thread_data_once in case we end up recreating
176 // the thread-data in the rare case of QObject construction
177 // after destroying the QThreadData.
178 pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT;
179 current_thread_data_once = pthread_once_init;
180}
181Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)
182
183
184// Utility functions for getting, setting and clearing thread specific data.
185static QThreadData *get_thread_data()
186{
187#ifdef HAVE_TLS
188 return currentThreadData;
189#else
190 pthread_once(&current_thread_data_once, create_current_thread_data_key);
191 return reinterpret_cast<QThreadData *>(pthread_getspecific(current_thread_data_key));
192#endif
193}
194
195static void set_thread_data(QThreadData *data)
196{
197#ifdef HAVE_TLS
198 currentThreadData = data;
199#endif
200 pthread_once(&current_thread_data_once, create_current_thread_data_key);
201 pthread_setspecific(current_thread_data_key, data);
202}
203
204static void clear_thread_data()
205{
206#ifdef HAVE_TLS
207 currentThreadData = 0;
208#endif
209 pthread_setspecific(current_thread_data_key, 0);
210}
211
212void QThreadData::clearCurrentThreadData()
213{
214 clear_thread_data();
215}
216
217QThreadData *QThreadData::current()
218{
219 QThreadData *data = get_thread_data();
220 if (!data) {
221 void *a;
222 if (QInternal::activateCallbacks(QInternal::AdoptCurrentThread, &a)) {
223 QThread *adopted = static_cast<QThread*>(a);
224 Q_ASSERT(adopted);
225 data = QThreadData::get2(adopted);
226 set_thread_data(data);
227 adopted->d_func()->running = true;
228 adopted->d_func()->finished = false;
229 static_cast<QAdoptedThread *>(adopted)->init();
230 } else {
231 data = new QThreadData;
232 QT_TRY {
233 set_thread_data(data);
234 data->thread = new QAdoptedThread(data);
235 } QT_CATCH(...) {
236 clear_thread_data();
237 data->deref();
238 data = 0;
239 QT_RETHROW;
240 }
241 data->deref();
242 }
243 data->isAdopted = true;
244 data->threadId = (Qt::HANDLE)pthread_self();
245 if (!QCoreApplicationPrivate::theMainThread)
246 QCoreApplicationPrivate::theMainThread = data->thread;
247 }
248 return data;
249}
250
251
252void QAdoptedThread::init()
253{
254 Q_D(QThread);
255 d->thread_id = pthread_self();
256}
257
258/*
259 QThreadPrivate
260*/
261
262#if defined(Q_C_CALLBACKS)
263extern "C" {
264#endif
265
266typedef void*(*QtThreadCallback)(void*);
267
268#if defined(Q_C_CALLBACKS)
269}
270#endif
271
272#endif // QT_NO_THREAD
273
274void QThreadPrivate::createEventDispatcher(QThreadData *data)
275{
276#if defined(Q_OS_BLACKBERRY)
277 data->eventDispatcher = new QEventDispatcherBlackberry;
278#else
279#if !defined(QT_NO_GLIB)
280 if (qgetenv("QT_NO_GLIB").isEmpty()
281 && qgetenv("QT_NO_THREADED_GLIB").isEmpty()
282 && QEventDispatcherGlib::versionSupported())
283 data->eventDispatcher = new QEventDispatcherGlib;
284 else
285#endif
286 data->eventDispatcher = new QEventDispatcherUNIX;
287#endif
288
289 data->eventDispatcher->startingUp();
290}
291
292#ifndef QT_NO_THREAD
293
294#if (defined(Q_OS_LINUX) || (defined(Q_OS_MAC) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) || defined(Q_OS_QNX))
295static void setCurrentThreadName(pthread_t threadId, const char *name)
296{
297# if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
298 Q_UNUSED(threadId);
299 prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
300# elif (defined(Q_OS_MAC) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6)
301 Q_UNUSED(threadId);
302 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_6)
303 pthread_setname_np(name);
304# elif defined(Q_OS_QNX)
305 pthread_setname_np(threadId, name);
306# endif
307}
308#endif
309
310void *QThreadPrivate::start(void *arg)
311{
312 pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
313 pthread_cleanup_push(QThreadPrivate::finish, arg);
314
315 QThread *thr = reinterpret_cast<QThread *>(arg);
316 QThreadData *data = QThreadData::get2(thr);
317
318 // do we need to reset the thread priority?
319 if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
320 thr->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
321 }
322
323 data->threadId = (Qt::HANDLE)pthread_self();
324 set_thread_data(data);
325
326 data->ref();
327 {
328 QMutexLocker locker(&thr->d_func()->mutex);
329 data->quitNow = thr->d_func()->exited;
330 }
331
332 // ### TODO: allow the user to create a custom event dispatcher
333 createEventDispatcher(data);
334
335#if (defined(Q_OS_LINUX) || (defined(Q_OS_MAC) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6) || defined(Q_OS_QNX))
336 // sets the name of the current thread.
337 QString objectName = thr->objectName();
338
339 if (Q_LIKELY(objectName.isEmpty()))
340 setCurrentThreadName(thr->d_func()->thread_id, thr->metaObject()->className());
341 else
342 setCurrentThreadName(thr->d_func()->thread_id, objectName.toLocal8Bit());
343
344#endif
345
346 emit thr->started();
347 pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
348 pthread_testcancel();
349 thr->run();
350
351 pthread_cleanup_pop(1);
352
353 return 0;
354}
355
356void QThreadPrivate::finish(void *arg)
357{
358 QThread *thr = reinterpret_cast<QThread *>(arg);
359 QThreadPrivate *d = thr->d_func();
360
361 QMutexLocker locker(&d->mutex);
362
363 d->isInFinish = true;
364 d->priority = QThread::InheritPriority;
365 bool terminated = d->terminated;
366 void *data = &d->data->tls;
367 locker.unlock();
368 if (terminated)
369 emit thr->terminated();
370 emit thr->finished();
371 QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
372 QThreadStorageData::finish((void **)data);
373 locker.relock();
374 d->terminated = false;
375
376 QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher;
377 if (eventDispatcher) {
378 d->data->eventDispatcher = 0;
379 locker.unlock();
380 eventDispatcher->closingDown();
381 delete eventDispatcher;
382 locker.relock();
383 }
384
385 d->thread_id = 0;
386 d->running = false;
387 d->finished = true;
388
389 d->isInFinish = false;
390 d->thread_done.wakeAll();
391}
392
393
394
395
396/**************************************************************************
397 ** QThread
398 *************************************************************************/
399
400Qt::HANDLE QThread::currentThreadId()
401{
402 // requires a C cast here otherwise we run into trouble on AIX
403 return (Qt::HANDLE)pthread_self();
404}
405
406#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
407// LSB doesn't define _SC_NPROCESSORS_ONLN.
408# define _SC_NPROCESSORS_ONLN 84
409#endif
410
411int QThread::idealThreadCount()
412{
413 int cores = -1;
414
415#if defined(Q_OS_MAC) && !defined(Q_WS_QPA)
416 // Mac OS X
417 cores = MPProcessorsScheduled();
418#elif 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 cores = -1;
424 } else {
425 cores = (int)psd.psd_proc_cnt;
426 }
427#elif defined(Q_OS_BSD4)
428 // FreeBSD, OpenBSD, NetBSD, BSD/OS
429 size_t len = sizeof(cores);
430 int mib[2];
431 mib[0] = CTL_HW;
432 mib[1] = HW_NCPU;
433 if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
434 perror("sysctl");
435 cores = -1;
436 }
437#elif defined(Q_OS_IRIX)
438 // IRIX
439 cores = (int)sysconf(_SC_NPROC_ONLN);
440#elif defined(Q_OS_INTEGRITY)
441#if (__INTEGRITY_MAJOR_VERSION >= 10)
442 // Integrity V10+ does support multicore CPUs
443 Value processorCount;
444 if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
445 cores = processorCount;
446 else
447#endif
448 cores = 1;
449#elif defined(Q_OS_VXWORKS)
450 // VxWorks
451# if defined(QT_VXWORKS_HAS_CPUSET)
452 cpuset_t cpus = vxCpuEnabledGet();
453 cores = 0;
454
455 // 128 cores should be enough for everyone ;)
456 for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
457 if (CPUSET_ISSET(cpus, i)) {
458 CPUSET_CLR(cpus, i);
459 cores++;
460 }
461 }
462# else
463 // as of aug 2008 VxWorks < 6.6 only supports one single core CPU
464 cores = 1;
465# endif
466#else
467 // the rest: Linux, Solaris, AIX, Tru64
468 cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
469#endif
470
471 return cores;
472}
473
474void QThread::yieldCurrentThread()
475{
476 sched_yield();
477}
478
479/* \internal
480 helper function to do thread sleeps, since usleep()/nanosleep()
481 aren't reliable enough (in terms of behavior and availability)
482*/
483static void thread_sleep(struct timespec *ti)
484{
485 pthread_mutex_t mtx;
486 pthread_cond_t cnd;
487
488 pthread_mutex_init(&mtx, 0);
489 pthread_cond_init(&cnd, 0);
490
491 pthread_mutex_lock(&mtx);
492 (void) pthread_cond_timedwait(&cnd, &mtx, ti);
493 pthread_mutex_unlock(&mtx);
494
495 pthread_cond_destroy(&cnd);
496 pthread_mutex_destroy(&mtx);
497}
498
499void QThread::sleep(unsigned long secs)
500{
501 struct timeval tv;
502 gettimeofday(&tv, 0);
503 struct timespec ti;
504 ti.tv_sec = tv.tv_sec + secs;
505 ti.tv_nsec = (tv.tv_usec * 1000);
506 thread_sleep(&ti);
507}
508
509void QThread::msleep(unsigned long msecs)
510{
511 struct timeval tv;
512 gettimeofday(&tv, 0);
513 struct timespec ti;
514
515 ti.tv_nsec = (tv.tv_usec + (msecs % 1000) * 1000) * 1000;
516 ti.tv_sec = tv.tv_sec + (msecs / 1000) + (ti.tv_nsec / 1000000000);
517 ti.tv_nsec %= 1000000000;
518 thread_sleep(&ti);
519}
520
521void QThread::usleep(unsigned long usecs)
522{
523 struct timeval tv;
524 gettimeofday(&tv, 0);
525 struct timespec ti;
526
527 ti.tv_nsec = (tv.tv_usec + (usecs % 1000000)) * 1000;
528 ti.tv_sec = tv.tv_sec + (usecs / 1000000) + (ti.tv_nsec / 1000000000);
529 ti.tv_nsec %= 1000000000;
530 thread_sleep(&ti);
531}
532
533#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
534// Does some magic and calculate the Unix scheduler priorities
535// sched_policy is IN/OUT: it must be set to a valid policy before calling this function
536// sched_priority is OUT only
537static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
538{
539#ifdef Q_OS_QNX
540 // without Round Robin drawn intensive apps will hog the cpu
541 // and make the system appear frozen
542 *sched_policy = SCHED_RR;
543#endif
544#ifdef SCHED_IDLE
545 if (priority == QThread::IdlePriority) {
546 *sched_policy = SCHED_IDLE;
547 *sched_priority = 0;
548 return true;
549 }
550 const int lowestPriority = QThread::LowestPriority;
551#else
552 const int lowestPriority = QThread::IdlePriority;
553#endif
554 const int highestPriority = QThread::TimeCriticalPriority;
555
556 int prio_min;
557 int prio_max;
558#if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM)
559 // for other scheduling policies than SCHED_RR or SCHED_FIFO
560 prio_min = SCHED_FIFO_LOW_PRI;
561 prio_max = SCHED_FIFO_HIGH_PRI;
562
563 if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
564#endif
565 {
566 prio_min = sched_get_priority_min(*sched_policy);
567 prio_max = sched_get_priority_max(*sched_policy);
568 }
569
570 if (prio_min == -1 || prio_max == -1)
571 return false;
572
573 int prio;
574 // crudely scale our priority enum values to the prio_min/prio_max
575 prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
576 prio = qMax(prio_min, qMin(prio_max, prio));
577
578 *sched_priority = prio;
579 return true;
580}
581#endif
582
583void QThread::start(Priority priority)
584{
585 Q_D(QThread);
586 QMutexLocker locker(&d->mutex);
587
588 if (d->isInFinish)
589 d->thread_done.wait(locker.mutex());
590
591 if (d->running)
592 return;
593
594 d->running = true;
595 d->finished = false;
596 d->terminated = false;
597 d->returnCode = 0;
598 d->exited = false;
599
600 pthread_attr_t attr;
601 pthread_attr_init(&attr);
602 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
603
604 d->priority = priority;
605
606#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
607 switch (priority) {
608 case InheritPriority:
609 {
610 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
611 break;
612 }
613
614 default:
615 {
616 int sched_policy;
617 if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
618 // failed to get the scheduling policy, don't bother
619 // setting the priority
620 qWarning("QThread::start: Cannot determine default scheduler policy");
621 break;
622 }
623
624 int prio;
625 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
626 // failed to get the scheduling parameters, don't
627 // bother setting the priority
628 qWarning("QThread::start: Cannot determine scheduler priority range");
629 break;
630 }
631
632 sched_param sp;
633 sp.sched_priority = prio;
634
635 if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
636 || pthread_attr_setschedpolicy(&attr, sched_policy) != 0
637 || pthread_attr_setschedparam(&attr, &sp) != 0) {
638 // could not set scheduling hints, fallback to inheriting them
639 // we'll try again from inside the thread
640 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
641 d->priority = Priority(priority | ThreadPriorityResetFlag);
642 }
643 break;
644 }
645 }
646#endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
647
648
649 if (d->stackSize > 0) {
650#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
651 int code = pthread_attr_setstacksize(&attr, d->stackSize);
652#else
653 int code = ENOSYS; // stack size not supported, automatically fail
654#endif // _POSIX_THREAD_ATTR_STACKSIZE
655
656 if (code) {
657 qWarning("QThread::start: Thread stack size error: %s",
658 qPrintable(qt_error_string(code)));
659
660 // we failed to set the stacksize, and as the documentation states,
661 // the thread will fail to run...
662 d->running = false;
663 d->finished = false;
664 return;
665 }
666 }
667
668 int code =
669 pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
670 if (code == EPERM) {
671 // caller does not have permission to set the scheduling
672 // parameters/policy
673 pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
674 code =
675 pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
676 }
677
678 pthread_attr_destroy(&attr);
679
680 if (code) {
681 qWarning("QThread::start: Thread creation error: %s", qPrintable(qt_error_string(code)));
682
683 d->running = false;
684 d->finished = false;
685 d->thread_id = 0;
686 }
687}
688
689void QThread::terminate()
690{
691 Q_D(QThread);
692 QMutexLocker locker(&d->mutex);
693
694 if (!d->thread_id)
695 return;
696
697 int code = pthread_cancel(d->thread_id);
698 if (code) {
699 qWarning("QThread::start: Thread termination error: %s",
700 qPrintable(qt_error_string((code))));
701 } else {
702 d->terminated = true;
703 }
704}
705
706bool QThread::wait(unsigned long time)
707{
708 Q_D(QThread);
709 QMutexLocker locker(&d->mutex);
710
711 if (d->thread_id == pthread_self()) {
712 qWarning("QThread::wait: Thread tried to wait on itself");
713 return false;
714 }
715
716 if (d->finished || !d->running)
717 return true;
718
719 while (d->running) {
720 if (!d->thread_done.wait(locker.mutex(), time))
721 return false;
722 }
723 return true;
724}
725
726void QThread::setTerminationEnabled(bool enabled)
727{
728 QThread *thr = currentThread();
729 Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
730 "Current thread was not started with QThread.");
731
732 Q_UNUSED(thr)
733 pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
734 if (enabled)
735 pthread_testcancel();
736}
737
738void QThread::setPriority(Priority priority)
739{
740 Q_D(QThread);
741 QMutexLocker locker(&d->mutex);
742 if (!d->running) {
743 qWarning("QThread::setPriority: Cannot set priority, thread is not running");
744 return;
745 }
746
747 d->priority = priority;
748
749 // copied from start() with a few modifications:
750
751#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
752 int sched_policy;
753 sched_param param;
754
755 if (pthread_getschedparam(d->thread_id, &sched_policy, &param) != 0) {
756 // failed to get the scheduling policy, don't bother setting
757 // the priority
758 qWarning("QThread::setPriority: Cannot get scheduler parameters");
759 return;
760 }
761
762 int prio;
763 if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
764 // failed to get the scheduling parameters, don't
765 // bother setting the priority
766 qWarning("QThread::setPriority: Cannot determine scheduler priority range");
767 return;
768 }
769
770 param.sched_priority = prio;
771 int status = pthread_setschedparam(d->thread_id, sched_policy, &param);
772
773# ifdef SCHED_IDLE
774 // were we trying to set to idle priority and failed?
775 if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
776 // reset to lowest priority possible
777 pthread_getschedparam(d->thread_id, &sched_policy, &param);
778 param.sched_priority = sched_get_priority_min(sched_policy);
779 pthread_setschedparam(d->thread_id, sched_policy, &param);
780 }
781# else
782 Q_UNUSED(status);
783# endif // SCHED_IDLE
784#endif
785}
786
787#endif // QT_NO_THREAD
788
789QT_END_NAMESPACE
790
791