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:
parent
98437f0e2e
commit
c28204066c
@ -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--;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user