Don't store the pthread_t thread ID twice in QThread
It was being stored once in QThreadPrivate and once in QThreadData, with the latter being hidden as a Qt::HANDLE. Besides saving a little bit of memory, this also solves a small data race condition that arises from trying to connect a signal to an object moved to that thread and then emit that signal shortly after the thread starts. Before this patch, QThreadData::threadId was initialized only by QThreadPrivate::start(), which meant that we were racing that initialization with this check in QMetaObject::activate: const bool receiverInSameThread = currentThreadId == receiver->d_func()->threadData->threadId; Task-number: QTBUG-52337 Change-Id: Ifea6e497f11a461db432ffff1449ae01f1099aae Reviewed-by: Olivier Goffart (Woboq GmbH) <ogoffart@woboq.com> Reviewed-by: Jędrzej Nowacki <jedrzej.nowacki@theqtcompany.com>
This commit is contained in:
parent
002112e805
commit
112e53fdc4
@ -142,16 +142,12 @@ QThreadPrivate::QThreadPrivate(QThreadData *d)
|
|||||||
exited(false), returnCode(-1),
|
exited(false), returnCode(-1),
|
||||||
stackSize(0), priority(QThread::InheritPriority), data(d)
|
stackSize(0), priority(QThread::InheritPriority), data(d)
|
||||||
{
|
{
|
||||||
#if defined (Q_OS_UNIX)
|
#if defined (Q_OS_WIN)
|
||||||
thread_id = 0;
|
|
||||||
#elif defined (Q_OS_WIN)
|
|
||||||
handle = 0;
|
handle = 0;
|
||||||
# ifndef Q_OS_WINRT
|
# ifndef Q_OS_WINRT
|
||||||
id = 0;
|
id = 0;
|
||||||
# endif
|
# endif
|
||||||
waiters = 0;
|
waiters = 0;
|
||||||
#endif
|
|
||||||
#if defined (Q_OS_WIN)
|
|
||||||
terminationEnabled = true;
|
terminationEnabled = true;
|
||||||
terminatePending = false;
|
terminatePending = false;
|
||||||
#endif
|
#endif
|
||||||
|
@ -169,7 +169,6 @@ public:
|
|||||||
static QThread *threadForId(int id);
|
static QThread *threadForId(int id);
|
||||||
|
|
||||||
#ifdef Q_OS_UNIX
|
#ifdef Q_OS_UNIX
|
||||||
pthread_t thread_id;
|
|
||||||
QWaitCondition thread_done;
|
QWaitCondition thread_done;
|
||||||
|
|
||||||
static void *start(void *arg);
|
static void *start(void *arg);
|
||||||
|
@ -105,6 +105,8 @@ QT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
#ifndef QT_NO_THREAD
|
#ifndef QT_NO_THREAD
|
||||||
|
|
||||||
|
Q_STATIC_ASSERT(sizeof(pthread_t) == sizeof(Qt::HANDLE));
|
||||||
|
|
||||||
enum { ThreadPriorityResetFlag = 0x80000000 };
|
enum { ThreadPriorityResetFlag = 0x80000000 };
|
||||||
|
|
||||||
#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL)) && !defined(QT_LINUXBASE)
|
#if defined(Q_OS_LINUX) && defined(__GLIBC__) && (defined(Q_CC_GNU) || defined(Q_CC_INTEL)) && !defined(QT_LINUXBASE)
|
||||||
@ -234,8 +236,6 @@ QThreadData *QThreadData::current(bool createIfNecessary)
|
|||||||
|
|
||||||
void QAdoptedThread::init()
|
void QAdoptedThread::init()
|
||||||
{
|
{
|
||||||
Q_D(QThread);
|
|
||||||
d->thread_id = pthread_self();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -325,10 +325,11 @@ void *QThreadPrivate::start(void *arg)
|
|||||||
// sets the name of the current thread.
|
// sets the name of the current thread.
|
||||||
QString objectName = thr->objectName();
|
QString objectName = thr->objectName();
|
||||||
|
|
||||||
|
pthread_t thread_id = reinterpret_cast<pthread_t>(data->threadId);
|
||||||
if (Q_LIKELY(objectName.isEmpty()))
|
if (Q_LIKELY(objectName.isEmpty()))
|
||||||
setCurrentThreadName(thr->d_func()->thread_id, thr->metaObject()->className());
|
setCurrentThreadName(thread_id, thr->metaObject()->className());
|
||||||
else
|
else
|
||||||
setCurrentThreadName(thr->d_func()->thread_id, objectName.toLocal8Bit());
|
setCurrentThreadName(thread_id, objectName.toLocal8Bit());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -369,7 +370,6 @@ void QThreadPrivate::finish(void *arg)
|
|||||||
locker.relock();
|
locker.relock();
|
||||||
}
|
}
|
||||||
|
|
||||||
d->thread_id = 0;
|
|
||||||
d->running = false;
|
d->running = false;
|
||||||
d->finished = true;
|
d->finished = true;
|
||||||
d->interruptionRequested = false;
|
d->interruptionRequested = false;
|
||||||
@ -615,15 +615,16 @@ void QThread::start(Priority priority)
|
|||||||
}
|
}
|
||||||
|
|
||||||
int code =
|
int code =
|
||||||
pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
|
pthread_create(reinterpret_cast<pthread_t *>(&d->data->threadId), &attr,
|
||||||
|
QThreadPrivate::start, this);
|
||||||
if (code == EPERM) {
|
if (code == EPERM) {
|
||||||
// caller does not have permission to set the scheduling
|
// caller does not have permission to set the scheduling
|
||||||
// parameters/policy
|
// parameters/policy
|
||||||
#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
|
#if defined(QT_HAS_THREAD_PRIORITY_SCHEDULING)
|
||||||
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
|
pthread_attr_setinheritsched(&attr, PTHREAD_INHERIT_SCHED);
|
||||||
#endif
|
#endif
|
||||||
code =
|
code = pthread_create(reinterpret_cast<pthread_t *>(&d->data->threadId), &attr,
|
||||||
pthread_create(&d->thread_id, &attr, QThreadPrivate::start, this);
|
QThreadPrivate::start, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_attr_destroy(&attr);
|
pthread_attr_destroy(&attr);
|
||||||
@ -633,7 +634,7 @@ void QThread::start(Priority priority)
|
|||||||
|
|
||||||
d->running = false;
|
d->running = false;
|
||||||
d->finished = false;
|
d->finished = false;
|
||||||
d->thread_id = 0;
|
d->data->threadId = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -643,10 +644,10 @@ void QThread::terminate()
|
|||||||
Q_D(QThread);
|
Q_D(QThread);
|
||||||
QMutexLocker locker(&d->mutex);
|
QMutexLocker locker(&d->mutex);
|
||||||
|
|
||||||
if (!d->thread_id)
|
if (!d->data->threadId)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int code = pthread_cancel(d->thread_id);
|
int code = pthread_cancel(reinterpret_cast<pthread_t>(d->data->threadId));
|
||||||
if (code) {
|
if (code) {
|
||||||
qWarning("QThread::start: Thread termination error: %s",
|
qWarning("QThread::start: Thread termination error: %s",
|
||||||
qPrintable(qt_error_string((code))));
|
qPrintable(qt_error_string((code))));
|
||||||
@ -659,7 +660,7 @@ bool QThread::wait(unsigned long time)
|
|||||||
Q_D(QThread);
|
Q_D(QThread);
|
||||||
QMutexLocker locker(&d->mutex);
|
QMutexLocker locker(&d->mutex);
|
||||||
|
|
||||||
if (d->thread_id == pthread_self()) {
|
if (reinterpret_cast<pthread_t>(d->data->threadId) == pthread_self()) {
|
||||||
qWarning("QThread::wait: Thread tried to wait on itself");
|
qWarning("QThread::wait: Thread tried to wait on itself");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -701,7 +702,7 @@ void QThreadPrivate::setPriority(QThread::Priority threadPriority)
|
|||||||
int sched_policy;
|
int sched_policy;
|
||||||
sched_param param;
|
sched_param param;
|
||||||
|
|
||||||
if (pthread_getschedparam(thread_id, &sched_policy, ¶m) != 0) {
|
if (pthread_getschedparam(reinterpret_cast<pthread_t>(data->threadId), &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");
|
||||||
@ -717,15 +718,15 @@ void QThreadPrivate::setPriority(QThread::Priority threadPriority)
|
|||||||
}
|
}
|
||||||
|
|
||||||
param.sched_priority = prio;
|
param.sched_priority = prio;
|
||||||
int status = pthread_setschedparam(thread_id, sched_policy, ¶m);
|
int status = pthread_setschedparam(reinterpret_cast<pthread_t>(data->threadId), 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(thread_id, &sched_policy, ¶m);
|
pthread_getschedparam(reinterpret_cast<pthread_t>(data->threadId), &sched_policy, ¶m);
|
||||||
param.sched_priority = sched_get_priority_min(sched_policy);
|
param.sched_priority = sched_get_priority_min(sched_policy);
|
||||||
pthread_setschedparam(thread_id, sched_policy, ¶m);
|
pthread_setschedparam(reinterpret_cast<pthread_t>(data->threadId), sched_policy, ¶m);
|
||||||
}
|
}
|
||||||
# else
|
# else
|
||||||
Q_UNUSED(status);
|
Q_UNUSED(status);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user