QRecursiveMutexPrivate should not inherit from QMutexPrivate

QMutexPrivate takes more memory than necessary, and also initialize
platform specific ressources.

Change-Id: I70be1b89b1c21499645785ae47693a6b2514e28b
Reviewed-by: Bradley T. Hughes <bradley.hughes@nokia.com>
This commit is contained in:
Olivier Goffart 2011-10-20 17:11:18 +02:00 committed by Qt by Nokia
parent 72257f6429
commit 73b682d816
7 changed files with 55 additions and 49 deletions

View File

@ -150,11 +150,16 @@ QMutex::QMutex(RecursionMode mode)
*/ */
QMutex::~QMutex() QMutex::~QMutex()
{ {
if (isRecursive()) QMutexData *d = d_ptr.load();
delete static_cast<QRecursiveMutexPrivate *>(d_ptr.load()); if (quintptr(d) > 0x3 && d->recursive) {
else if (d_ptr.load()) { delete static_cast<QRecursiveMutexPrivate *>(d);
} else if (d) {
#ifndef Q_OS_LINUX #ifndef Q_OS_LINUX
if (d_ptr.load()->possiblyUnlocked.load() && tryLock()) { unlock(); return; } if (d != dummyLocked() && static_cast<QMutexPrivate *>(d)->possiblyUnlocked.load()
&& tryLock()) {
unlock();
return;
}
#endif #endif
qWarning("QMutex: destroying locked mutex"); qWarning("QMutex: destroying locked mutex");
} }
@ -233,7 +238,7 @@ QMutex::~QMutex()
*/ */
bool QBasicMutex::isRecursive() { bool QBasicMutex::isRecursive() {
QMutexPrivate *d = d_ptr.load(); QMutexData *d = d_ptr.load();
if (quintptr(d) <= 0x3) if (quintptr(d) <= 0x3)
return false; return false;
return d->recursive; return d->recursive;
@ -342,30 +347,31 @@ bool QBasicMutex::isRecursive() {
bool QBasicMutex::lockInternal(int timeout) bool QBasicMutex::lockInternal(int timeout)
{ {
while (!fastTryLock()) { while (!fastTryLock()) {
QMutexPrivate *d = d_ptr.loadAcquire(); QMutexData *copy = d_ptr.loadAcquire();
if (!d) // if d is 0, the mutex is unlocked if (!copy) // if d is 0, the mutex is unlocked
continue; continue;
if (d == dummyLocked()) { if (copy == dummyLocked()) {
if (timeout == 0) if (timeout == 0)
return false; return false;
QMutexPrivate *newD = QMutexPrivate::allocate(); QMutexPrivate *newD = QMutexPrivate::allocate();
if (!d_ptr.testAndSetOrdered(d, newD)) { if (!d_ptr.testAndSetOrdered(dummyLocked(), newD)) {
//Either the mutex is already unlocked, or another thread already set it. //Either the mutex is already unlocked, or another thread already set it.
newD->deref(); newD->deref();
continue; continue;
} }
d = newD; copy = newD;
//the d->refCount is already 1 the deref will occurs when we unlock //the d->refCount is already 1 the deref will occurs when we unlock
} else if (d->recursive) { } else if (copy->recursive) {
return static_cast<QRecursiveMutexPrivate *>(d)->lock(timeout); return static_cast<QRecursiveMutexPrivate *>(copy)->lock(timeout);
} }
QMutexPrivate *d = static_cast<QMutexPrivate *>(copy);
if (timeout == 0 && !d->possiblyUnlocked.load()) if (timeout == 0 && !d->possiblyUnlocked.load())
return false; return false;
if (!d->ref()) if (!d->ref())
continue; //that QMutexPrivate was already released continue; //that QMutexData was already released
if (d != d_ptr.loadAcquire()) { if (d != d_ptr.loadAcquire()) {
//Either the mutex is already unlocked, or relocked with another mutex //Either the mutex is already unlocked, or relocked with another mutex
@ -433,15 +439,17 @@ bool QBasicMutex::lockInternal(int timeout)
*/ */
void QBasicMutex::unlockInternal() void QBasicMutex::unlockInternal()
{ {
QMutexPrivate *d = d_ptr.loadAcquire(); QMutexData *copy = d_ptr.loadAcquire();
Q_ASSERT(d); //we must be locked Q_ASSERT(copy); //we must be locked
Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed Q_ASSERT(copy != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed
if (d->recursive) { if (copy->recursive) {
static_cast<QRecursiveMutexPrivate *>(d)->unlock(); static_cast<QRecursiveMutexPrivate *>(copy)->unlock();
return; return;
} }
QMutexPrivate *d = reinterpret_cast<QMutexPrivate *>(copy);
if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) { if (d->waiters.fetchAndAddRelease(-QMutexPrivate::BigNumber) == 0) {
//there is no one waiting on this mutex anymore, set the mutex as unlocked (d = 0) //there is no one waiting on this mutex anymore, set the mutex as unlocked (d = 0)
if (d_ptr.testAndSetRelease(d, 0)) { if (d_ptr.testAndSetRelease(d, 0)) {

View File

@ -54,7 +54,7 @@ QT_MODULE(Core)
#if !defined(QT_NO_THREAD) && !defined(qdoc) #if !defined(QT_NO_THREAD) && !defined(qdoc)
class QMutexPrivate; class QMutexData;
class Q_CORE_EXPORT QBasicMutex class Q_CORE_EXPORT QBasicMutex
{ {
@ -83,13 +83,13 @@ private:
bool lockInternal(int timeout = -1); bool lockInternal(int timeout = -1);
void unlockInternal(); void unlockInternal();
QBasicAtomicPointer<QMutexPrivate> d_ptr; QBasicAtomicPointer<QMutexData> d_ptr;
static inline QMutexPrivate *dummyLocked() { static inline QMutexData *dummyLocked() {
return reinterpret_cast<QMutexPrivate *>(quintptr(1)); return reinterpret_cast<QMutexData *>(quintptr(1));
} }
friend class QMutex; friend class QMutex;
friend class QMutexPrivate; friend class QMutexData;
}; };
class Q_CORE_EXPORT QMutex : public QBasicMutex { class Q_CORE_EXPORT QMutex : public QBasicMutex {

View File

@ -65,16 +65,11 @@ static inline int _q_futex(void *addr, int op, int val, const struct timespec *t
return syscall(SYS_futex, int_addr, op, val, timeout, addr2, val2); return syscall(SYS_futex, int_addr, op, val, timeout, addr2, val2);
} }
static inline QMutexPrivate *dummyFutexValue() static inline QMutexData *dummyFutexValue()
{ {
return reinterpret_cast<QMutexPrivate *>(quintptr(3)); return reinterpret_cast<QMutexData *>(quintptr(3));
} }
QMutexPrivate::~QMutexPrivate() {}
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
: recursive(mode == QMutex::Recursive) {}
bool QBasicMutex::lockInternal(int timeout) bool QBasicMutex::lockInternal(int timeout)
{ {
QElapsedTimer elapsedTimer; QElapsedTimer elapsedTimer;
@ -82,7 +77,7 @@ bool QBasicMutex::lockInternal(int timeout)
elapsedTimer.start(); elapsedTimer.start();
while (!fastTryLock()) { while (!fastTryLock()) {
QMutexPrivate *d = d_ptr.load(); QMutexData *d = d_ptr.load();
if (!d) // if d is 0, the mutex is unlocked if (!d) // if d is 0, the mutex is unlocked
continue; continue;
@ -118,7 +113,7 @@ bool QBasicMutex::lockInternal(int timeout)
void QBasicMutex::unlockInternal() void QBasicMutex::unlockInternal()
{ {
QMutexPrivate *d = d_ptr.load(); QMutexData *d = d_ptr.load();
Q_ASSERT(d); //we must be locked Q_ASSERT(d); //we must be locked
Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed Q_ASSERT(d != dummyLocked()); // testAndSetRelease(dummyLocked(), 0) failed

View File

@ -53,8 +53,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) QMutexPrivate::QMutexPrivate()
: recursive(mode == QMutex::Recursive)
{ {
kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0);
if (r != KERN_SUCCESS) if (r != KERN_SUCCESS)

View File

@ -65,15 +65,23 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
class QMutexPrivate { class QMutexData
{
public:
bool recursive;
QMutexData(QMutex::RecursionMode mode = QMutex::NonRecursive)
: recursive(mode == QMutex::Recursive) {}
};
#if !defined(Q_OS_LINUX)
class QMutexPrivate : public QMutexData {
public: public:
~QMutexPrivate(); ~QMutexPrivate();
QMutexPrivate(QMutex::RecursionMode mode = QMutex::NonRecursive); QMutexPrivate();
bool wait(int timeout = -1); bool wait(int timeout = -1);
void wakeUp(); void wakeUp();
#if !defined(Q_OS_LINUX)
// Conrol the lifetime of the privates // Conrol the lifetime of the privates
QAtomicInt refCount; QAtomicInt refCount;
int id; int id;
@ -102,15 +110,11 @@ public:
QAtomicInt possiblyUnlocked; //bool saying that a timed wait timed out QAtomicInt possiblyUnlocked; //bool saying that a timed wait timed out
enum { BigNumber = 0x100000 }; //Must be bigger than the possible number of waiters (number of threads) enum { BigNumber = 0x100000 }; //Must be bigger than the possible number of waiters (number of threads)
void derefWaiters(int value); void derefWaiters(int value);
#endif
// handle recursive mutex
bool recursive;
//platform specific stuff //platform specific stuff
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
semaphore_t mach_semaphore; semaphore_t mach_semaphore;
#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) #elif defined(Q_OS_UNIX)
bool wakeup; bool wakeup;
pthread_mutex_t mutex; pthread_mutex_t mutex;
pthread_cond_t cond; pthread_cond_t cond;
@ -118,12 +122,13 @@ public:
HANDLE event; HANDLE event;
#endif #endif
}; };
#endif //Q_OS_LINUX
class QRecursiveMutexPrivate : public QMutexPrivate class QRecursiveMutexPrivate : public QMutexData
{ {
public: public:
QRecursiveMutexPrivate() QRecursiveMutexPrivate()
: QMutexPrivate(QMutex::Recursive), owner(0), count(0) {} : QMutexData(QMutex::Recursive), owner(0), count(0) {}
Qt::HANDLE owner; Qt::HANDLE owner;
uint count; uint count;
QMutex mutex; QMutex mutex;

View File

@ -60,8 +60,8 @@ static void report_error(int code, const char *where, const char *what)
qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code))); qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code)));
} }
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) QMutexPrivate::QMutexPrivate()
: recursive(mode == QMutex::Recursive), wakeup(false) : wakeup(false)
{ {
report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init");
report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init");

View File

@ -47,12 +47,11 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) QMutexPrivate::QMutexPrivate()
: recursive(mode)
{ {
event = CreateEvent(0, FALSE, FALSE, 0); event = CreateEvent(0, FALSE, FALSE, 0);
if (!event) if (!event)
qWarning("QMutexPrivate::QMutexPrivate: Cannot create event"); qWarning("QMutexData::QMutexData: Cannot create event");
} }
QMutexPrivate::~QMutexPrivate() QMutexPrivate::~QMutexPrivate()