qmutex_unix: use a semaphore when available

It makes tst_QMutex::contendedQMutex with no msleep 8 times faster

Change-Id: Ic300e7618b4467e4e08b30f0213bd23c06d4d90a
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Olivier Goffart 2015-11-06 12:19:19 +01:00 committed by Olivier Goffart (Woboq GmbH)
parent e0c8316e17
commit c7ab816af1
2 changed files with 56 additions and 3 deletions

View File

@ -55,11 +55,14 @@
#if defined(Q_OS_MAC) #if defined(Q_OS_MAC)
# include <mach/semaphore.h> # include <mach/semaphore.h>
#endif #elif defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
// use Linux mutexes everywhere except for LSB builds // use Linux mutexes everywhere except for LSB builds
# define QT_LINUX_FUTEX # define QT_LINUX_FUTEX
#elif defined(Q_OS_UNIX)
# if _POSIX_VERSION-0 >= 200112L || _XOPEN_VERSION-0 >= 600
# include <semaphore.h>
# define QT_UNIX_SEMAPHORE
# endif
#endif #endif
struct timespec; struct timespec;
@ -120,6 +123,8 @@ public:
//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(QT_UNIX_SEMAPHORE)
sem_t semaphore;
#elif defined(Q_OS_UNIX) #elif defined(Q_OS_UNIX)
bool wakeup; bool wakeup;
pthread_mutex_t mutex; pthread_mutex_t mutex;

View File

@ -1,6 +1,7 @@
/**************************************************************************** /****************************************************************************
** **
** Copyright (C) 2015 The Qt Company Ltd. ** Copyright (C) 2015 The Qt Company Ltd.
** Copyright (C) 2015 Olivier Goffart <ogoffart@woboq.com>
** Contact: http://www.qt.io/licensing/ ** Contact: http://www.qt.io/licensing/
** **
** This file is part of the QtCore module of the Qt Toolkit. ** This file is part of the QtCore module of the Qt Toolkit.
@ -42,6 +43,7 @@
#include <errno.h> #include <errno.h>
#include <sys/time.h> #include <sys/time.h>
#include <time.h> #include <time.h>
#include "private/qcore_unix_p.h"
#if defined(Q_OS_VXWORKS) && defined(wakeup) #if defined(Q_OS_VXWORKS) && defined(wakeup)
#undef wakeup #undef wakeup
@ -55,6 +57,51 @@ 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)));
} }
#ifdef QT_UNIX_SEMAPHORE
QMutexPrivate::QMutexPrivate()
{
report_error(sem_init(&semaphore, 0, 0), "QMutex", "sem_init");
}
QMutexPrivate::~QMutexPrivate()
{
report_error(sem_destroy(&semaphore), "QMutex", "sem_destroy");
}
bool QMutexPrivate::wait(int timeout)
{
int errorCode;
if (timeout < 0) {
do {
errorCode = sem_wait(&semaphore);
} while (errorCode && errno == EINTR);
report_error(errorCode, "QMutex::lock()", "sem_wait");
} else {
timespec ts;
report_error(clock_gettime(CLOCK_REALTIME, &ts), "QMutex::lock()", "clock_gettime");
ts.tv_sec += timeout / 1000;
ts.tv_nsec += timeout % 1000 * Q_UINT64_C(1000) * 1000;
normalizedTimespec(ts);
do {
errorCode = sem_timedwait(&semaphore, &ts);
} while (errorCode && errno == EINTR);
if (errorCode && errno == ETIMEDOUT)
return false;
report_error(errorCode, "QMutex::lock()", "sem_timedwait");
}
return true;
}
void QMutexPrivate::wakeUp() Q_DECL_NOTHROW
{
report_error(sem_post(&semaphore), "QMutex::unlock", "sem_post");
}
#else // QT_UNIX_SEMAPHORE
QMutexPrivate::QMutexPrivate() QMutexPrivate::QMutexPrivate()
: wakeup(false) : wakeup(false)
{ {
@ -103,6 +150,7 @@ void QMutexPrivate::wakeUp() Q_DECL_NOTHROW
report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock");
} }
#endif
QT_END_NAMESPACE QT_END_NAMESPACE