From 96c76839f9870f44790bbd1936a96c0d5200b6ad Mon Sep 17 00:00:00 2001 From: Thiago Macieira Date: Sat, 10 Jun 2023 09:47:25 -0700 Subject: Switch futex support to QDeadlineTimer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This allows us to use absolute times on Linux (today) and FreeBSD (soon), plus simplifies both QMutex and QSemaphore. Change-Id: I63b988479db546dabffcfffd17675a182aa528fa Reviewed-by: Ahmad Samir Reviewed-by: Qt CI Bot Reviewed-by: MÃ¥rten Nordheim --- src/corelib/global/minimum-linux_p.h | 1 + src/corelib/thread/qfutex_linux_p.h | 9 +++++---- src/corelib/thread/qfutex_p.h | 5 ++--- src/corelib/thread/qfutex_win_p.h | 9 +++------ src/corelib/thread/qmutex.cpp | 15 +++++---------- src/corelib/thread/qsemaphore.cpp | 9 +++------ 6 files changed, 19 insertions(+), 29 deletions(-) diff --git a/src/corelib/global/minimum-linux_p.h b/src/corelib/global/minimum-linux_p.h index 509ad792f7..e8c872bc4a 100644 --- a/src/corelib/global/minimum-linux_p.h +++ b/src/corelib/global/minimum-linux_p.h @@ -35,6 +35,7 @@ QT_BEGIN_NAMESPACE * - FUTEX_PRIVATE_FLAG 2.6.22 * - O_CLOEXEC 2.6.23 * - eventfd 2.6.23 + * - FUTEX_WAIT_BITSET 2.6.25 * - pipe2 & dup3 2.6.27 * - accept4 2.6.28 * - renameat2 3.16 QT_CONFIG(renameat2) diff --git a/src/corelib/thread/qfutex_linux_p.h b/src/corelib/thread/qfutex_linux_p.h index 9291c67623..e114dfca72 100644 --- a/src/corelib/thread/qfutex_linux_p.h +++ b/src/corelib/thread/qfutex_linux_p.h @@ -16,10 +16,9 @@ // #include +#include #include -#include - #include #include #include @@ -68,10 +67,12 @@ inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue) _q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue)); } template -inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, std::chrono::nanoseconds timeout) +inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, QDeadlineTimer deadline) { + auto timeout = deadline.deadline().time_since_epoch(); struct timespec ts = durationToTimespec(timeout); - int r = _q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue), quintptr(&ts)); + int r = _q_futex(addr(&futex), FUTEX_WAIT_BITSET, qintptr(expectedValue), quintptr(&ts), + nullptr, FUTEX_BITSET_MATCH_ANY); return r == 0 || errno != ETIMEDOUT; } template inline void futexWakeOne(Atomic &futex) diff --git a/src/corelib/thread/qfutex_p.h b/src/corelib/thread/qfutex_p.h index 05ddede641..f7130ebad2 100644 --- a/src/corelib/thread/qfutex_p.h +++ b/src/corelib/thread/qfutex_p.h @@ -15,16 +15,15 @@ // We mean it. // +#include #include -#include - QT_BEGIN_NAMESPACE namespace QtDummyFutex { constexpr inline bool futexAvailable() { return false; } template - inline bool futexWait(Atomic &, typename Atomic::Type, std::chrono::nanoseconds = {}) + inline bool futexWait(Atomic &, typename Atomic::Type, QDeadlineTimer = {}) { Q_UNREACHABLE_RETURN(false); } template inline void futexWakeOne(Atomic &) { Q_UNREACHABLE(); } diff --git a/src/corelib/thread/qfutex_win_p.h b/src/corelib/thread/qfutex_win_p.h index a5ce142d28..75a12bd82c 100644 --- a/src/corelib/thread/qfutex_win_p.h +++ b/src/corelib/thread/qfutex_win_p.h @@ -16,10 +16,9 @@ // #include +#include #include -#include - #include #define QT_ALWAYS_USE_FUTEX @@ -37,12 +36,10 @@ inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue) QtTsan::futexAcquire(&futex); } template -inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, std::chrono::nanoseconds timeout) +inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, QDeadlineTimer deadline) { using namespace std::chrono; - // Using ceil so that any non-zero timeout doesn't get trunated to 0ms - auto msecs = ceil(timeout); - BOOL r = WaitOnAddress(&futex, &expectedValue, sizeof(expectedValue), DWORD(msecs.count())); + BOOL r = WaitOnAddress(&futex, &expectedValue, sizeof(expectedValue), DWORD(deadline.remainingTime())); return r || GetLastError() != ERROR_TIMEOUT; } template inline void futexWakeAll(Atomic &futex) diff --git a/src/corelib/thread/qmutex.cpp b/src/corelib/thread/qmutex.cpp index 7058e890e0..f1fb38118f 100644 --- a/src/corelib/thread/qmutex.cpp +++ b/src/corelib/thread/qmutex.cpp @@ -673,9 +673,7 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT */ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT { - using namespace std::chrono; - nanoseconds remainingTime = deadlineTimer.remainingTimeAsDuration(); - if (remainingTime == 0ns) + if (deadlineTimer.hasExpired()) return false; if (futexAvailable()) { @@ -691,7 +689,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC return true; for (;;) { - if (!futexWait(d_ptr, dummyFutexValue(), remainingTime)) + if (!futexWait(d_ptr, dummyFutexValue(), deadlineTimer)) return false; // We got woken up, so must try to acquire the mutex. We must set @@ -700,9 +698,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr) return true; - // calculate the remaining time - remainingTime = deadlineTimer.remainingTimeAsDuration(); - if (remainingTime == 0ns) + if (deadlineTimer.hasExpired()) return false; } } @@ -714,7 +710,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC continue; if (copy == dummyLocked()) { - if (remainingTime == 0ns) + if (deadlineTimer.hasExpired()) return false; // The mutex is locked but does not have a QMutexPrivate yet. // we need to allocate a QMutexPrivate @@ -729,7 +725,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC } QMutexPrivate *d = static_cast(copy); - if (remainingTime == 0ns && !d->possiblyUnlocked.loadRelaxed()) + if (deadlineTimer.hasExpired() && !d->possiblyUnlocked.loadRelaxed()) return false; // At this point we have a pointer to a QMutexPrivate. But the other thread @@ -791,7 +787,6 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC Q_ASSERT(d == d_ptr.loadRelaxed()); return true; } else { - Q_ASSERT(remainingTime >= 0ns); // timed out d->derefWaiters(1); //There may be a race in which the mutex is unlocked right after we timed out, diff --git a/src/corelib/thread/qsemaphore.cpp b/src/corelib/thread/qsemaphore.cpp index e09750581e..c472e62698 100644 --- a/src/corelib/thread/qsemaphore.cpp +++ b/src/corelib/thread/qsemaphore.cpp @@ -149,7 +149,6 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger &u, quintptr curValu QDeadlineTimer timer) { using namespace std::chrono; - nanoseconds remainingTime = IsTimed ? timer.remainingTimeAsDuration() : -1ns; int n = int(unsigned(nn)); // we're called after one testAndSet, so start by waiting first @@ -166,8 +165,8 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger &u, quintptr curValu } } - if (IsTimed && remainingTime > 0ns) { - bool timedout = !futexWait(*ptr, curValue, remainingTime); + if (IsTimed) { + bool timedout = !futexWait(*ptr, curValue, timer); if (timedout) return false; } else { @@ -175,8 +174,6 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger &u, quintptr curValu } curValue = u.loadAcquire(); - if (IsTimed) - remainingTime = timer.remainingTimeAsDuration(); // try to acquire while (futexAvailCounter(curValue) >= n) { @@ -186,7 +183,7 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger &u, quintptr curValu } // not enough tokens available, put us to wait - if (IsTimed && remainingTime == 0ns) + if (IsTimed && timer.hasExpired()) return false; } } -- cgit v1.2.3