summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThiago Macieira <thiago.macieira@intel.com>2023-06-10 09:47:25 -0700
committerThiago Macieira <thiago.macieira@intel.com>2023-06-15 04:04:56 -0700
commit96c76839f9870f44790bbd1936a96c0d5200b6ad (patch)
treea1230d73a78fa4da13ed193cfdc00d2ead173fd4
parent585db639a407069c241e11351df1ed3d1e7b869e (diff)
Switch futex support to QDeadlineTimer
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 <a.samirh78@gmail.com> Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: MÃ¥rten Nordheim <marten.nordheim@qt.io>
-rw-r--r--src/corelib/global/minimum-linux_p.h1
-rw-r--r--src/corelib/thread/qfutex_linux_p.h9
-rw-r--r--src/corelib/thread/qfutex_p.h5
-rw-r--r--src/corelib/thread/qfutex_win_p.h9
-rw-r--r--src/corelib/thread/qmutex.cpp15
-rw-r--r--src/corelib/thread/qsemaphore.cpp9
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 <private/qcore_unix_p.h>
+#include <qdeadlinetimer.h>
#include <qtsan_impl.h>
-#include <chrono>
-
#include <asm/unistd.h>
#include <errno.h>
#include <limits.h>
@@ -68,10 +67,12 @@ inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
_q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue));
}
template <typename Atomic>
-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<std::chrono::steady_clock>().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 <typename Atomic> 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 <qdeadlinetimer.h>
#include <private/qglobal_p.h>
-#include <chrono>
-
QT_BEGIN_NAMESPACE
namespace QtDummyFutex {
constexpr inline bool futexAvailable() { return false; }
template <typename Atomic>
- inline bool futexWait(Atomic &, typename Atomic::Type, std::chrono::nanoseconds = {})
+ inline bool futexWait(Atomic &, typename Atomic::Type, QDeadlineTimer = {})
{ Q_UNREACHABLE_RETURN(false); }
template <typename Atomic> 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 <private/qglobal_p.h>
+#include <qdeadlinetimer.h>
#include <qtsan_impl.h>
-#include <chrono>
-
#include <qt_windows.h>
#define QT_ALWAYS_USE_FUTEX
@@ -37,12 +36,10 @@ inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
QtTsan::futexAcquire(&futex);
}
template <typename Atomic>
-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<milliseconds>(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 <typename Atomic> 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<QMutexPrivate *>(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<quintptr> &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<quintptr> &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<quintptr> &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<quintptr> &u, quintptr curValu
}
// not enough tokens available, put us to wait
- if (IsTimed && remainingTime == 0ns)
+ if (IsTimed && timer.hasExpired())
return false;
}
}