diff options
author | Bradley T. Hughes <bradley.hughes@nokia.com> | 2010-09-16 13:46:43 (GMT) |
---|---|---|
committer | Bradley T. Hughes <bradley.hughes@nokia.com> | 2010-12-20 15:49:46 (GMT) |
commit | cf17b743d2fe84ab259b7232ab07b58a1872e18e (patch) | |
tree | 7a0dfd1f21ba9041de7c39c6947adeacf9e4d8e5 | |
parent | 87bab705ded31559941020d3c500f43f571f9c16 (diff) | |
download | Qt-cf17b743d2fe84ab259b7232ab07b58a1872e18e.zip Qt-cf17b743d2fe84ab259b7232ab07b58a1872e18e.tar.gz Qt-cf17b743d2fe84ab259b7232ab07b58a1872e18e.tar.bz2 |
Improve QMutex contention performance on Mac OS X
Use a Mach semaphore to implement QMutexPrivate::wait() and ::wakeup(). This
makes QMutex perform more or less identically the same as pthread_mutex_t when
contended.
Reviewed-by: joao
-rw-r--r-- | src/corelib/thread/qmutex_p.h | 8 | ||||
-rw-r--r-- | src/corelib/thread/qmutex_unix.cpp | 53 |
2 files changed, 59 insertions, 2 deletions
diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 57a6062..e23be94 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -58,6 +58,10 @@ #include <QtCore/qnamespace.h> #include <QtCore/qmutex.h> +#if defined(Q_OS_MAC) +# include <mach/semaphore.h> +#endif + QT_BEGIN_NAMESPACE class QMutexPrivate : public QMutexData { @@ -72,7 +76,9 @@ public: Qt::HANDLE owner; uint count; -#if defined(Q_OS_UNIX) +#if defined(Q_OS_MAC) + semaphore_t mach_semaphore; +#elif defined(Q_OS_UNIX) volatile bool wakeup; pthread_mutex_t mutex; pthread_cond_t cond; diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index dcf8b9f..ce1bfc2 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -53,28 +53,77 @@ #undef wakeup #endif +#if defined(Q_OS_MAC) +# include <mach/mach.h> +# include <mach/task.h> +#endif + QT_BEGIN_NAMESPACE +#if !defined(Q_OS_MAC) static void report_error(int code, const char *where, const char *what) { if (code != 0) qWarning("%s: %s failure: %s", where, what, qPrintable(qt_error_string(code))); } +#endif QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) - : QMutexData(mode), lastSpinCount(0), owner(0), count(0), wakeup(false) + : QMutexData(mode), lastSpinCount(0), owner(0), count(0) { +#if defined(Q_OS_MAC) + kern_return_t r = semaphore_create(mach_task_self(), &mach_semaphore, SYNC_POLICY_FIFO, 0); + if (r != KERN_SUCCESS) + qWarning("QMutex: failed to create semaphore, error %d", r); +#else + wakeup = false; report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); +#endif } QMutexPrivate::~QMutexPrivate() { +#if defined(Q_OS_MAC) + kern_return_t r = semaphore_destroy(mach_task_self(), mach_semaphore); + if (r != KERN_SUCCESS) + qWarning("QMutex: failed to destroy semaphore, error %d", r); +#else report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy"); report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy"); +#endif } +#if defined(Q_OS_MAC) + +bool QMutexPrivate::wait(int timeout) +{ + if (contenders.fetchAndAddAcquire(1) == 0) { + // lock acquired without waiting + return true; + } + bool returnValue; + if (timeout < 0) { + returnValue = semaphore_wait(mach_semaphore) == KERN_SUCCESS; + } else { + mach_timespec_t ts; + ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; + ts.tv_sec = (timeout / 1000); + kern_return_t r = semaphore_timedwait(mach_semaphore, ts); + returnValue = r == KERN_SUCCESS; + } + contenders.deref(); + return returnValue; +} + +void QMutexPrivate::wakeUp() +{ + semaphore_signal(mach_semaphore); +} + +#else // !Q_OS_MAC + bool QMutexPrivate::wait(int timeout) { if (contenders.fetchAndAddAcquire(1) == 0) { @@ -117,6 +166,8 @@ void QMutexPrivate::wakeUp() report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); } +#endif // !Q_OS_MAC + QT_END_NAMESPACE #endif // QT_NO_THREAD |