mirror of
https://github.com/Atmosphere-NX/Atmosphere
synced 2024-11-14 09:06:35 +00:00
util: better match true std::atomic semantics
This commit is contained in:
parent
c6d7174dd3
commit
aed9d3f535
12 changed files with 102 additions and 53 deletions
|
@ -22,7 +22,7 @@ namespace ams::secmon {
|
||||||
|
|
||||||
constexpr inline uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress();
|
constexpr inline uintptr_t PMC = MemoryRegionVirtualDevicePmc.GetAddress();
|
||||||
|
|
||||||
constinit util::Atomic<bool> g_is_locked{false};
|
constinit util::Atomic<bool> g_is_locked = false;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ namespace ams::secmon::smc {
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
constinit util::Atomic<bool> g_is_locked{false};
|
constinit util::Atomic<bool> g_is_locked = false;
|
||||||
|
|
||||||
ALWAYS_INLINE bool TryLockSecurityEngineImpl() {
|
ALWAYS_INLINE bool TryLockSecurityEngineImpl() {
|
||||||
bool value = false;
|
bool value = false;
|
||||||
|
|
|
@ -66,7 +66,7 @@ namespace ams::kern {
|
||||||
KSlabHeapImpl::Free(allocated + i);
|
KSlabHeapImpl::Free(allocated + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_count.FetchAdd(sizeof(PageBuffer) / sizeof(T));
|
m_count += sizeof(PageBuffer) / sizeof(T);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ namespace ams::kern {
|
||||||
for (size_t i = 1; i < sizeof(PageBuffer) / sizeof(T); i++) {
|
for (size_t i = 1; i < sizeof(PageBuffer) / sizeof(T); i++) {
|
||||||
KSlabHeapImpl::Free(allocated + i);
|
KSlabHeapImpl::Free(allocated + i);
|
||||||
}
|
}
|
||||||
m_count.FetchAdd(sizeof(PageBuffer) / sizeof(T));
|
m_count += sizeof(PageBuffer) / sizeof(T);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +99,7 @@ namespace ams::kern {
|
||||||
std::construct_at(allocated);
|
std::construct_at(allocated);
|
||||||
|
|
||||||
/* Update our tracking. */
|
/* Update our tracking. */
|
||||||
size_t used = m_used.FetchAdd(1) + 1;
|
const size_t used = ++m_used;
|
||||||
size_t peak = m_peak.Load();
|
size_t peak = m_peak.Load();
|
||||||
while (peak < used) {
|
while (peak < used) {
|
||||||
if (m_peak.CompareExchangeWeak<std::memory_order_relaxed>(peak, used)) {
|
if (m_peak.CompareExchangeWeak<std::memory_order_relaxed>(peak, used)) {
|
||||||
|
@ -113,7 +113,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
ALWAYS_INLINE void Free(T *t) {
|
ALWAYS_INLINE void Free(T *t) {
|
||||||
KSlabHeapImpl::Free(t);
|
KSlabHeapImpl::Free(t);
|
||||||
m_used.FetchSub(1);
|
--m_used;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -288,7 +288,7 @@ namespace ams::kern {
|
||||||
|
|
||||||
KThread *GetExceptionThread() const { return m_exception_thread; }
|
KThread *GetExceptionThread() const { return m_exception_thread; }
|
||||||
|
|
||||||
void AddCpuTime(s64 diff) { m_cpu_time.FetchAdd(diff); }
|
void AddCpuTime(s64 diff) { m_cpu_time += diff; }
|
||||||
s64 GetCpuTime() { return m_cpu_time.Load(); }
|
s64 GetCpuTime() { return m_cpu_time.Load(); }
|
||||||
|
|
||||||
constexpr s64 GetScheduledCount() const { return m_schedule_count; }
|
constexpr s64 GetScheduledCount() const { return m_schedule_count; }
|
||||||
|
|
|
@ -176,8 +176,6 @@ namespace ams::kern {
|
||||||
};
|
};
|
||||||
static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>);
|
static_assert(ams::util::HasRedBlackKeyType<ConditionVariableComparator>);
|
||||||
static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>);
|
static_assert(std::same_as<ams::util::RedBlackKeyType<ConditionVariableComparator, void>, ConditionVariableComparator::RedBlackKeyType>);
|
||||||
private:
|
|
||||||
static constinit inline util::Atomic<u64> s_next_thread_id{0};
|
|
||||||
private:
|
private:
|
||||||
util::IntrusiveListNode m_process_list_node{};
|
util::IntrusiveListNode m_process_list_node{};
|
||||||
util::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node{};
|
util::IntrusiveRedBlackTreeNode m_condvar_arbiter_tree_node{};
|
||||||
|
@ -348,11 +346,11 @@ namespace ams::kern {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ALWAYS_INLINE void RegisterDpc(DpcFlag flag) {
|
ALWAYS_INLINE void RegisterDpc(DpcFlag flag) {
|
||||||
this->GetStackParameters().dpc_flags.FetchOr(flag);
|
this->GetStackParameters().dpc_flags |= flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void ClearDpc(DpcFlag flag) {
|
ALWAYS_INLINE void ClearDpc(DpcFlag flag) {
|
||||||
this->GetStackParameters().dpc_flags.FetchAnd(~flag);
|
this->GetStackParameters().dpc_flags &= ~flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE u8 GetDpc() const {
|
ALWAYS_INLINE u8 GetDpc() const {
|
||||||
|
@ -544,7 +542,7 @@ namespace ams::kern {
|
||||||
constexpr bool IsAttachedToDebugger() const { return m_debug_attached; }
|
constexpr bool IsAttachedToDebugger() const { return m_debug_attached; }
|
||||||
|
|
||||||
void AddCpuTime(s32 core_id, s64 amount) {
|
void AddCpuTime(s32 core_id, s64 amount) {
|
||||||
m_cpu_time.FetchAdd(amount);
|
m_cpu_time += amount;
|
||||||
/* TODO: Debug kernels track per-core tick counts. Should we? */
|
/* TODO: Debug kernels track per-core tick counts. Should we? */
|
||||||
MESOSPHERE_UNUSED(core_id);
|
MESOSPHERE_UNUSED(core_id);
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,7 +287,7 @@ namespace ams::kern::arch::arm64::cpu {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_target_cores.FetchAnd(~(1ul << GetCurrentCoreId()));
|
m_target_cores &= (~(1ul << GetCurrentCoreId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE void SetEventLocally() {
|
ALWAYS_INLINE void SetEventLocally() {
|
||||||
|
|
|
@ -28,7 +28,7 @@ namespace ams::kern {
|
||||||
void KClientPort::OnSessionFinalized() {
|
void KClientPort::OnSessionFinalized() {
|
||||||
KScopedSchedulerLock sl;
|
KScopedSchedulerLock sl;
|
||||||
|
|
||||||
if (m_num_sessions.FetchSub(1) == m_max_sessions) {
|
if (const auto prev = m_num_sessions--; prev == m_max_sessions) {
|
||||||
this->NotifyAvailable();
|
this->NotifyAvailable();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,8 +25,8 @@ namespace ams::kern {
|
||||||
constexpr u64 ProcessIdMin = InitialProcessIdMax + 1;
|
constexpr u64 ProcessIdMin = InitialProcessIdMax + 1;
|
||||||
constexpr u64 ProcessIdMax = std::numeric_limits<u64>::max();
|
constexpr u64 ProcessIdMax = std::numeric_limits<u64>::max();
|
||||||
|
|
||||||
constinit util::Atomic<u64> g_initial_process_id{InitialProcessIdMin};
|
constinit util::Atomic<u64> g_initial_process_id = InitialProcessIdMin;
|
||||||
constinit util::Atomic<u64> g_process_id{ProcessIdMin};
|
constinit util::Atomic<u64> g_process_id = ProcessIdMin;
|
||||||
|
|
||||||
Result TerminateChildren(KProcess *process, const KThread *thread_to_not_terminate) {
|
Result TerminateChildren(KProcess *process, const KThread *thread_to_not_terminate) {
|
||||||
/* Request that all children threads terminate. */
|
/* Request that all children threads terminate. */
|
||||||
|
@ -299,7 +299,7 @@ namespace ams::kern {
|
||||||
R_TRY(m_capabilities.Initialize(caps, num_caps, std::addressof(m_page_table)));
|
R_TRY(m_capabilities.Initialize(caps, num_caps, std::addressof(m_page_table)));
|
||||||
|
|
||||||
/* Initialize the process id. */
|
/* Initialize the process id. */
|
||||||
m_process_id = g_initial_process_id.FetchAdd(1);
|
m_process_id = g_initial_process_id++;
|
||||||
MESOSPHERE_ABORT_UNLESS(InitialProcessIdMin <= m_process_id);
|
MESOSPHERE_ABORT_UNLESS(InitialProcessIdMin <= m_process_id);
|
||||||
MESOSPHERE_ABORT_UNLESS(m_process_id <= InitialProcessIdMax);
|
MESOSPHERE_ABORT_UNLESS(m_process_id <= InitialProcessIdMax);
|
||||||
|
|
||||||
|
@ -409,7 +409,7 @@ namespace ams::kern {
|
||||||
R_TRY(m_capabilities.Initialize(user_caps, num_caps, std::addressof(m_page_table)));
|
R_TRY(m_capabilities.Initialize(user_caps, num_caps, std::addressof(m_page_table)));
|
||||||
|
|
||||||
/* Initialize the process id. */
|
/* Initialize the process id. */
|
||||||
m_process_id = g_process_id.FetchAdd(1);
|
m_process_id = g_process_id++;
|
||||||
MESOSPHERE_ABORT_UNLESS(ProcessIdMin <= m_process_id);
|
MESOSPHERE_ABORT_UNLESS(ProcessIdMin <= m_process_id);
|
||||||
MESOSPHERE_ABORT_UNLESS(m_process_id <= ProcessIdMax);
|
MESOSPHERE_ABORT_UNLESS(m_process_id <= ProcessIdMax);
|
||||||
|
|
||||||
|
@ -791,13 +791,13 @@ namespace ams::kern {
|
||||||
void KProcess::IncrementRunningThreadCount() {
|
void KProcess::IncrementRunningThreadCount() {
|
||||||
MESOSPHERE_ASSERT(m_num_running_threads.Load() >= 0);
|
MESOSPHERE_ASSERT(m_num_running_threads.Load() >= 0);
|
||||||
|
|
||||||
m_num_running_threads.FetchAdd(1);
|
++m_num_running_threads;
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::DecrementRunningThreadCount() {
|
void KProcess::DecrementRunningThreadCount() {
|
||||||
MESOSPHERE_ASSERT(m_num_running_threads.Load() > 0);
|
MESOSPHERE_ASSERT(m_num_running_threads.Load() > 0);
|
||||||
|
|
||||||
if (m_num_running_threads.FetchSub(1) == 1) {
|
if (const auto prev = m_num_running_threads--; prev == 1) {
|
||||||
this->Terminate();
|
this->Terminate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ namespace ams::kern {
|
||||||
|
|
||||||
constexpr inline s32 TerminatingThreadPriority = ams::svc::SystemThreadPriorityHighest - 1;
|
constexpr inline s32 TerminatingThreadPriority = ams::svc::SystemThreadPriorityHighest - 1;
|
||||||
|
|
||||||
|
constinit util::Atomic<u64> g_thread_id = 0;
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE bool IsKernelAddressKey(KProcessAddress key) {
|
constexpr ALWAYS_INLINE bool IsKernelAddressKey(KProcessAddress key) {
|
||||||
const uintptr_t key_uptr = GetInteger(key);
|
const uintptr_t key_uptr = GetInteger(key);
|
||||||
return KernelVirtualAddressSpaceBase <= key_uptr && key_uptr <= KernelVirtualAddressSpaceLast && (key_uptr & 1) == 0;
|
return KernelVirtualAddressSpaceBase <= key_uptr && key_uptr <= KernelVirtualAddressSpaceLast && (key_uptr & 1) == 0;
|
||||||
|
@ -219,7 +221,7 @@ namespace ams::kern {
|
||||||
this->SetInExceptionHandler();
|
this->SetInExceptionHandler();
|
||||||
|
|
||||||
/* Set thread ID. */
|
/* Set thread ID. */
|
||||||
m_thread_id = s_next_thread_id.FetchAdd(1);
|
m_thread_id = g_thread_id++;
|
||||||
|
|
||||||
/* We initialized! */
|
/* We initialized! */
|
||||||
m_initialized = true;
|
m_initialized = true;
|
||||||
|
|
|
@ -42,15 +42,15 @@ namespace ams::kern {
|
||||||
return arr;
|
return arr;
|
||||||
}();
|
}();
|
||||||
|
|
||||||
constinit util::Atomic<s32> g_next_ticket{0};
|
constinit util::Atomic<s32> g_next_ticket = 0;
|
||||||
constinit util::Atomic<s32> g_current_ticket{0};
|
constinit util::Atomic<s32> g_current_ticket = 0;
|
||||||
|
|
||||||
constinit std::array<s32, cpu::NumCores> g_core_tickets = NegativeArray;
|
constinit std::array<s32, cpu::NumCores> g_core_tickets = NegativeArray;
|
||||||
|
|
||||||
s32 GetCoreTicket() {
|
s32 GetCoreTicket() {
|
||||||
const s32 core_id = GetCurrentCoreId();
|
const s32 core_id = GetCurrentCoreId();
|
||||||
if (g_core_tickets[core_id] == -1) {
|
if (g_core_tickets[core_id] == -1) {
|
||||||
g_core_tickets[core_id] = 2 * g_next_ticket.FetchAdd(1);
|
g_core_tickets[core_id] = 2 * (g_next_ticket++);
|
||||||
}
|
}
|
||||||
return g_core_tickets[core_id];
|
return g_core_tickets[core_id];
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,6 +110,11 @@ namespace ams::util {
|
||||||
using StorageType = impl::AtomicStorage<T>;
|
using StorageType = impl::AtomicStorage<T>;
|
||||||
|
|
||||||
static constexpr bool IsIntegral = std::integral<T>;
|
static constexpr bool IsIntegral = std::integral<T>;
|
||||||
|
static constexpr bool IsPointer = std::is_pointer<T>::value;
|
||||||
|
|
||||||
|
static constexpr bool HasArithmeticFunctions = IsIntegral || IsPointer;
|
||||||
|
|
||||||
|
using DifferenceType = typename std::conditional<IsIntegral, T, typename std::conditional<IsPointer, std::ptrdiff_t, void>::type>::type;
|
||||||
|
|
||||||
static constexpr ALWAYS_INLINE T ConvertToType(StorageType s) {
|
static constexpr ALWAYS_INLINE T ConvertToType(StorageType s) {
|
||||||
if constexpr (std::integral<T>) {
|
if constexpr (std::integral<T>) {
|
||||||
|
@ -140,8 +145,8 @@ namespace ams::util {
|
||||||
ALWAYS_INLINE volatile StorageType *GetStoragePointer() { return reinterpret_cast< volatile StorageType *>(std::addressof(m_v)); }
|
ALWAYS_INLINE volatile StorageType *GetStoragePointer() { return reinterpret_cast< volatile StorageType *>(std::addressof(m_v)); }
|
||||||
ALWAYS_INLINE const volatile StorageType *GetStoragePointer() const { return reinterpret_cast<const volatile StorageType *>(std::addressof(m_v)); }
|
ALWAYS_INLINE const volatile StorageType *GetStoragePointer() const { return reinterpret_cast<const volatile StorageType *>(std::addressof(m_v)); }
|
||||||
public:
|
public:
|
||||||
ALWAYS_INLINE explicit Atomic() { /* ... */ }
|
ALWAYS_INLINE Atomic() { /* ... */ }
|
||||||
constexpr ALWAYS_INLINE explicit Atomic(T v) : m_v(ConvertToStorage(v)) { /* ... */ }
|
constexpr ALWAYS_INLINE Atomic(T v) : m_v(ConvertToStorage(v)) { /* ... */ }
|
||||||
|
|
||||||
constexpr ALWAYS_INLINE T operator=(T desired) {
|
constexpr ALWAYS_INLINE T operator=(T desired) {
|
||||||
if (std::is_constant_evaluated()) {
|
if (std::is_constant_evaluated()) {
|
||||||
|
@ -296,27 +301,44 @@ namespace ams::util {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(_OPERATION_, _OPERATOR_) \
|
#define AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(_OPERATION_, _OPERATOR_, _POINTER_ALLOWED_) \
|
||||||
template<bool Enable = IsIntegral, typename = typename std::enable_if<Enable, void>::type> \
|
template<bool Enable = (IsIntegral || (_POINTER_ALLOWED_ && IsPointer)), typename = typename std::enable_if<Enable, void>::type> \
|
||||||
ALWAYS_INLINE T Fetch ## _OPERATION_(T arg) { \
|
ALWAYS_INLINE T Fetch ## _OPERATION_(DifferenceType arg) { \
|
||||||
static_assert(Enable); \
|
static_assert(Enable == (IsIntegral || (_POINTER_ALLOWED_ && IsPointer))); \
|
||||||
volatile StorageType * const p = this->GetStoragePointer(); \
|
volatile StorageType * const p = this->GetStoragePointer(); \
|
||||||
const StorageType s = ConvertToStorage(arg); \
|
|
||||||
\
|
\
|
||||||
StorageType current; \
|
StorageType current; \
|
||||||
do { \
|
do { \
|
||||||
current = impl::LoadAcquireExclusiveForAtomic<StorageType>(p); \
|
current = impl::LoadAcquireExclusiveForAtomic<StorageType>(p); \
|
||||||
} while (AMS_UNLIKELY(!impl::StoreReleaseExclusiveForAtomic<StorageType>(p, current _OPERATOR_ s))); \
|
} while (AMS_UNLIKELY(!impl::StoreReleaseExclusiveForAtomic<StorageType>(p, ConvertToStorage(ConvertToType(current) _OPERATOR_ arg)))); \
|
||||||
return static_cast<T>(current); \
|
return ConvertToType(current); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
template<bool Enable = (IsIntegral || (_POINTER_ALLOWED_ && IsPointer)), typename = typename std::enable_if<Enable, void>::type> \
|
||||||
|
ALWAYS_INLINE T operator _OPERATOR_##=(DifferenceType arg) { \
|
||||||
|
static_assert(Enable == (IsIntegral || (_POINTER_ALLOWED_ && IsPointer))); \
|
||||||
|
return this->Fetch ## _OPERATION_(arg) _OPERATOR_ arg; \
|
||||||
}
|
}
|
||||||
|
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Add, +)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Add, +, true)
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Sub, -)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Sub, -, true)
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(And, &)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(And, &, false)
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Or, |)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Or, |, false)
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Xor, ^)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Xor, ^, false)
|
||||||
|
|
||||||
#undef AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION
|
#undef AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION
|
||||||
|
|
||||||
|
template<bool Enable = HasArithmeticFunctions, typename = typename std::enable_if<Enable, void>::type>
|
||||||
|
ALWAYS_INLINE T operator++() { static_assert(Enable == HasArithmeticFunctions); return this->FetchAdd(1) + 1; }
|
||||||
|
|
||||||
|
template<bool Enable = HasArithmeticFunctions, typename = typename std::enable_if<Enable, void>::type>
|
||||||
|
ALWAYS_INLINE T operator++(int) { static_assert(Enable == HasArithmeticFunctions); return this->FetchAdd(1); }
|
||||||
|
|
||||||
|
template<bool Enable = HasArithmeticFunctions, typename = typename std::enable_if<Enable, void>::type>
|
||||||
|
ALWAYS_INLINE T operator--() { static_assert(Enable == HasArithmeticFunctions); return this->FetchSub(1) - 1; }
|
||||||
|
|
||||||
|
template<bool Enable = HasArithmeticFunctions, typename = typename std::enable_if<Enable, void>::type>
|
||||||
|
ALWAYS_INLINE T operator--(int) { static_assert(Enable == HasArithmeticFunctions); return this->FetchSub(1); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -55,13 +55,20 @@ namespace ams::util {
|
||||||
class Atomic {
|
class Atomic {
|
||||||
NON_COPYABLE(Atomic);
|
NON_COPYABLE(Atomic);
|
||||||
NON_MOVEABLE(Atomic);
|
NON_MOVEABLE(Atomic);
|
||||||
|
private:
|
||||||
|
static constexpr bool IsIntegral = std::integral<T>;
|
||||||
|
static constexpr bool IsPointer = std::is_pointer<T>::value;
|
||||||
|
|
||||||
|
static constexpr bool HasArithmeticFunctions = IsIntegral || IsPointer;
|
||||||
|
|
||||||
|
using DifferenceType = typename std::conditional<IsIntegral, T, typename std::conditional<IsPointer, std::ptrdiff_t, void>::type>::type;
|
||||||
private:
|
private:
|
||||||
static_assert(std::atomic<T>::is_always_lock_free);
|
static_assert(std::atomic<T>::is_always_lock_free);
|
||||||
private:
|
private:
|
||||||
std::atomic<T> m_v;
|
std::atomic<T> m_v;
|
||||||
public:
|
public:
|
||||||
ALWAYS_INLINE explicit Atomic() { /* ... */ }
|
ALWAYS_INLINE Atomic() { /* ... */ }
|
||||||
constexpr ALWAYS_INLINE explicit Atomic(T v) : m_v(v) { /* ... */ }
|
constexpr ALWAYS_INLINE Atomic(T v) : m_v(v) { /* ... */ }
|
||||||
|
|
||||||
ALWAYS_INLINE T operator=(T desired) {
|
ALWAYS_INLINE T operator=(T desired) {
|
||||||
return (m_v = desired);
|
return (m_v = desired);
|
||||||
|
@ -93,18 +100,38 @@ namespace ams::util {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#define AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(_OPERATION_, _OPERATION_LOWER_) \
|
#define AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(_OPERATION_, _OPERATION_LOWER_, _OPERATOR_, _POINTER_ALLOWED_) \
|
||||||
ALWAYS_INLINE T Fetch ## _OPERATION_(T arg) { \
|
template<bool Enable = (IsIntegral || (_POINTER_ALLOWED_ && IsPointer)), typename = typename std::enable_if<Enable, void>::type> \
|
||||||
|
ALWAYS_INLINE T Fetch ## _OPERATION_(DifferenceType arg) { \
|
||||||
|
static_assert(Enable == (IsIntegral || (_POINTER_ALLOWED_ && IsPointer))); \
|
||||||
return m_v.fetch_##_OPERATION_LOWER_(arg); \
|
return m_v.fetch_##_OPERATION_LOWER_(arg); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
template<bool Enable = (IsIntegral || (_POINTER_ALLOWED_ && IsPointer)), typename = typename std::enable_if<Enable, void>::type> \
|
||||||
|
ALWAYS_INLINE T operator _OPERATOR_##=(DifferenceType arg) { \
|
||||||
|
static_assert(Enable == (IsIntegral || (_POINTER_ALLOWED_ && IsPointer))); \
|
||||||
|
return this->Fetch##_OPERATION_(arg) _OPERATOR_ arg; \
|
||||||
}
|
}
|
||||||
|
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Add, add)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Add, add, +, true)
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Sub, sub)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Sub, sub, -, true)
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(And, and)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(And, and, &, false)
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Or, or)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Or, or, |, false)
|
||||||
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Xor, xor)
|
AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION(Xor, xor, ^, false)
|
||||||
|
|
||||||
#undef AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION
|
#undef AMS_UTIL_IMPL_DEFINE_ATOMIC_FETCH_OPERATE_FUNCTION
|
||||||
|
|
||||||
|
template<bool Enable = HasArithmeticFunctions, typename = typename std::enable_if<Enable, void>::type>
|
||||||
|
ALWAYS_INLINE T operator++() { static_assert(Enable == HasArithmeticFunctions); return this->FetchAdd(1) + 1; }
|
||||||
|
|
||||||
|
template<bool Enable = HasArithmeticFunctions, typename = typename std::enable_if<Enable, void>::type>
|
||||||
|
ALWAYS_INLINE T operator++(int) { static_assert(Enable == HasArithmeticFunctions); return this->FetchAdd(1); }
|
||||||
|
|
||||||
|
template<bool Enable = HasArithmeticFunctions, typename = typename std::enable_if<Enable, void>::type>
|
||||||
|
ALWAYS_INLINE T operator--() { static_assert(Enable == HasArithmeticFunctions); return this->FetchSub(1) - 1; }
|
||||||
|
|
||||||
|
template<bool Enable = HasArithmeticFunctions, typename = typename std::enable_if<Enable, void>::type>
|
||||||
|
ALWAYS_INLINE T operator--(int) { static_assert(Enable == HasArithmeticFunctions); return this->FetchSub(1); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue