diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/compat/removed_api.cpp | 1 | ||||
-rw-r--r-- | src/corelib/thread/qmutex.cpp | 68 | ||||
-rw-r--r-- | src/corelib/thread/qmutex.h | 46 | ||||
-rw-r--r-- | src/corelib/thread/qmutex_mac.cpp | 11 | ||||
-rw-r--r-- | src/corelib/thread/qmutex_p.h | 2 | ||||
-rw-r--r-- | src/corelib/thread/qmutex_unix.cpp | 11 |
6 files changed, 106 insertions, 33 deletions
diff --git a/src/corelib/compat/removed_api.cpp b/src/corelib/compat/removed_api.cpp index d810da59e8..1212aef1cb 100644 --- a/src/corelib/compat/removed_api.cpp +++ b/src/corelib/compat/removed_api.cpp @@ -603,6 +603,7 @@ QStringView QXmlStreamAttributes::value(QLatin1StringView qualifiedName) const // inlined API #if QT_CONFIG(thread) +#include "qmutex.h" #include "qreadwritelock.h" #endif diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 293a4a772a..b794d79e23 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -146,6 +146,23 @@ void QBasicMutex::destroyInternal(QMutexPrivate *d) \sa lock(), unlock() */ +/*! \fn bool QMutex::tryLock(QDeadlineTimer timer) + \since 6.6 + + Attempts to lock the mutex. This function returns \c true if the lock + was obtained; otherwise it returns \c false. If another thread has + locked the mutex, this function will wait until \a timer expires + for the mutex to become available. + + If the lock was obtained, the mutex must be unlocked with unlock() + before another thread can successfully lock it. + + Calling this function multiple times on the same mutex from the + same thread will cause a \e dead-lock. + + \sa lock(), unlock() +*/ + /*! \fn bool QMutex::tryLock() \overload @@ -279,6 +296,8 @@ QRecursiveMutex::~QRecursiveMutex() */ /*! + \fn QRecursiveMutex::tryLock(int timeout) + Attempts to lock the mutex. This function returns \c true if the lock was obtained; otherwise it returns \c false. If another thread has locked the mutex, this function will wait for at most \a timeout @@ -296,7 +315,24 @@ QRecursiveMutex::~QRecursiveMutex() \sa lock(), unlock() */ -bool QRecursiveMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT + +/*! + \since 6.6 + + Attempts to lock the mutex. This function returns \c true if the lock + was obtained; otherwise it returns \c false. If another thread has + locked the mutex, this function will wait until \a timeout expires + for the mutex to become available. + + If the lock was obtained, the mutex must be unlocked with unlock() + before another thread can successfully lock it. + + Calling this function multiple times on the same mutex from the + same thread is allowed. + + \sa lock(), unlock() +*/ +bool QRecursiveMutex::tryLock(QDeadlineTimer timeout) QT_MUTEX_LOCK_NOEXCEPT { unsigned tsanFlags = QtTsan::MutexWriteReentrant | QtTsan::TryLock; QtTsan::mutexPreLock(this, tsanFlags); @@ -309,7 +345,7 @@ bool QRecursiveMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT return true; } bool success = true; - if (timeout == -1) { + if (timeout.isForever()) { mutex.lock(); } else { success = mutex.tryLock(timeout); @@ -622,25 +658,37 @@ void QBasicMutex::lockInternal() QT_MUTEX_LOCK_NOEXCEPT /*! \internal helper for lock(int) */ +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT { if (timeout == 0) return false; + return lockInternal(QDeadlineTimer(timeout)); +} +#endif + +/*! + \internal helper for tryLock(QDeadlineTimer) + */ +bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT +{ + qint64 remainingTime = deadlineTimer.remainingTimeNSecs(); + if (remainingTime == 0) + return false; + if (futexAvailable()) { - if (Q_UNLIKELY(timeout < 0)) { + if (Q_UNLIKELY(remainingTime < 0)) { // deadlineTimer.isForever() lockInternal(); return true; } - QDeadlineTimer deadlineTimer(timeout); // The mutex is already locked, set a bit indicating we're waiting. // Note we must set to dummyFutexValue because there could be other threads // also waiting. if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr) return true; - qint64 remainingTime = deadlineTimer.remainingTimeNSecs(); Q_FOREVER { if (!futexWait(d_ptr, dummyFutexValue(), remainingTime)) return false; @@ -665,7 +713,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT continue; if (copy == dummyLocked()) { - if (timeout == 0) + if (remainingTime == 0) return false; // The mutex is locked but does not have a QMutexPrivate yet. // we need to allocate a QMutexPrivate @@ -680,7 +728,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT } QMutexPrivate *d = static_cast<QMutexPrivate *>(copy); - if (timeout == 0 && !d->possiblyUnlocked.loadRelaxed()) + if (remainingTime == 0 && !d->possiblyUnlocked.loadRelaxed()) return false; // At this point we have a pointer to a QMutexPrivate. But the other thread @@ -733,7 +781,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT continue; } - if (d->wait(timeout)) { + if (d->wait(deadlineTimer)) { // reset the possiblyUnlocked flag if needed (and deref its corresponding reference) if (d->possiblyUnlocked.loadRelaxed() && d->possiblyUnlocked.testAndSetRelaxed(true, false)) d->deref(); @@ -742,8 +790,8 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT Q_ASSERT(d == d_ptr.loadRelaxed()); return true; } else { - Q_ASSERT(timeout >= 0); - //timeout + Q_ASSERT(remainingTime >= 0); + // timed out d->derefWaiters(1); //There may be a race in which the mutex is unlocked right after we timed out, // and before we deref the waiters, so maybe the mutex is actually unlocked. diff --git a/src/corelib/thread/qmutex.h b/src/corelib/thread/qmutex.h index e185041b13..18ffdd2cf4 100644 --- a/src/corelib/thread/qmutex.h +++ b/src/corelib/thread/qmutex.h @@ -6,6 +6,7 @@ #include <QtCore/qglobal.h> #include <QtCore/qatomic.h> +#include <QtCore/qdeadlinetimer.h> #include <QtCore/qtsan_impl.h> #include <new> @@ -110,7 +111,10 @@ private: } void lockInternal() QT_MUTEX_LOCK_NOEXCEPT; + bool lockInternal(QDeadlineTimer timeout) QT_MUTEX_LOCK_NOEXCEPT; +#if QT_VERSION < QT_VERSION_CHECK(7, 0, 0) bool lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT; +#endif void unlockInternal() noexcept; void destroyInternal(QMutexPrivate *d); @@ -147,6 +151,11 @@ public: using QBasicMutex::tryLock; bool tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT { + return tryLock(QDeadlineTimer(timeout)); + } + + bool tryLock(QDeadlineTimer timeout) QT_MUTEX_LOCK_NOEXCEPT + { unsigned tsanFlags = QtTsan::TryLock; QtTsan::mutexPreLock(this, tsanFlags); @@ -166,21 +175,24 @@ public: return success; } +#ifndef Q_QDOC + // because tryLock(QDeadlineTimer::Forever) is tryLock(0) + bool tryLock(QDeadlineTimer::ForeverConstant) QT_MUTEX_LOCK_NOEXCEPT + { lock(); return true; } +#endif + // TimedLockable concept template <class Rep, class Period> bool try_lock_for(std::chrono::duration<Rep, Period> duration) { - return tryLock(QtPrivate::convertToMilliseconds(duration)); + return tryLock(QDeadlineTimer(duration)); } // TimedLockable concept template<class Clock, class Duration> bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) { - // Implemented in terms of try_lock_for to honor the similar - // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12. - - return try_lock_for(timePoint - Clock::now()); + return tryLock(QDeadlineTimer(timePoint)); } }; @@ -201,8 +213,10 @@ public: // BasicLockable concept void lock() QT_MUTEX_LOCK_NOEXCEPT - { tryLock(-1); } + { tryLock(QDeadlineTimer(QDeadlineTimer::Forever)); } + QT_CORE_INLINE_SINCE(6, 6) bool tryLock(int timeout = 0) QT_MUTEX_LOCK_NOEXCEPT; + bool tryLock(QDeadlineTimer timer) QT_MUTEX_LOCK_NOEXCEPT; // BasicLockable concept void unlock() noexcept; @@ -213,20 +227,30 @@ public: template <class Rep, class Period> bool try_lock_for(std::chrono::duration<Rep, Period> duration) { - return tryLock(QtPrivate::convertToMilliseconds(duration)); + return tryLock(QDeadlineTimer(duration)); } // TimedLockable concept template<class Clock, class Duration> bool try_lock_until(std::chrono::time_point<Clock, Duration> timePoint) { - // Implemented in terms of try_lock_for to honor the similar - // requirement in N4606 § 30.4.1.3 [thread.timedmutex.requirements]/12. - - return try_lock_for(timePoint - Clock::now()); + return tryLock(QDeadlineTimer(timePoint)); } + +#ifndef Q_QDOC + // because tryLock(QDeadlineTimer::Forever) is tryLock(0) + bool tryLock(QDeadlineTimer::ForeverConstant) QT_MUTEX_LOCK_NOEXCEPT + { lock(); return true; } +#endif }; +#if QT_CORE_INLINE_IMPL_SINCE(6, 6) +bool QRecursiveMutex::tryLock(int timeout) QT_MUTEX_LOCK_NOEXCEPT +{ + return tryLock(QDeadlineTimer(timeout)); +} +#endif + template <typename Mutex> class [[nodiscard]] QMutexLocker { diff --git a/src/corelib/thread/qmutex_mac.cpp b/src/corelib/thread/qmutex_mac.cpp index a9e2330bf6..7849133e58 100644 --- a/src/corelib/thread/qmutex_mac.cpp +++ b/src/corelib/thread/qmutex_mac.cpp @@ -5,6 +5,8 @@ #include "qmutex.h" #include "qmutex_p.h" +#include "private/qcore_unix_p.h" + #include <mach/mach.h> #include <mach/task.h> @@ -26,18 +28,19 @@ QMutexPrivate::~QMutexPrivate() qWarning("QMutex: failed to destroy semaphore, error %d", r); } -bool QMutexPrivate::wait(int timeout) +bool QMutexPrivate::wait(QDeadlineTimer timeout) { kern_return_t r; - if (timeout < 0) { + if (timeout.isForever()) { do { r = semaphore_wait(mach_semaphore); } while (r == KERN_ABORTED); Q_ASSERT(r == KERN_SUCCESS); } else { + timespec tv = durationToTimespec(timeout.remainingTimeAsDuration()); mach_timespec_t ts; - ts.tv_nsec = ((timeout % 1000) * 1000) * 1000; - ts.tv_sec = (timeout / 1000); + ts.tv_nsec = tv.tv_nsec; + ts.tv_sec = tv.tv_sec; r = semaphore_timedwait(mach_semaphore, ts); } return (r == KERN_SUCCESS); diff --git a/src/corelib/thread/qmutex_p.h b/src/corelib/thread/qmutex_p.h index e02686ad68..aabb66fa55 100644 --- a/src/corelib/thread/qmutex_p.h +++ b/src/corelib/thread/qmutex_p.h @@ -43,7 +43,7 @@ public: ~QMutexPrivate(); QMutexPrivate(); - bool wait(int timeout = -1); + bool wait(QDeadlineTimer timeout = QDeadlineTimer::Forever); void wakeUp() noexcept; // Control the lifetime of the privates diff --git a/src/corelib/thread/qmutex_unix.cpp b/src/corelib/thread/qmutex_unix.cpp index 0cbf462527..bad8b5dddc 100644 --- a/src/corelib/thread/qmutex_unix.cpp +++ b/src/corelib/thread/qmutex_unix.cpp @@ -36,21 +36,18 @@ QMutexPrivate::~QMutexPrivate() report_error(sem_destroy(&semaphore), "QMutex", "sem_destroy"); } -bool QMutexPrivate::wait(int timeout) +bool QMutexPrivate::wait(QDeadlineTimer timeout) { int errorCode; - if (timeout < 0) { + if (timeout.isForever()) { 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 { + auto tp = timeout.deadline<std::chrono::system_clock>(); + timespec ts = durationToTimespec(tp.time_since_epoch()); errorCode = sem_timedwait(&semaphore, &ts); } while (errorCode && errno == EINTR); |