diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/thread/qmutex_p.h | 2 | ||||
-rw-r--r-- | src/corelib/thread/qmutex_unix.cpp | 43 |
2 files changed, 39 insertions, 6 deletions
diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index e23be94..2d45cfb 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -78,7 +78,7 @@ public: #if defined(Q_OS_MAC) semaphore_t mach_semaphore; -#elif defined(Q_OS_UNIX) +#elif defined(Q_OS_UNIX) && !defined(Q_OS_LINUX) 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 ce1bfc2..e872187 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -56,11 +56,15 @@ #if defined(Q_OS_MAC) # include <mach/mach.h> # include <mach/task.h> +#elif defined(Q_OS_LINUX) +# include <linux/futex.h> +# include <sys/syscall.h> +# include <unistd.h> #endif QT_BEGIN_NAMESPACE -#if !defined(Q_OS_MAC) +#if !defined(Q_OS_MAC) && !defined(Q_OS_LINUX) static void report_error(int code, const char *where, const char *what) { if (code != 0) @@ -76,7 +80,7 @@ QMutexPrivate::QMutexPrivate(QMutex::RecursionMode mode) 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 +#elif !defined(Q_OS_LINUX) wakeup = false; report_error(pthread_mutex_init(&mutex, NULL), "QMutex", "mutex init"); report_error(pthread_cond_init(&cond, NULL), "QMutex", "cv init"); @@ -89,7 +93,7 @@ QMutexPrivate::~QMutexPrivate() 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 +#elif !defined(Q_OS_LINUX) report_error(pthread_cond_destroy(&cond), "QMutex", "cv destroy"); report_error(pthread_mutex_destroy(&mutex), "QMutex", "mutex destroy"); #endif @@ -122,7 +126,36 @@ void QMutexPrivate::wakeUp() semaphore_signal(mach_semaphore); } -#else // !Q_OS_MAC +#elif defined(Q_OS_LINUX) + +static inline int _q_futex(volatile int *addr, int op, int val, const struct timespec *timeout, int *addr2, int val2) +{ + return syscall(SYS_futex, addr, op, val, timeout, addr2, val2); +} + +bool QMutexPrivate::wait(int timeout) +{ + while (contenders.fetchAndStoreAcquire(2) > 0) { + struct timespec ts, *pts = 0; + if (timeout >= 0) { + ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; + ts.tv_sec = (timeout / 1000); + pts = &ts; + } + int r = _q_futex(&contenders._q_value, FUTEX_WAIT, 2, pts, 0, 0); + if (r != 0 && errno == ETIMEDOUT) + return false; + } + return true; +} + +void QMutexPrivate::wakeUp() +{ + (void) contenders.fetchAndStoreRelease(0); + (void) _q_futex(&contenders._q_value, FUTEX_WAKE, 1, 0, 0, 0); +} + +#else // !Q_OS_MAC && !Q_OS_LINUX bool QMutexPrivate::wait(int timeout) { @@ -166,7 +199,7 @@ void QMutexPrivate::wakeUp() report_error(pthread_mutex_unlock(&mutex), "QMutex::unlock", "mutex unlock"); } -#endif // !Q_OS_MAC +#endif // !Q_OS_MAC && !Q_OS_LINUX QT_END_NAMESPACE |