QtLinuxFutex, QBasicMutex, QSemaphore: use chrono for time arithmetic
Done-With: Thiago Macieira <thiago.macieira@intel.com> Change-Id: I7c696d58ee596254f91bcd131fe884b6e6ef0852 Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
71c9b9f05b
commit
3e7d68a6f4
@ -18,12 +18,14 @@
|
||||
#include <private/qglobal_p.h>
|
||||
#include <QtCore/qtsan_impl.h>
|
||||
|
||||
#include <chrono>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
namespace QtDummyFutex {
|
||||
constexpr inline bool futexAvailable() { return false; }
|
||||
template <typename Atomic>
|
||||
inline bool futexWait(Atomic &, typename Atomic::Type, int = 0)
|
||||
inline bool futexWait(Atomic &, typename Atomic::Type, std::chrono::nanoseconds = {})
|
||||
{ Q_UNREACHABLE_RETURN(false); }
|
||||
template <typename Atomic> inline void futexWakeOne(Atomic &)
|
||||
{ Q_UNREACHABLE(); }
|
||||
@ -34,6 +36,7 @@ namespace QtDummyFutex {
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#if defined(Q_OS_LINUX) && !defined(QT_LINUXBASE)
|
||||
# include <private/qcore_unix_p.h>
|
||||
// use Linux mutexes everywhere except for LSB builds
|
||||
# include <sys/syscall.h>
|
||||
# include <errno.h>
|
||||
@ -83,11 +86,9 @@ namespace QtLinuxFutex {
|
||||
_q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue));
|
||||
}
|
||||
template <typename Atomic>
|
||||
inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, qint64 nstimeout)
|
||||
inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, std::chrono::nanoseconds timeout)
|
||||
{
|
||||
struct timespec ts;
|
||||
ts.tv_sec = nstimeout / 1000 / 1000 / 1000;
|
||||
ts.tv_nsec = nstimeout % (1000 * 1000 * 1000);
|
||||
struct timespec ts= durationToTimespec(timeout);
|
||||
int r = _q_futex(addr(&futex), FUTEX_WAIT, qintptr(expectedValue), quintptr(&ts));
|
||||
return r == 0 || errno != ETIMEDOUT;
|
||||
}
|
||||
@ -124,9 +125,12 @@ inline void futexWait(Atomic &futex, typename Atomic::Type expectedValue)
|
||||
QtTsan::futexAcquire(&futex);
|
||||
}
|
||||
template <typename Atomic>
|
||||
inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, qint64 nstimeout)
|
||||
inline bool futexWait(Atomic &futex, typename Atomic::Type expectedValue, std::chrono::nanoseconds timeout)
|
||||
{
|
||||
BOOL r = WaitOnAddress(&futex, &expectedValue, sizeof(expectedValue), DWORD(nstimeout / 1000 / 1000));
|
||||
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()));
|
||||
return r || GetLastError() != ERROR_TIMEOUT;
|
||||
}
|
||||
template <typename Atomic> inline void futexWakeAll(Atomic &futex)
|
||||
|
@ -673,12 +673,13 @@ bool QBasicMutex::lockInternal(int timeout) QT_MUTEX_LOCK_NOEXCEPT
|
||||
*/
|
||||
bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXCEPT
|
||||
{
|
||||
qint64 remainingTime = deadlineTimer.remainingTimeNSecs();
|
||||
if (remainingTime == 0)
|
||||
using namespace std::chrono;
|
||||
nanoseconds remainingTime = deadlineTimer.remainingTimeAsDuration();
|
||||
if (remainingTime == 0ns)
|
||||
return false;
|
||||
|
||||
if (futexAvailable()) {
|
||||
if (Q_UNLIKELY(remainingTime < 0)) { // deadlineTimer.isForever()
|
||||
if (Q_UNLIKELY(deadlineTimer.isForever())) {
|
||||
lockInternal();
|
||||
return true;
|
||||
}
|
||||
@ -689,7 +690,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
|
||||
if (d_ptr.fetchAndStoreAcquire(dummyFutexValue()) == nullptr)
|
||||
return true;
|
||||
|
||||
Q_FOREVER {
|
||||
for (;;) {
|
||||
if (!futexWait(d_ptr, dummyFutexValue(), remainingTime))
|
||||
return false;
|
||||
|
||||
@ -700,8 +701,8 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
|
||||
return true;
|
||||
|
||||
// calculate the remaining time
|
||||
remainingTime = deadlineTimer.remainingTimeNSecs();
|
||||
if (remainingTime <= 0)
|
||||
remainingTime = deadlineTimer.remainingTimeAsDuration();
|
||||
if (remainingTime == 0ns)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -713,7 +714,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
|
||||
continue;
|
||||
|
||||
if (copy == dummyLocked()) {
|
||||
if (remainingTime == 0)
|
||||
if (remainingTime == 0ns)
|
||||
return false;
|
||||
// The mutex is locked but does not have a QMutexPrivate yet.
|
||||
// we need to allocate a QMutexPrivate
|
||||
@ -728,7 +729,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
|
||||
}
|
||||
|
||||
QMutexPrivate *d = static_cast<QMutexPrivate *>(copy);
|
||||
if (remainingTime == 0 && !d->possiblyUnlocked.loadRelaxed())
|
||||
if (remainingTime == 0ns && !d->possiblyUnlocked.loadRelaxed())
|
||||
return false;
|
||||
|
||||
// At this point we have a pointer to a QMutexPrivate. But the other thread
|
||||
@ -790,7 +791,7 @@ bool QBasicMutex::lockInternal(QDeadlineTimer deadlineTimer) QT_MUTEX_LOCK_NOEXC
|
||||
Q_ASSERT(d == d_ptr.loadRelaxed());
|
||||
return true;
|
||||
} else {
|
||||
Q_ASSERT(remainingTime >= 0);
|
||||
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,
|
||||
|
@ -148,7 +148,8 @@ template <bool IsTimed> bool
|
||||
futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValue, quintptr nn,
|
||||
QDeadlineTimer timer)
|
||||
{
|
||||
qint64 remainingTime = IsTimed ? timer.remainingTimeNSecs() : -1;
|
||||
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
|
||||
@ -165,7 +166,7 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValu
|
||||
}
|
||||
}
|
||||
|
||||
if (IsTimed && remainingTime > 0) {
|
||||
if (IsTimed && remainingTime > 0ns) {
|
||||
bool timedout = !futexWait(*ptr, curValue, remainingTime);
|
||||
if (timedout)
|
||||
return false;
|
||||
@ -175,7 +176,7 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValu
|
||||
|
||||
curValue = u.loadAcquire();
|
||||
if (IsTimed)
|
||||
remainingTime = timer.remainingTimeNSecs();
|
||||
remainingTime = timer.remainingTimeAsDuration();
|
||||
|
||||
// try to acquire
|
||||
while (futexAvailCounter(curValue) >= n) {
|
||||
@ -185,7 +186,7 @@ futexSemaphoreTryAcquire_loop(QBasicAtomicInteger<quintptr> &u, quintptr curValu
|
||||
}
|
||||
|
||||
// not enough tokens available, put us to wait
|
||||
if (remainingTime == 0)
|
||||
if (IsTimed && remainingTime == 0ns)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user