Fix race condition in QThread::setPriority
The value of priority was read without the mutex locked, from within the thread. Had to extract a QThreadPrivate::setPriority method so that it can be called with the mutex already locked. So if the main thread calls setPriority while the thread is starting, it will be either be before or after the "re-set priority" code at thread startup, but at least not in the middle of it. Change-Id: I7a054f68623f61482c749274da66f3b2dcd8bcee Reviewed-by: Olivier Goffart <ogoffart@woboq.com>
This commit is contained in:
parent
c550a5d42c
commit
d4adee7851
@ -593,6 +593,16 @@ void QThread::run()
|
|||||||
|
|
||||||
\sa Priority, priority(), start()
|
\sa Priority, priority(), start()
|
||||||
*/
|
*/
|
||||||
|
void QThread::setPriority(Priority priority)
|
||||||
|
{
|
||||||
|
Q_D(QThread);
|
||||||
|
QMutexLocker locker(&d->mutex);
|
||||||
|
if (!d->running) {
|
||||||
|
qWarning("QThread::setPriority: Cannot set priority, thread is not running");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
d->setPriority(priority);
|
||||||
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\since 4.1
|
\since 4.1
|
||||||
|
@ -142,6 +142,8 @@ public:
|
|||||||
QThreadPrivate(QThreadData *d = 0);
|
QThreadPrivate(QThreadData *d = 0);
|
||||||
~QThreadPrivate();
|
~QThreadPrivate();
|
||||||
|
|
||||||
|
void setPriority(QThread::Priority prio);
|
||||||
|
|
||||||
mutable QMutex mutex;
|
mutable QMutex mutex;
|
||||||
QAtomicInt quitLockRef;
|
QAtomicInt quitLockRef;
|
||||||
|
|
||||||
|
@ -300,17 +300,18 @@ void *QThreadPrivate::start(void *arg)
|
|||||||
QThread *thr = reinterpret_cast<QThread *>(arg);
|
QThread *thr = reinterpret_cast<QThread *>(arg);
|
||||||
QThreadData *data = QThreadData::get2(thr);
|
QThreadData *data = QThreadData::get2(thr);
|
||||||
|
|
||||||
// do we need to reset the thread priority?
|
|
||||||
if (int(thr->d_func()->priority) & ThreadPriorityResetFlag) {
|
|
||||||
thr->setPriority(QThread::Priority(thr->d_func()->priority & ~ThreadPriorityResetFlag));
|
|
||||||
}
|
|
||||||
|
|
||||||
data->threadId = (Qt::HANDLE)pthread_self();
|
|
||||||
set_thread_data(data);
|
|
||||||
|
|
||||||
data->ref();
|
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&thr->d_func()->mutex);
|
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 = (Qt::HANDLE)pthread_self();
|
||||||
|
set_thread_data(data);
|
||||||
|
|
||||||
|
data->ref();
|
||||||
data->quitNow = thr->d_func()->exited;
|
data->quitNow = thr->d_func()->exited;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -687,16 +688,10 @@ void QThread::setTerminationEnabled(bool enabled)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void QThread::setPriority(Priority priority)
|
// Caller must lock the mutex
|
||||||
|
void QThreadPrivate::setPriority(QThread::Priority threadPriority)
|
||||||
{
|
{
|
||||||
Q_D(QThread);
|
priority = threadPriority;
|
||||||
QMutexLocker locker(&d->mutex);
|
|
||||||
if (!d->running) {
|
|
||||||
qWarning("QThread::setPriority: Cannot set priority, thread is not running");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
d->priority = priority;
|
|
||||||
|
|
||||||
// copied from start() with a few modifications:
|
// copied from start() with a few modifications:
|
||||||
|
|
||||||
@ -704,7 +699,7 @@ void QThread::setPriority(Priority priority)
|
|||||||
int sched_policy;
|
int sched_policy;
|
||||||
sched_param param;
|
sched_param param;
|
||||||
|
|
||||||
if (pthread_getschedparam(d->thread_id, &sched_policy, ¶m) != 0) {
|
if (pthread_getschedparam(thread_id, &sched_policy, ¶m) != 0) {
|
||||||
// failed to get the scheduling policy, don't bother setting
|
// failed to get the scheduling policy, don't bother setting
|
||||||
// the priority
|
// the priority
|
||||||
qWarning("QThread::setPriority: Cannot get scheduler parameters");
|
qWarning("QThread::setPriority: Cannot get scheduler parameters");
|
||||||
@ -720,15 +715,15 @@ void QThread::setPriority(Priority priority)
|
|||||||
}
|
}
|
||||||
|
|
||||||
param.sched_priority = prio;
|
param.sched_priority = prio;
|
||||||
int status = pthread_setschedparam(d->thread_id, sched_policy, ¶m);
|
int status = pthread_setschedparam(thread_id, sched_policy, ¶m);
|
||||||
|
|
||||||
# ifdef SCHED_IDLE
|
# ifdef SCHED_IDLE
|
||||||
// were we trying to set to idle priority and failed?
|
// were we trying to set to idle priority and failed?
|
||||||
if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
|
if (status == -1 && sched_policy == SCHED_IDLE && errno == EINVAL) {
|
||||||
// reset to lowest priority possible
|
// reset to lowest priority possible
|
||||||
pthread_getschedparam(d->thread_id, &sched_policy, ¶m);
|
pthread_getschedparam(thread_id, &sched_policy, ¶m);
|
||||||
param.sched_priority = sched_get_priority_min(sched_policy);
|
param.sched_priority = sched_get_priority_min(sched_policy);
|
||||||
pthread_setschedparam(d->thread_id, sched_policy, ¶m);
|
pthread_setschedparam(thread_id, sched_policy, ¶m);
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
Q_UNUSED(status);
|
Q_UNUSED(status);
|
||||||
|
@ -588,55 +588,49 @@ void QThread::setTerminationEnabled(bool enabled)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QThread::setPriority(Priority priority)
|
// Caller must hold the mutex
|
||||||
|
void QThreadPrivate::setPriority(QThread::Priority threadPriority)
|
||||||
{
|
{
|
||||||
Q_D(QThread);
|
|
||||||
QMutexLocker locker(&d->mutex);
|
|
||||||
if (!d->running) {
|
|
||||||
qWarning("QThread::setPriority: Cannot set priority, thread is not running");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// copied from start() with a few modifications:
|
// copied from start() with a few modifications:
|
||||||
|
|
||||||
int prio;
|
int prio;
|
||||||
d->priority = priority;
|
priority = threadPriority;
|
||||||
switch (d->priority) {
|
switch (priority) {
|
||||||
case IdlePriority:
|
case QThread::IdlePriority:
|
||||||
prio = THREAD_PRIORITY_IDLE;
|
prio = THREAD_PRIORITY_IDLE;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LowestPriority:
|
case QThread::LowestPriority:
|
||||||
prio = THREAD_PRIORITY_LOWEST;
|
prio = THREAD_PRIORITY_LOWEST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case LowPriority:
|
case QThread::LowPriority:
|
||||||
prio = THREAD_PRIORITY_BELOW_NORMAL;
|
prio = THREAD_PRIORITY_BELOW_NORMAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case NormalPriority:
|
case QThread::NormalPriority:
|
||||||
prio = THREAD_PRIORITY_NORMAL;
|
prio = THREAD_PRIORITY_NORMAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HighPriority:
|
case QThread::HighPriority:
|
||||||
prio = THREAD_PRIORITY_ABOVE_NORMAL;
|
prio = THREAD_PRIORITY_ABOVE_NORMAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case HighestPriority:
|
case QThread::HighestPriority:
|
||||||
prio = THREAD_PRIORITY_HIGHEST;
|
prio = THREAD_PRIORITY_HIGHEST;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TimeCriticalPriority:
|
case QThread::TimeCriticalPriority:
|
||||||
prio = THREAD_PRIORITY_TIME_CRITICAL;
|
prio = THREAD_PRIORITY_TIME_CRITICAL;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case InheritPriority:
|
case QThread::InheritPriority:
|
||||||
default:
|
default:
|
||||||
qWarning("QThread::setPriority: Argument cannot be InheritPriority");
|
qWarning("QThread::setPriority: Argument cannot be InheritPriority");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!SetThreadPriority(d->handle, prio)) {
|
if (!SetThreadPriority(handle, prio)) {
|
||||||
qErrnoWarning("QThread::setPriority: Failed to set thread priority");
|
qErrnoWarning("QThread::setPriority: Failed to set thread priority");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user