summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/corelib/thread/qmutex.cpp36
-rw-r--r--src/corelib/thread/qmutex_p.h4
-rw-r--r--src/corelib/thread/qmutex_unix.cpp2
-rw-r--r--src/corelib/thread/qmutex_win.cpp2
4 files changed, 25 insertions, 19 deletions
diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp
index 54b3ed4..72f87b7 100644
--- a/src/corelib/thread/qmutex.cpp
+++ b/src/corelib/thread/qmutex.cpp
@@ -45,6 +45,7 @@
#ifndef QT_NO_THREAD
#include "qatomic.h"
+#include "qelapsedtimer.h"
#include "qthread.h"
#include "qmutex_p.h"
@@ -439,31 +440,34 @@ void QMutex::lockInternal()
return;
}
- int spinCount = 0;
- int lastSpinCount = d->lastSpinCount;
-
- enum { AdditionalSpins = 20, SpinCountPenalizationDivisor = 4 };
- const int maximumSpinCount = lastSpinCount + AdditionalSpins;
-
+ QElapsedTimer elapsedTimer;
+ elapsedTimer.start();
do {
- if (spinCount++ > maximumSpinCount) {
- // didn't get the lock, wait for it
+ if (elapsedTimer.hasExpired(d->maximumSpinTime)) {
+ // didn't get the lock, wait for it, since we're not going to gain anything by spinning more
+ int spinTime = elapsedTimer.restart();
bool isLocked = d->wait();
Q_ASSERT_X(isLocked, "QMutex::lock",
"Internal error, infinite wait has timed out.");
Q_UNUSED(isLocked);
- // decrease the lastSpinCount since we didn't actually get the lock by spinning
- spinCount = -d->lastSpinCount / SpinCountPenalizationDivisor;
- break;
+ int maximumSpinTime = d->maximumSpinTime;
+ int waitTime = elapsedTimer.elapsed();
+ // adjust the spin count when spinning does not benefit contention performance
+ if (spinTime + waitTime > QMutexPrivate::MaximumSpinTimeThreshold) {
+ // long waits, stop spinning
+ d->maximumSpinTime = 0;
+ } else if (waitTime < maximumSpinTime) {
+ // never spin more than the minimum wait time (otherwise we may perform worse)
+ d->maximumSpinTime = waitTime;
+ }
+ return;
}
+ // be a good citizen... yielding lets something else run if there is something to run, but may also relieve memory pressure if not
+ QThread::yieldCurrentThread();
} 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;
+ // spinning is working, do not change the spin time
}
/*!
diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h
index 2d45cfb..6de42ad 100644
--- a/src/corelib/thread/qmutex_p.h
+++ b/src/corelib/thread/qmutex_p.h
@@ -72,7 +72,9 @@ public:
bool wait(int timeout = -1);
void wakeUp();
- volatile int lastSpinCount;
+ // half of a frame (in ms) at 60fps
+ enum { MaximumSpinTimeThreshold = 8 };
+ volatile int maximumSpinTime;
Qt::HANDLE owner;
uint count;
diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp
index e872187..48014cc 100644
--- a/src/corelib/thread/qmutex_unix.cpp
+++ b/src/corelib/thread/qmutex_unix.cpp
@@ -74,7 +74,7 @@ static void report_error(int code, const char *where, const char *what)
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
- : QMutexData(mode), lastSpinCount(0), owner(0), count(0)
+ : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), owner(0), count(0)
{
#if defined(Q_OS_MAC)
kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0);
diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp
index c278f04..89e8b87 100644
--- a/src/corelib/thread/qmutex_win.cpp
+++ b/src/corelib/thread/qmutex_win.cpp
@@ -48,7 +48,7 @@
QT_BEGIN_NAMESPACE
QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode)
- : QMutexData(mode), lastSpinCount(0), owner(0), count(0)
+ : QMutexData(mode), maximumSpinTime(MaximumSpinTimeThreshold), owner(0), count(0)
{
event = CreateEvent(0, FALSE, FALSE, 0);
if (!event)