From c28204066c2d3bae989132ab15e8df437ae38f3d Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Thu, 2 Aug 2012 16:15:22 +0200 Subject: Mark mutex locking and unlocking functions with noexcept Unlocking a mutex can never throw an exception. That doesn't make sense and our code should make sure it can't happen. Right now, provided that the system-level functions don't throw, we don't either. Locking a mutex cannot throw on Linux because we use futexes directly. A non-recursive mutex is just a futex, whereas a recursive mutex uses a mutex (a futex) to manage a lock count. However, on other platforms, due to the freelist, there can be memory allocation, which means it might throw std::bad_alloc. Not because of the freelist itself (that uses malloc and will just crash if malloc fails) but because of Q_GLOBAL_STATIC. In 5.1, the global static will be noexcept provided the type's constructor is so too (it is, in this case). Change-Id: I4c562383f48de1be7827b9afb512d73eaf0792d5 Reviewed-by: Marc Mutz Reviewed-by: Thiago Macieira --- src/corelib/thread/qmutex.cpp | 18 +++++++++--------- src/corelib/thread/qmutex.h | 32 ++++++++++++++++++-------------- src/corelib/thread/qmutex_linux.cpp | 6 +++--- src/corelib/thread/qmutex_mac.cpp | 2 +- src/corelib/thread/qmutex_p.h | 8 ++++---- src/corelib/thread/qmutex_unix.cpp | 2 +- src/corelib/thread/qmutex_win.cpp | 2 +- 7 files changed, 37 insertions(+), 33 deletions(-) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index a88e3ceef9..1d35b76c92 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -68,7 +68,6 @@ QT_BEGIN_NAMESPACE - Do not use tryLock with timeout > 0, else you can have a leak (see the ~QMutex destructor) */ - /*! \class QMutex \inmodule QtCore @@ -179,7 +178,7 @@ QMutex::~QMutex() \sa unlock() */ -void QMutex::lock() +void QMutex::lock() QT_MUTEX_LOCK_NOEXCEPT { QBasicMutex::lock(); } @@ -207,7 +206,7 @@ void QMutex::lock() \sa lock(), unlock() */ -bool QMutex::tryLock(int timeout) +bool QMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT { return QBasicMutex::tryLock(timeout); } @@ -219,7 +218,7 @@ bool QMutex::tryLock(int timeout) \sa lock() */ -void QMutex::unlock() +void QMutex::unlock() Q_DECL_NOTHROW { QBasicMutex::unlock(); } @@ -332,7 +331,7 @@ bool QBasicMutex::isRecursive() { /*! \internal helper for lock() */ -bool QBasicMutex::lockInternal(int timeout) +bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT { while (!fastTryLock()) { QMutexData *copy = d_ptr.loadAcquire(); @@ -425,7 +424,7 @@ bool QBasicMutex::lockInternal(int timeout) /*! \internal */ -void QBasicMutex::unlockInternal() +void QBasicMutex::unlockInternal() Q_DECL_NOTHROW { QMutexData *copy = d_ptr.loadAcquire(); Q_ASSERT(copy); //we must be locked @@ -493,7 +492,7 @@ void QMutexPrivate::release() } // atomically subtract "value" to the waiters, and remove the QMutexPrivate::BigNumber flag -void QMutexPrivate::derefWaiters(int value) +void QMutexPrivate::derefWaiters(int value) Q_DECL_NOTHROW { int old_waiters; int new_waiters; @@ -511,7 +510,8 @@ void QMutexPrivate::derefWaiters(int value) /*! \internal */ -bool QRecursiveMutexPrivate::lock(int timeout) { +bool QRecursiveMutexPrivate::lock(int timeout) QT_MUTEX_LOCK_NOEXCEPT +{ Qt::HANDLE self = QThread::currentThreadId(); if (owner == self) { ++count; @@ -533,7 +533,7 @@ bool QRecursiveMutexPrivate::lock(int timeout) { /*! \internal */ -void QRecursiveMutexPrivate::unlock() +void QRecursiveMutexPrivate::unlock() Q_DECL_NOTHROW { if (count > 0) { count--; diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index 4fe4df09c6..5d4d6969f5 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -53,34 +53,40 @@ QT_BEGIN_NAMESPACE #if !defined(QT_NO_THREAD) && !defined(qdoc) +#ifdef Q_OS_LINUX +# define QT_MUTEX_LOCK_NOEXCEPT Q_DECL_NOTHROW +#else +# define QT_MUTEX_LOCK_NOEXCEPT +#endif + class QMutexData; class Q_CORE_EXPORT QBasicMutex { public: - inline void lock() { + inline void lock() QT_MUTEX_LOCK_NOEXCEPT { if (!fastTryLock()) lockInternal(); } - inline void unlock() { + inline void unlock() Q_DECL_NOTHROW { Q_ASSERT(d_ptr.load()); //mutex must be locked if (!d_ptr.testAndSetRelease(dummyLocked(), 0)) unlockInternal(); } - bool tryLock(int timeout = 0) { + bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT { return fastTryLock() || lockInternal(timeout); } bool isRecursive(); private: - inline bool fastTryLock() { + inline bool fastTryLock() Q_DECL_NOTHROW { return d_ptr.testAndSetAcquire(0, dummyLocked()); } - bool lockInternal(int timeout = -1); - void unlockInternal(); + bool lockInternal(int timeout = -1) QT_MUTEX_LOCK_NOEXCEPT; + void unlockInternal() Q_DECL_NOTHROW; QBasicAtomicPointer d_ptr; static inline QMutexData *dummyLocked() { @@ -97,9 +103,9 @@ public: explicit QMutex(RecursionMode mode = NonRecursive); ~QMutex(); - void lock(); - bool tryLock(int timeout = 0); - void unlock(); + void lock() QT_MUTEX_LOCK_NOEXCEPT; + bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT; + void unlock() Q_DECL_NOTHROW; using QBasicMutex::isRecursive; @@ -111,7 +117,7 @@ private: class Q_CORE_EXPORT QMutexLocker { public: - inline explicit QMutexLocker(QBasicMutex *m) + inline explicit QMutexLocker(QBasicMutex *m) QT_MUTEX_LOCK_NOEXCEPT { Q_ASSERT_X((reinterpret_cast(m) & quintptr(1u)) == quintptr(0), "QMutexLocker", "QMutex pointer is misaligned"); @@ -124,7 +130,7 @@ public: } inline ~QMutexLocker() { unlock(); } - inline void unlock() + inline void unlock() Q_DECL_NOTHROW { if ((val & quintptr(1u)) == quintptr(1u)) { val &= ~quintptr(1u); @@ -132,7 +138,7 @@ public: } } - inline void relock() + inline void relock() QT_MUTEX_LOCK_NOEXCEPT { if (val) { if ((val & quintptr(1u)) == quintptr(0u)) { @@ -162,8 +168,6 @@ private: quintptr val; }; - - #else // QT_NO_THREAD or qdoc class Q_CORE_EXPORT QMutex diff --git a/src/corelib/thread/qmutex_linux.cpp b/src/corelib/thread/qmutex_linux.cpp index a10bd35eff..3ccaeff4e3 100644 --- a/src/corelib/thread/qmutex_linux.cpp +++ b/src/corelib/thread/qmutex_linux.cpp @@ -87,7 +87,7 @@ static inline int futexFlags() return value; } -static inline int _q_futex(void *addr, int op, int val, const struct timespec *timeout) +static inline int _q_futex(void *addr, int op, int val, const struct timespec *timeout) Q_DECL_NOTHROW { volatile int *int_addr = reinterpret_cast(addr); #if Q_BYTE_ORDER == Q_BIG_ENDIAN && QT_POINTER_SIZE == 8 @@ -106,7 +106,7 @@ static inline QMutexData *dummyFutexValue() return reinterpret_cast(quintptr(3)); } -bool QBasicMutex::lockInternal(int timeout) +bool QBasicMutex::lockInternal(int timeout) Q_DECL_NOTHROW { QElapsedTimer elapsedTimer; if (timeout >= 1) @@ -147,7 +147,7 @@ bool QBasicMutex::lockInternal(int timeout) return true; } -void QBasicMutex::unlockInternal() +void QBasicMutex::unlockInternal() Q_DECL_NOTHROW { QMutexData *d = d_ptr.load(); Q_ASSERT(d); //we must be locked diff --git a/src/corelib/thread/qmutex_mac.cpp b/src/corelib/thread/qmutex_mac.cpp index ecd3442d91..a828499ebd 100644 --- a/src/corelib/thread/qmutex_mac.cpp +++ b/src/corelib/thread/qmutex_mac.cpp @@ -84,7 +84,7 @@ bool QMutexPrivate::wait(int timeout) return (r == KERN_SUCCESS); } -void QMutexPrivate::wakeUp() +void QMutexPrivate::wakeUp() Q_DECL_NOTHROW { semaphore_signal(mach_semaphore); } diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index 92f13b1b7d..3ef99d5fc0 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -86,7 +86,7 @@ public: QMutexPrivate(); bool wait(int timeout = -1); - void wakeUp(); + void wakeUp() Q_DECL_NOTHROW; // Conrol the lifetime of the privates QAtomicInt refCount; @@ -115,7 +115,7 @@ public: QAtomicInt waiters; //number of thread waiting QAtomicInt possiblyUnlocked; //bool saying that a timed wait timed out enum { BigNumber = 0x100000 }; //Must be bigger than the possible number of waiters (number of threads) - void derefWaiters(int value); + void derefWaiters(int value) Q_DECL_NOTHROW; //platform specific stuff #if defined(Q_OS_MAC) @@ -139,8 +139,8 @@ public: uint count; QMutex mutex; - bool lock(int timeout); - void unlock(); + bool lock(int timeout) QT_MUTEX_LOCK_NOEXCEPT; + void unlock() Q_DECL_NOTHROW; }; QT_END_NAMESPACE diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index 0347d4b3da..6c74c68d8e 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -104,7 +104,7 @@ bool QMutexPrivate::wait(int timeout) return ret; } -void QMutexPrivate::wakeUp() +void QMutexPrivate::wakeUp() Q_DECL_NOTHROW { report_error(pthread_mutex_lock(&mutex), "QMutex::unlock", "mutex lock"); wakeup = true; diff --git a/src/corelib/thread/qmutex_win.cpp b/src/corelib/thread/qmutex_win.cpp index 1fdf97b0d0..0e06c6a26e 100644 --- a/src/corelib/thread/qmutex_win.cpp +++ b/src/corelib/thread/qmutex_win.cpp @@ -61,7 +61,7 @@ bool QMutexPrivate::wait(int timeout) return (WaitForSingleObject(event, timeout < 0 ? INFINITE : timeout) == WAIT_OBJECT_0); } -void QMutexPrivate::wakeUp() +void QMutexPrivate::wakeUp() Q_DECL_NOTHROW { SetEvent(event); } QT_END_NAMESPACE -- cgit v1.2.3