summaryrefslogtreecommitdiffstats
path: root/src/corelib/thread/qmutex.cpp
diff options
context:
space:
mode:
authorOlivier Goffart <olivier.goffart@nokia.com>2010-04-21 18:17:08 (GMT)
committerOlivier Goffart <olivier.goffart@nokia.com>2010-05-18 10:32:31 (GMT)
commitc25a6e090c8074e68d7eb40f2533da8bab5e7dd8 (patch)
tree0d881265383a23871aa6f93c02f756b5dc8d36e1 /src/corelib/thread/qmutex.cpp
parentaef03d80f7d9b71dfe777cd7927808d69dac0c27 (diff)
downloadQt-c25a6e090c8074e68d7eb40f2533da8bab5e7dd8.zip
Qt-c25a6e090c8074e68d7eb40f2533da8bab5e7dd8.tar.gz
Qt-c25a6e090c8074e68d7eb40f2533da8bab5e7dd8.tar.bz2
Inline the common case when there is no contention.
QMutex locking could be used in performence critical code (such as QObject and co.) where the cost of a function call is not neglectible. This would slow down the common case where there is only one thread and no contention. Since we need to keep the old symbol for binary compatibilty, introduce new *Inline function. Reviewed-by: Brad
Diffstat (limited to 'src/corelib/thread/qmutex.cpp')
-rw-r--r--src/corelib/thread/qmutex.cpp133
1 files changed, 93 insertions, 40 deletions
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
index 43df13a..eb6f729 100644
--- a/src/corelib/thread/qmutex.cpp
+++ b/src/corelib/thread/qmutex.cpp
@@ -130,7 +130,7 @@ QMutex::QMutex(RecursionMode mode)
\warning Destroying a locked mutex may result in undefined behavior.
*/
QMutex::~QMutex()
-{ delete d; }
+{ delete static_cast<QMutexPrivate *>(d); }
/*!
Locks the mutex. If another thread has locked the mutex then this
@@ -146,6 +146,7 @@ QMutex::~QMutex()
*/
void QMutex::lock()
{
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
Qt::HANDLE self;
if (d->recursive) {
@@ -184,43 +185,7 @@ void QMutex::lock()
bool isLocked = d->contenders == 0 && d->contenders.testAndSetAcquire(0, 1);
if (!isLocked) {
- int spinCount = 0;
- int lastSpinCount = d->lastSpinCount;
-
- enum { AdditionalSpins = 20, SpinCountPenalizationDivisor = 4 };
- const int maximumSpinCount = lastSpinCount + AdditionalSpins;
-
- do {
- if (spinCount++ > maximumSpinCount) {
- // puts("spinning useless, sleeping");
- isLocked = d->contenders.fetchAndAddAcquire(1) == 0;
- if (!isLocked) {
-#ifndef QT_NO_DEBUG
- if (d->owner == self)
- qWarning() << "QMutex::lock: Deadlock detected in thread" << d->owner;
-#endif
-
- // didn't get the lock, wait for it
- isLocked = d->wait();
- Q_ASSERT_X(isLocked, "QMutex::lock",
- "Internal error, infinite wait has timed out.");
-
- // don't need to wait for the lock anymore
- d->contenders.deref();
- }
- // decrease the lastSpinCount since we didn't actually get the lock by spinning
- spinCount = -d->lastSpinCount / SpinCountPenalizationDivisor;
- break;
- }
-
- isLocked = d->contenders == 0 && d->contenders.testAndSetAcquire(0, 1);
- } while (!isLocked);
-
- // adjust the last spin lock count
- lastSpinCount = d->lastSpinCount;
- d->lastSpinCount = spinCount >= 0
- ? qMax(lastSpinCount, spinCount)
- : lastSpinCount + spinCount;
+ lockInternal();
}
#ifndef QT_NO_DEBUG
@@ -247,6 +212,7 @@ void QMutex::lock()
*/
bool QMutex::tryLock()
{
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
Qt::HANDLE self;
if (d->recursive) {
@@ -310,6 +276,7 @@ bool QMutex::tryLock()
*/
bool QMutex::tryLock(int timeout)
{
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
Qt::HANDLE self;
if (d->recursive) {
@@ -366,8 +333,13 @@ bool QMutex::tryLock(int timeout)
*/
void QMutex::unlock()
{
- Q_ASSERT_X(d->owner == QThread::currentThreadId(), "QMutex::unlock()",
- "A mutex must be unlocked in the same thread that locked it.");
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
+#ifndef QT_NO_DEBUG
+ //note: if the mutex has been locked with (try)lockInline, d->owner could have not been set, and this would be a false warning
+ if ((d->owner || d->recursive) && d->owner != QThread::currentThreadId())
+ qWarning("QMutex::unlock(): A mutex must be unlocked in the same thread that locked it.");
+#endif
+
if (d->recursive) {
if (!--d->count) {
@@ -506,6 +478,87 @@ void QMutex::unlock()
Use the constructor that takes a RecursionMode parameter instead.
*/
+/*!
+ \internal helper for lockInline()
+ */
+void QMutex::lockInternal()
+{
+ QMutexPrivate *d = static_cast<QMutexPrivate *>(this->d);
+ int spinCount = 0;
+ int lastSpinCount = d->lastSpinCount;
+
+ enum { AdditionalSpins = 20, SpinCountPenalizationDivisor = 4 };
+ const int maximumSpinCount = lastSpinCount + AdditionalSpins;
+
+#ifndef QT_NO_DEBUG
+ Qt::HANDLE self = QThread::currentThreadId();
+#endif
+
+ do {
+ if (spinCount++ > maximumSpinCount) {
+ // puts("spinning useless, sleeping");
+ bool isLocked = d->contenders.fetchAndAddAcquire(1) == 0;
+ if (!isLocked) {
+#ifndef QT_NO_DEBUG
+ if (d->owner == self)
+ qWarning() << "QMutex::lock: Deadlock detected in thread" << d->owner;
+#endif
+
+ // didn't get the lock, wait for it
+ isLocked = d->wait();
+ Q_ASSERT_X(isLocked, "QMutex::lock",
+ "Internal error, infinite wait has timed out.");
+
+ // don't need to wait for the lock anymore
+ d->contenders.deref();
+ }
+ // decrease the lastSpinCount since we didn't actually get the lock by spinning
+ spinCount = -d->lastSpinCount / SpinCountPenalizationDivisor;
+ break;
+ }
+ } while (d->contenders != 0 || !d->contenders.testAndSetAcquire(0, 1));
+
+ // adjust the last spin lock count
+ lastSpinCount = d->lastSpinCount;
+ d->lastSpinCount = spinCount >= 0
+ ? qMax(lastSpinCount, spinCount)
+ : lastSpinCount + spinCount;
+
+#ifndef QT_NO_DEBUG
+ d->owner = self;
+#endif
+}
+
+/*!
+ \internal
+*/
+void QMutex::unlockInternal()
+{
+#ifndef QT_NO_DEBUG
+ static_cast<QMutexPrivate *>(d)->owner = 0;
+#endif
+ static_cast<QMutexPrivate *>(d)->wakeUp();
+}
+
+/*!
+ \fn QMutex::lockInline()
+ \internal
+ inline version of QMutex::lock()
+*/
+
+/*!
+ \fn QMutex::unlockInline()
+ \internal
+ inline version of QMutex::unlock()
+*/
+
+/*!
+ \fn QMutex::tryLockInline()
+ \internal
+ inline version of QMutex::tryLock()
+*/
+
+
QT_END_NAMESPACE
#endif // QT_NO_THREAD