mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-01-16 07:10:40 +00:00
atomic.hpp: add timeout support
This commit is contained in:
parent
a45f86a4a2
commit
aa99faa85d
@ -72,22 +72,41 @@ namespace
|
||||
return s_waiter_maps[std::hash<const void*>()(ptr) % std::size(s_waiter_maps)];
|
||||
}
|
||||
|
||||
void fallback_wait(const void* data, std::size_t size, u64 old_value)
|
||||
void fallback_wait(const void* data, std::size_t size, u64 old_value, u64 timeout)
|
||||
{
|
||||
auto& wmap = get_fallback_map(data);
|
||||
|
||||
if (!timeout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Update node key
|
||||
s_tls_waiter.key() = data;
|
||||
|
||||
if (std::unique_lock lock(wmap.mutex); ptr_cmp(data, size, old_value) && s_tls_wait_cb(data))
|
||||
{
|
||||
// Add node to the waiter list
|
||||
std::condition_variable& cond = wmap.list.insert(std::move(s_tls_waiter))->second.cond;
|
||||
const auto iter = wmap.list.insert(std::move(s_tls_waiter));
|
||||
|
||||
// Wait until the node is returned to its TLS location
|
||||
if (timeout + 1)
|
||||
{
|
||||
if (!iter->second.cond.wait_for(lock, std::chrono::nanoseconds(timeout), [&]
|
||||
{
|
||||
return 1 && s_tls_waiter;
|
||||
}))
|
||||
{
|
||||
// Put it back
|
||||
s_tls_waiter = wmap.list.extract(iter);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
while (!s_tls_waiter)
|
||||
{
|
||||
cond.wait(lock);
|
||||
iter->second.cond.wait(lock);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -127,9 +146,9 @@ namespace
|
||||
|
||||
#if !defined(_WIN32) && !defined(__linux__)
|
||||
|
||||
void atomic_storage_futex::wait(const void* data, std::size_t size, u64 old_value)
|
||||
void atomic_storage_futex::wait(const void* data, std::size_t size, u64 old_value, u64 timeout)
|
||||
{
|
||||
fallback_wait(data, size, old_value);
|
||||
fallback_wait(data, size, old_value, timeout);
|
||||
}
|
||||
|
||||
void atomic_storage_futex::notify_one(const void* data)
|
||||
@ -144,8 +163,13 @@ void atomic_storage_futex::notify_all(const void* data)
|
||||
|
||||
#else
|
||||
|
||||
void atomic_storage_futex::wait(const void* data, std::size_t size, u64 old_value)
|
||||
void atomic_storage_futex::wait(const void* data, std::size_t size, u64 old_value, u64 timeout)
|
||||
{
|
||||
if (!timeout)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const std::intptr_t iptr = reinterpret_cast<std::intptr_t>(data);
|
||||
|
||||
atomic_t<s64>& entry = s_hashtable[iptr % s_hashtable_size];
|
||||
@ -183,10 +207,26 @@ void atomic_storage_futex::wait(const void* data, std::size_t size, u64 old_valu
|
||||
if (ptr_cmp(data, size, old_value) && s_tls_wait_cb(data))
|
||||
{
|
||||
#ifdef _WIN32
|
||||
NtWaitForKeyedEvent(nullptr, &entry, false, nullptr);
|
||||
return;
|
||||
LARGE_INTEGER qw;
|
||||
qw.QuadPart = -static_cast<s64>(timeout / 100);
|
||||
|
||||
if (timeout % 100)
|
||||
{
|
||||
// Round up to closest 100ns unit
|
||||
qw.QuadPart -= 1;
|
||||
}
|
||||
|
||||
if (!NtWaitForKeyedEvent(nullptr, &entry, false, timeout + 1 ? &qw : nullptr))
|
||||
{
|
||||
// Return if no errors, continue if timed out
|
||||
return;
|
||||
}
|
||||
#else
|
||||
futex(reinterpret_cast<char*>(&entry) + 4 * IS_BE_MACHINE, FUTEX_WAIT_PRIVATE, new_value, nullptr);
|
||||
struct timespec ts;
|
||||
ts.tv_sec = timeout / 1'000'000'000;
|
||||
ts.tv_nsec = timeout % 1'000'000'000;
|
||||
|
||||
futex(reinterpret_cast<char*>(&entry) + 4 * IS_BE_MACHINE, FUTEX_WAIT_PRIVATE, new_value, timeout + 1 ? &ts : nullptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -7,6 +7,12 @@
|
||||
#include <atomic>
|
||||
#endif
|
||||
|
||||
// Wait timeout extension (in nanoseconds)
|
||||
enum class atomic_wait_timeout : u64
|
||||
{
|
||||
inf = 0xffff'ffff'ffff'ffff,
|
||||
};
|
||||
|
||||
// Helper for waitable atomics (as in C++20 std::atomic)
|
||||
struct atomic_storage_futex
|
||||
{
|
||||
@ -14,7 +20,7 @@ private:
|
||||
template <typename T>
|
||||
friend class atomic_t;
|
||||
|
||||
static void wait(const void* data, std::size_t size, u64 old_value);
|
||||
static void wait(const void* data, std::size_t size, u64 old_value, u64 timeout);
|
||||
static void notify_one(const void* data);
|
||||
static void notify_all(const void* data);
|
||||
|
||||
@ -1128,9 +1134,9 @@ public:
|
||||
return atomic_storage<type>::btr(m_data, bit);
|
||||
}
|
||||
|
||||
void wait(type old_value) const noexcept
|
||||
void wait(type old_value, atomic_wait_timeout timeout = atomic_wait_timeout::inf) const noexcept
|
||||
{
|
||||
atomic_storage_futex::wait(&m_data, sizeof(T), std::bit_cast<get_uint_t<sizeof(T)>>(old_value));
|
||||
atomic_storage_futex::wait(&m_data, sizeof(T), std::bit_cast<get_uint_t<sizeof(T)>>(old_value), static_cast<u64>(timeout));
|
||||
}
|
||||
|
||||
void notify_one() noexcept
|
||||
|
Loading…
Reference in New Issue
Block a user