blob: cb3c0d6bb182440a97d0a5c4bc6b1a66d3a6d35b [file] [log] [blame]
/****************************************************************************
**
** Copyright (C) 2016 The Qt Company Ltd.
** Copyright (C) 2016 Intel Corporation.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qthread.h"
#include "qplatformdefs.h"
#include <private/qcoreapplication_p.h>
#include <private/qcore_unix_p.h>
#if defined(Q_OS_DARWIN)
# include <private/qeventdispatcher_cf_p.h>
#else
# if !defined(QT_NO_GLIB)
# include "../kernel/qeventdispatcher_glib_p.h"
# endif
#endif
#include <private/qeventdispatcher_unix_p.h>
#include "qthreadstorage.h"
#include "qthread_p.h"
#include "qdebug.h"
#ifdef __GLIBCXX__
#include <cxxabi.h>
#endif
#include <sched.h>
#include <errno.h>
#ifdef Q_OS_BSD4
#include <sys/sysctl.h>
#endif
#ifdef Q_OS_VXWORKS
# if (_WRS_VXWORKS_MAJOR > 6) || ((_WRS_VXWORKS_MAJOR == 6) && (_WRS_VXWORKS_MINOR >= 6))
# include <vxCpuLib.h>
# include <cpuset.h>
# define QT_VXWORKS_HAS_CPUSET
# endif
#endif
#ifdef Q_OS_HPUX
#include <sys/pstat.h>
#endif
#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
#include <sys/prctl.h>
#endif
#if defined(Q_OS_LINUX) && !defined(SCHED_IDLE)
// from linux/sched.h
# define SCHED_IDLE 5
#endif
#if defined(Q_OS_DARWIN) || !defined(Q_OS_ANDROID) && !defined(Q_OS_OPENBSD) && defined(_POSIX_THREAD_PRIORITY_SCHEDULING) && (_POSIX_THREAD_PRIORITY_SCHEDULING-0 >= 0)
#define QT_HAS_THREAD_PRIORITY_SCHEDULING
#endif
#if defined(Q_OS_QNX)
#include <sys/neutrino.h>
#endif
QT_BEGIN_NAMESPACE
#if QT_CONFIG(thread)
Q_STATIC_ASSERT(sizeof(pthread_t) <= sizeof(Qt::HANDLE));
enum { ThreadPriorityResetFlag = 0x80000000 };
static thread_local QThreadData *currentThreadData = 0;
static pthread_once_t current_thread_data_once = PTHREAD_ONCE_INIT;
static pthread_key_t current_thread_data_key;
static void destroy_current_thread_data(void *p)
{
#if defined(Q_OS_VXWORKS)
// Calling setspecific(..., 0) sets the value to 0 for ALL threads.
// The 'set to 1' workaround adds a bit of an overhead though,
// since this function is called twice now.
if (p == (void *)1)
return;
#endif
// POSIX says the value in our key is set to zero before calling
// this destructor function, so we need to set it back to the
// right value...
pthread_setspecific(current_thread_data_key, p);
QThreadData *data = static_cast<QThreadData *>(p);
if (data->isAdopted) {
QThread *thread = data->thread.loadAcquire();
Q_ASSERT(thread);
QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
Q_ASSERT(!thread_p->finished);
thread_p->finish(thread);
}
data->deref();
// ... but we must reset it to zero before returning so we aren't
// called again (POSIX allows implementations to call destructor
// functions repeatedly until all values are zero)
pthread_setspecific(current_thread_data_key,
#if defined(Q_OS_VXWORKS)
(void *)1);
#else
0);
#endif
}
static void create_current_thread_data_key()
{
pthread_key_create(&current_thread_data_key, destroy_current_thread_data);
}
static void destroy_current_thread_data_key()
{
pthread_once(&current_thread_data_once, create_current_thread_data_key);
pthread_key_delete(current_thread_data_key);
// Reset current_thread_data_once in case we end up recreating
// the thread-data in the rare case of QObject construction
// after destroying the QThreadData.
pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT;
current_thread_data_once = pthread_once_init;
}
Q_DESTRUCTOR_FUNCTION(destroy_current_thread_data_key)
// Utility functions for getting, setting and clearing thread specific data.
static QThreadData *get_thread_data()
{
return currentThreadData;
}
static void set_thread_data(QThreadData *data)
{
currentThreadData = data;
pthread_once(&current_thread_data_once, create_current_thread_data_key);
pthread_setspecific(current_thread_data_key, data);
}
static void clear_thread_data()
{
currentThreadData = 0;
pthread_setspecific(current_thread_data_key, 0);
}
template <typename T>
static typename std::enable_if<QTypeInfo<T>::isIntegral, Qt::HANDLE>::type to_HANDLE(T id)
{
return reinterpret_cast<Qt::HANDLE>(static_cast<intptr_t>(id));
}
template <typename T>
static typename std::enable_if<QTypeInfo<T>::isIntegral, T>::type from_HANDLE(Qt::HANDLE id)
{
return static_cast<T>(reinterpret_cast<intptr_t>(id));
}
template <typename T>
static typename std::enable_if<QTypeInfo<T>::isPointer, Qt::HANDLE>::type to_HANDLE(T id)
{
return id;
}
template <typename T>
static typename std::enable_if<QTypeInfo<T>::isPointer, T>::type from_HANDLE(Qt::HANDLE id)
{
return static_cast<T>(id);
}
void QThreadData::clearCurrentThreadData()
{
clear_thread_data();
}
QThreadData *QThreadData::current(bool createIfNecessary)
{
QThreadData *data = get_thread_data();
if (!data && createIfNecessary) {
data = new QThreadData;
QT_TRY {
set_thread_data(data);
data->thread = new QAdoptedThread(data);
} QT_CATCH(...) {
clear_thread_data();
data->deref();
data = 0;
QT_RETHROW;
}
data->deref();
data->isAdopted = true;
data->threadId.storeRelaxed(to_HANDLE(pthread_self()));
if (!QCoreApplicationPrivate::theMainThread.loadAcquire())
QCoreApplicationPrivate::theMainThread.storeRelease(data->thread.loadRelaxed());
}
return data;
}
void QAdoptedThread::init()
{
}
/*
QThreadPrivate
*/
extern "C" {
typedef void*(*QtThreadCallback)(void*);
}
#endif // QT_CONFIG(thread)
QAbstractEventDispatcher *QThreadPrivate::createEventDispatcher(QThreadData *data)
{
Q_UNUSED(data);
#if defined(Q_OS_DARWIN)
bool ok = false;
int value = qEnvironmentVariableIntValue("QT_EVENT_DISPATCHER_CORE_FOUNDATION", &ok);
if (ok && value > 0)
return new QEventDispatcherCoreFoundation;
else
return new QEventDispatcherUNIX;
#elif !defined(QT_NO_GLIB)
const bool isQtMainThread = data->thread.loadAcquire() == QCoreApplicationPrivate::mainThread();
if (qEnvironmentVariableIsEmpty("QT_NO_GLIB")
&& (isQtMainThread || qEnvironmentVariableIsEmpty("QT_NO_THREADED_GLIB"))
&& QEventDispatcherGlib::versionSupported())
return new QEventDispatcherGlib;
else
return new QEventDispatcherUNIX;
#else
return new QEventDispatcherUNIX;
#endif
}
#if QT_CONFIG(thread)
#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
static void setCurrentThreadName(const char *name)
{
# if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0);
# elif defined(Q_OS_MAC)
pthread_setname_np(name);
# elif defined(Q_OS_QNX)
pthread_setname_np(pthread_self(), name);
# endif
}
#endif
void *QThreadPrivate::start(void *arg)
{
#if !defined(Q_OS_ANDROID)
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
#endif
pthread_cleanup_push(QThreadPrivate::finish, arg);
#ifndef QT_NO_EXCEPTIONS
try
#endif
{
QThread *thr = reinterpret_cast<QThread *>(arg);
QThreadData *data = QThreadData::get2(thr);
{
QMutexLocker locker(&thr->d_func()->mutex);
// do we need to reset the thread priority?
if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
thr->d_func()->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
}
data->threadId.storeRelaxed(to_HANDLE(pthread_self()));
set_thread_data(data);
data->ref();
data->quitNow = thr->d_func()->exited;
}
data->ensureEventDispatcher();
#if (defined(Q_OS_LINUX) || defined(Q_OS_MAC) || defined(Q_OS_QNX))
{
// Sets the name of the current thread. We can only do this
// when the thread is starting, as we don't have a cross
// platform way of setting the name of an arbitrary thread.
if (Q_LIKELY(thr->objectName().isEmpty()))
setCurrentThreadName(thr->metaObject()->className());
else
setCurrentThreadName(thr->objectName().toLocal8Bit());
}
#endif
emit thr->started(QThread::QPrivateSignal());
#if !defined(Q_OS_ANDROID)
pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
pthread_testcancel();
#endif
thr->run();
}
#ifndef QT_NO_EXCEPTIONS
#ifdef __GLIBCXX__
// POSIX thread cancellation under glibc is implemented by throwing an exception
// of this type. Do what libstdc++ is doing and handle it specially in order not to
// abort the application if user's code calls a cancellation function.
catch (const abi::__forced_unwind &) {
throw;
}
#endif // __GLIBCXX__
catch (...) {
qTerminate();
}
#endif // QT_NO_EXCEPTIONS
// This pop runs finish() below. It's outside the try/catch (and has its
// own try/catch) to prevent finish() to be run in case an exception is
// thrown.
pthread_cleanup_pop(1);
return 0;
}
void QThreadPrivate::finish(void *arg)
{
#ifndef QT_NO_EXCEPTIONS
try
#endif
{
QThread *thr = reinterpret_cast<QThread *>(arg);
QThreadPrivate *d = thr->d_func();
QMutexLocker locker(&d->mutex);
d->isInFinish = true;
d->priority = QThread::InheritPriority;
void *data = &d->data->tls;
locker.unlock();
emit thr->finished(QThread::QPrivateSignal());
QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
QThreadStorageData::finish((void **)data);
locker.relock();
QAbstractEventDispatcher *eventDispatcher = d->data->eventDispatcher.loadRelaxed();
if (eventDispatcher) {
d->data->eventDispatcher = 0;
locker.unlock();
eventDispatcher->closingDown();
delete eventDispatcher;
locker.relock();
}
d->running = false;
d->finished = true;
d->interruptionRequested = false;
d->isInFinish = false;
d->thread_done.wakeAll();
}
#ifndef QT_NO_EXCEPTIONS
#ifdef __GLIBCXX__
// POSIX thread cancellation under glibc is implemented by throwing an exception
// of this type. Do what libstdc++ is doing and handle it specially in order not to
// abort the application if user's code calls a cancellation function.
catch (const abi::__forced_unwind &) {
throw;
}
#endif // __GLIBCXX__
catch (...) {
qTerminate();
}
#endif // QT_NO_EXCEPTIONS
}
/**************************************************************************
** QThread
*************************************************************************/
Qt::HANDLE QThread::currentThreadId() noexcept
{
// requires a C cast here otherwise we run into trouble on AIX
return to_HANDLE(pthread_self());
}
#if defined(QT_LINUXBASE) && !defined(_SC_NPROCESSORS_ONLN)
// LSB doesn't define _SC_NPROCESSORS_ONLN.
# define _SC_NPROCESSORS_ONLN 84
#endif
#ifdef Q_OS_WASM
int QThreadPrivate::idealThreadCount = 1;
#endif
int QThread::idealThreadCount() noexcept
{
int cores = 1;
#if defined(Q_OS_HPUX)
// HP-UX
struct pst_dynamic psd;
if (pstat_getdynamic(&psd, sizeof(psd), 1, 0) == -1) {
perror("pstat_getdynamic");
} else {
cores = (int)psd.psd_proc_cnt;
}
#elif defined(Q_OS_BSD4)
// FreeBSD, OpenBSD, NetBSD, BSD/OS, OS X, iOS
size_t len = sizeof(cores);
int mib[2];
mib[0] = CTL_HW;
mib[1] = HW_NCPU;
if (sysctl(mib, 2, &cores, &len, NULL, 0) != 0) {
perror("sysctl");
}
#elif defined(Q_OS_INTEGRITY)
#if (__INTEGRITY_MAJOR_VERSION >= 10)
// Integrity V10+ does support multicore CPUs
Value processorCount;
if (GetProcessorCount(CurrentTask(), &processorCount) == 0)
cores = processorCount;
else
#endif
// as of aug 2008 Integrity only supports one single core CPU
cores = 1;
#elif defined(Q_OS_VXWORKS)
// VxWorks
# if defined(QT_VXWORKS_HAS_CPUSET)
cpuset_t cpus = vxCpuEnabledGet();
cores = 0;
// 128 cores should be enough for everyone ;)
for (int i = 0; i < 128 && !CPUSET_ISZERO(cpus); ++i) {
if (CPUSET_ISSET(cpus, i)) {
CPUSET_CLR(cpus, i);
cores++;
}
}
# else
// as of aug 2008 VxWorks < 6.6 only supports one single core CPU
cores = 1;
# endif
#elif defined(Q_OS_WASM)
cores = QThreadPrivate::idealThreadCount;
#else
// the rest: Linux, Solaris, AIX, Tru64
cores = (int)sysconf(_SC_NPROCESSORS_ONLN);
if (cores == -1)
return 1;
#endif
return cores;
}
void QThread::yieldCurrentThread()
{
sched_yield();
}
#endif // QT_CONFIG(thread)
static timespec makeTimespec(time_t secs, long nsecs)
{
struct timespec ts;
ts.tv_sec = secs;
ts.tv_nsec = nsecs;
return ts;
}
void QThread::sleep(unsigned long secs)
{
qt_nanosleep(makeTimespec(secs, 0));
}
void QThread::msleep(unsigned long msecs)
{
qt_nanosleep(makeTimespec(msecs / 1000, msecs % 1000 * 1000 * 1000));
}
void QThread::usleep(unsigned long usecs)
{
qt_nanosleep(makeTimespec(usecs / 1000 / 1000, usecs % (1000*1000) * 1000));
}
#if QT_CONFIG(thread)
#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
#if defined(Q_OS_QNX)
static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
{
// On QNX, NormalPriority is mapped to 10. A QNX system could use a value different
// than 10 for the "normal" priority but it's difficult to achieve this so we'll
// assume that no one has ever created such a system. This makes the mapping from
// Qt priorities to QNX priorities lopsided. There's usually more space available
// to map into above the "normal" priority than below it. QNX also has a privileged
// priority range (for threads that assist the kernel). We'll assume that no Qt
// thread needs to use priorities in that range.
int priority_norm = 10;
// _sched_info::priority_priv isn't documented. You'd think that it's the start of the
// privileged priority range but it's actually the end of the unpriviledged range.
struct _sched_info info;
if (SchedInfo_r(0, *sched_policy, &info) != EOK)
return false;
if (priority == QThread::IdlePriority) {
*sched_priority = info.priority_min;
return true;
}
if (priority_norm < info.priority_min)
priority_norm = info.priority_min;
if (priority_norm > info.priority_priv)
priority_norm = info.priority_priv;
int to_min, to_max;
int from_min, from_max;
int prio;
if (priority < QThread::NormalPriority) {
to_min = info.priority_min;
to_max = priority_norm;
from_min = QThread::LowestPriority;
from_max = QThread::NormalPriority;
} else {
to_min = priority_norm;
to_max = info.priority_priv;
from_min = QThread::NormalPriority;
from_max = QThread::TimeCriticalPriority;
}
prio = ((priority - from_min) * (to_max - to_min)) / (from_max - from_min) + to_min;
prio = qBound(to_min, prio, to_max);
*sched_priority = prio;
return true;
}
#else
// Does some magic and calculate the Unix scheduler priorities
// sched_policy is IN/OUT: it must be set to a valid policy before calling this function
// sched_priority is OUT only
static bool calculateUnixPriority(int priority, int *sched_policy, int *sched_priority)
{
#ifdef SCHED_IDLE
if (priority == QThread::IdlePriority) {
*sched_policy = SCHED_IDLE;
*sched_priority = 0;
return true;
}
const int lowestPriority = QThread::LowestPriority;
#else
const int lowestPriority = QThread::IdlePriority;
#endif
const int highestPriority = QThread::TimeCriticalPriority;
int prio_min;
int prio_max;
#if defined(Q_OS_VXWORKS) && defined(VXWORKS_DKM)
// for other scheduling policies than SCHED_RR or SCHED_FIFO
prio_min = SCHED_FIFO_LOW_PRI;
prio_max = SCHED_FIFO_HIGH_PRI;
if ((*sched_policy == SCHED_RR) || (*sched_policy == SCHED_FIFO))
#endif
{
prio_min = sched_get_priority_min(*sched_policy);
prio_max = sched_get_priority_max(*sched_policy);
}
if (prio_min == -1 || prio_max == -1)
return false;
int prio;
// crudely scale our priority enum values to the prio_min/prio_max
prio = ((priority - lowestPriority) * (prio_max - prio_min) / highestPriority) + prio_min;
prio = qMax(prio_min, qMin(prio_max, prio));
*sched_priority = prio;
return true;
}
#endif
#endif
void QThread::start(Priority priority)
{
Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (d->isInFinish)
d->thread_done.wait(locker.mutex());
if (d->running)
return;
d->running = true;
d->finished = false;
d->returnCode = 0;
d->exited = false;
d->interruptionRequested = false;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
d->priority = priority;
#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
switch (priority) {
case InheritPriority:
{
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
break;
}
default:
{
int sched_policy;
if (pthread_attr_getschedpolicy(&attr, &sched_policy) != 0) {
// failed to get the scheduling policy, don't bother
// setting the priority
qWarning("QThread::start: Cannot determine default scheduler policy");
break;
}
int prio;
if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
// failed to get the scheduling parameters, don't
// bother setting the priority
qWarning("QThread::start: Cannot determine scheduler priority range");
break;
}
sched_param sp;
sp.sched_priority = prio;
if (pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED) != 0
|| pthread_attr_setschedpolicy(&attr, sched_policy) != 0
|| pthread_attr_setschedparam(&attr, &sp) != 0) {
// could not set scheduling hints, fallback to inheriting them
// we'll try again from inside the thread
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
d->priority = Priority(priority | ThreadPriorityResetFlag);
}
break;
}
}
#endif // QT_HAS_THREAD_PRIORITY_SCHEDULING
if (d->stackSize > 0) {
#if defined(_POSIX_THREAD_ATTR_STACKSIZE) && (_POSIX_THREAD_ATTR_STACKSIZE-0 > 0)
int code = pthread_attr_setstacksize(&attr, d->stackSize);
#else
int code = ENOSYS; // stack size not supported, automatically fail
#endif // _POSIX_THREAD_ATTR_STACKSIZE
if (code) {
qErrnoWarning(code, "QThread::start: Thread stack size error");
// we failed to set the stacksize, and as the documentation states,
// the thread will fail to run...
d->running = false;
d->finished = false;
return;
}
}
#ifdef Q_OS_INTEGRITY
if (Q_LIKELY(objectName().isEmpty()))
pthread_attr_setthreadname(&attr, metaObject()->className());
else
pthread_attr_setthreadname(&attr, objectName().toLocal8Bit());
#endif
pthread_t threadId;
int code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
if (code == EPERM) {
// caller does not have permission to set the scheduling
// parameters/policy
#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
#endif
code = pthread_create(&threadId, &attr, QThreadPrivate::start, this);
}
d->data->threadId.storeRelaxed(to_HANDLE(threadId));
pthread_attr_destroy(&attr);
if (code) {
qErrnoWarning(code, "QThread::start: Thread creation error");
d->running = false;
d->finished = false;
d->data->threadId.storeRelaxed(nullptr);
}
}
void QThread::terminate()
{
#if !defined(Q_OS_ANDROID)
Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (!d->data->threadId.loadRelaxed())
return;
int code = pthread_cancel(from_HANDLE<pthread_t>(d->data->threadId.loadRelaxed()));
if (code) {
qErrnoWarning(code, "QThread::start: Thread termination error");
}
#endif
}
bool QThread::wait(unsigned long time)
{
Q_D(QThread);
QMutexLocker locker(&d->mutex);
if (from_HANDLE<pthread_t>(d->data->threadId.loadRelaxed()) == pthread_self()) {
qWarning("QThread::wait: Thread tried to wait on itself");
return false;
}
if (d->finished || !d->running)
return true;
while (d->running) {
if (!d->thread_done.wait(locker.mutex(), time))
return false;
}
return true;
}
void QThread::setTerminationEnabled(bool enabled)
{
QThread *thr = currentThread();
Q_ASSERT_X(thr != 0, "QThread::setTerminationEnabled()",
"Current thread was not started with QThread.");
Q_UNUSED(thr)
#if defined(Q_OS_ANDROID)
Q_UNUSED(enabled);
#else
pthread_setcancelstate(enabled ? PTHREAD_CANCEL_ENABLE : PTHREAD_CANCEL_DISABLE, NULL);
if (enabled)
pthread_testcancel();
#endif
}
// Caller must lock the mutex
void QThreadPrivate::setPriority(QThread::Priority threadPriority)
{
priority = threadPriority;
// copied from start() with a few modifications:
#ifdef QT_HAS_THREAD_PRIORITY_SCHEDULING
int sched_policy;
sched_param param;
if (pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, &param) != 0) {
// failed to get the scheduling policy, don't bother setting
// the priority
qWarning("QThread::setPriority: Cannot get scheduler parameters");
return;
}
int prio;
if (!calculateUnixPriority(priority, &sched_policy, &prio)) {
// failed to get the scheduling parameters, don't
// bother setting the priority
qWarning("QThread::setPriority: Cannot determine scheduler priority range");
return;
}
param.sched_priority = prio;
int status = pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, &param);
# ifdef SCHED_IDLE
// were we trying to set to idle priority and failed?
if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
// reset to lowest priority possible
pthread_getschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), &sched_policy, &param);
param.sched_priority = sched_get_priority_min(sched_policy);
pthread_setschedparam(from_HANDLE<pthread_t>(data->threadId.loadRelaxed()), sched_policy, &param);
}
# else
Q_UNUSED(status);
# endif // SCHED_IDLE
#endif
}
#endif // QT_CONFIG(thread)
QT_END_NAMESPACE