mirror of
https://github.com/RPCS3/rpcs3.git
synced 2026-04-05 06:26:38 +00:00
atomic_t<>: extend fetch_op to support cancellation
Use std::invoke inside atomic_op/fetch_op Remove op_fetch because it's easily replaced Add fetch_dec_sat algorithm (conditional decrement)
This commit is contained in:
parent
ed9fb8405b
commit
fb5cdf9769
10 changed files with 80 additions and 60 deletions
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "types.h"
|
||||
#include <functional>
|
||||
|
||||
// Helper class, provides access to compiler-specific atomic intrinsics
|
||||
template<typename T, std::size_t Size = sizeof(T)>
|
||||
|
|
@ -609,36 +610,31 @@ public:
|
|||
return atomic_storage<type>::compare_exchange(m_data, old, exch);
|
||||
}
|
||||
|
||||
// Atomic operation; returns old value
|
||||
template <typename F>
|
||||
std::enable_if_t<std::is_void<std::invoke_result_t<F, T&>>::value, type> fetch_op(F&& func)
|
||||
// Atomic operation; returns old value, or pair of old value and return value (cancel op if evaluates to false)
|
||||
template <typename F, typename RT = std::invoke_result_t<F, T&>>
|
||||
std::conditional_t<std::is_void_v<RT>, type, std::pair<type, RT>> fetch_op(F&& func)
|
||||
{
|
||||
type _new, old = atomic_storage<type>::load(m_data);
|
||||
|
||||
while (true)
|
||||
{
|
||||
func((_new = old));
|
||||
|
||||
if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new)))
|
||||
if constexpr (std::is_void_v<RT>)
|
||||
{
|
||||
return old;
|
||||
std::invoke(func, (_new = old));
|
||||
|
||||
if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new)))
|
||||
{
|
||||
return old;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Atomic operation; returns new value
|
||||
template <typename F>
|
||||
std::enable_if_t<std::is_void<std::invoke_result_t<F, T&>>::value, type> op_fetch(F&& func)
|
||||
{
|
||||
type _new, old = atomic_storage<type>::load(m_data);
|
||||
|
||||
while (true)
|
||||
{
|
||||
func((_new = old));
|
||||
|
||||
if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new)))
|
||||
else
|
||||
{
|
||||
return _new;
|
||||
RT ret = std::invoke(func, (_new = old));
|
||||
|
||||
if (LIKELY(!ret || atomic_storage<type>::compare_exchange(m_data, old, _new)))
|
||||
{
|
||||
return {old, std::move(ret)};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -651,9 +647,9 @@ public:
|
|||
|
||||
while (true)
|
||||
{
|
||||
if constexpr(std::is_void<RT>::value)
|
||||
if constexpr (std::is_void_v<RT>)
|
||||
{
|
||||
func((_new = old), args...);
|
||||
std::invoke(func, (_new = old), args...);
|
||||
|
||||
if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new)))
|
||||
{
|
||||
|
|
@ -662,7 +658,7 @@ public:
|
|||
}
|
||||
else
|
||||
{
|
||||
RT result = func((_new = old), args...);
|
||||
RT result = std::invoke(func, (_new = old), args...);
|
||||
|
||||
if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new)))
|
||||
{
|
||||
|
|
@ -722,9 +718,10 @@ public:
|
|||
return atomic_storage<type>::add_fetch(m_data, rhs);
|
||||
}
|
||||
|
||||
return op_fetch([&](T& v)
|
||||
return atomic_op([&](T& v)
|
||||
{
|
||||
v += rhs;
|
||||
return v;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -761,9 +758,10 @@ public:
|
|||
return atomic_storage<type>::sub_fetch(m_data, rhs);
|
||||
}
|
||||
|
||||
return op_fetch([&](T& v)
|
||||
return atomic_op([&](T& v)
|
||||
{
|
||||
v -= rhs;
|
||||
return v;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -800,9 +798,10 @@ public:
|
|||
return atomic_storage<type>::and_fetch(m_data, rhs);
|
||||
}
|
||||
|
||||
return op_fetch([&](T& v)
|
||||
return atomic_op([&](T& v)
|
||||
{
|
||||
v &= rhs;
|
||||
return v;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -839,9 +838,10 @@ public:
|
|||
return atomic_storage<type>::or_fetch(m_data, rhs);
|
||||
}
|
||||
|
||||
return op_fetch([&](T& v)
|
||||
return atomic_op([&](T& v)
|
||||
{
|
||||
v |= rhs;
|
||||
return v;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -878,9 +878,10 @@ public:
|
|||
return atomic_storage<type>::xor_fetch(m_data, rhs);
|
||||
}
|
||||
|
||||
return op_fetch([&](T& v)
|
||||
return atomic_op([&](T& v)
|
||||
{
|
||||
v ^= rhs;
|
||||
return v;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -948,4 +949,28 @@ public:
|
|||
return v--;
|
||||
});
|
||||
}
|
||||
|
||||
// Conditionally decrement
|
||||
simple_type fetch_dec_sat(simple_type greater_than = std::numeric_limits<simple_type>::min(), simple_type amount = 1)
|
||||
{
|
||||
type _new, old = atomic_storage<type>::load(m_data);
|
||||
|
||||
while (true)
|
||||
{
|
||||
_new = old;
|
||||
|
||||
if (_new <= greater_than)
|
||||
{
|
||||
// Early exit
|
||||
return old;
|
||||
}
|
||||
|
||||
_new -= amount;
|
||||
|
||||
if (LIKELY(atomic_storage<type>::compare_exchange(m_data, old, _new)))
|
||||
{
|
||||
return old;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue