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 <marc.mutz@kdab.com>
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
Thiago Macieira 2012-08-02 16:15:22 +02:00 committed by Qt by Nokia
parent 98437f0e2e
commit c28204066c
7 changed files with 37 additions and 33 deletions

View File

@ -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--;

View File

@ -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<QMutexData> 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<quintptr>(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

View File

@ -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<volatile int *>(addr);
#if Q_BYTE_ORDER == Q_BIG_ENDIAN && QT_POINTER_SIZE == 8
@ -106,7 +106,7 @@ static inline QMutexData *dummyFutexValue()
return reinterpret_cast<QMutexData *>(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

View File

@ -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);
}

View File

@ -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

View File

@ -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;

View File

@ -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