mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-05 19:51:45 +00:00
os: use ported libnx mutex impl
This commit is contained in:
parent
8052dd6249
commit
19d8a0fc2b
1 changed files with 24 additions and 124 deletions
|
@ -19,142 +19,42 @@
|
|||
|
||||
namespace ams::os::impl {
|
||||
|
||||
namespace {
|
||||
|
||||
ALWAYS_INLINE void DataMemoryBarrierForCriticalSection() {
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
/* ... */
|
||||
#else
|
||||
#error "Unknown architecture for os::impl::InternalCriticalSectionImpl DataMemoryBarrier"
|
||||
#endif
|
||||
}
|
||||
|
||||
ALWAYS_INLINE u32 LoadExclusive(u32 *ptr) {
|
||||
u32 value;
|
||||
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
__asm__ __volatile__("ldaxr %w[value], [%[ptr]]" : [value]"=&r"(value) : [ptr]"r"(ptr) : "memory");
|
||||
#else
|
||||
#error "Unknown architecture for os::impl::InternalCriticalSectionImpl LoadExclusive"
|
||||
#endif
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE int StoreExclusive(u32 *ptr, u32 value) {
|
||||
int result;
|
||||
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
__asm__ __volatile__("stlxr %w[result], %w[value], [%[ptr]]" : [result]"=&r"(result) : [value]"r"(value), [ptr]"r"(ptr) : "memory");
|
||||
#else
|
||||
#error "Unknown architecture for os::impl::InternalCriticalSectionImpl StoreExclusive"
|
||||
#endif
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void ClearExclusive() {
|
||||
#if defined(ATMOSPHERE_ARCH_ARM64)
|
||||
__asm__ __volatile__("clrex" ::: "memory");
|
||||
#else
|
||||
#error "Unknown architecture for os::impl::InternalCriticalSectionImpl ClearExclusive"
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void InternalCriticalSectionImpl::Enter() {
|
||||
AMS_ASSERT(svc::GetThreadLocalRegion()->disable_count == 0);
|
||||
|
||||
const auto cur_handle = GetCurrentThreadHandle();
|
||||
AMS_ASSERT((this->thread_handle & ~ams::svc::HandleWaitMask) != cur_handle);
|
||||
|
||||
u32 value = LoadExclusive(std::addressof(this->thread_handle));
|
||||
while (true) {
|
||||
if (AMS_LIKELY(value == svc::InvalidHandle)) {
|
||||
if (AMS_UNLIKELY(StoreExclusive(std::addressof(this->thread_handle), cur_handle) != 0)) {
|
||||
value = LoadExclusive(std::addressof(this->thread_handle));
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (AMS_LIKELY((value & ams::svc::HandleWaitMask) == 0)) {
|
||||
if (AMS_UNLIKELY(StoreExclusive(std::addressof(this->thread_handle), value | ams::svc::HandleWaitMask) != 0)) {
|
||||
value = LoadExclusive(std::addressof(this->thread_handle));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
R_ABORT_UNLESS(ams::svc::ArbitrateLock(value & ~ams::svc::HandleWaitMask, reinterpret_cast<uintptr_t>(std::addressof(this->thread_handle)), cur_handle));
|
||||
|
||||
value = LoadExclusive(std::addressof(this->thread_handle));
|
||||
if (AMS_LIKELY((value & ~ams::svc::HandleWaitMask) == cur_handle)) {
|
||||
ClearExclusive();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
DataMemoryBarrierForCriticalSection();
|
||||
/* Use the libnx impl. */
|
||||
static_assert(std::is_same<decltype(this->thread_handle), ::Mutex>::value);
|
||||
return ::mutexLock(std::addressof(this->thread_handle));
|
||||
}
|
||||
|
||||
bool InternalCriticalSectionImpl::TryEnter() {
|
||||
AMS_ASSERT(svc::GetThreadLocalRegion()->disable_count == 0);
|
||||
|
||||
const auto cur_handle = GetCurrentThreadHandle();
|
||||
|
||||
while (true) {
|
||||
u32 value = LoadExclusive(std::addressof(this->thread_handle));
|
||||
if (AMS_UNLIKELY(value != svc::InvalidHandle)) {
|
||||
break;
|
||||
}
|
||||
|
||||
DataMemoryBarrierForCriticalSection();
|
||||
|
||||
if (AMS_LIKELY(StoreExclusive(std::addressof(this->thread_handle), cur_handle) == 0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
ClearExclusive();
|
||||
DataMemoryBarrierForCriticalSection();
|
||||
|
||||
return false;
|
||||
/* Use the libnx impl. */
|
||||
static_assert(std::is_same<decltype(this->thread_handle), ::Mutex>::value);
|
||||
return ::mutexTryLock(std::addressof(this->thread_handle));
|
||||
}
|
||||
|
||||
void InternalCriticalSectionImpl::Leave() {
|
||||
AMS_ASSERT(svc::GetThreadLocalRegion()->disable_count == 0);
|
||||
|
||||
const auto cur_handle = GetCurrentThreadHandle();
|
||||
u32 value = LoadExclusive(std::addressof(this->thread_handle));
|
||||
|
||||
while (true) {
|
||||
if (AMS_UNLIKELY(value != cur_handle)) {
|
||||
ClearExclusive();
|
||||
break;
|
||||
}
|
||||
|
||||
DataMemoryBarrierForCriticalSection();
|
||||
|
||||
if (AMS_LIKELY(StoreExclusive(std::addressof(this->thread_handle), 0) == 0)) {
|
||||
break;
|
||||
}
|
||||
|
||||
value = LoadExclusive(std::addressof(this->thread_handle));
|
||||
}
|
||||
|
||||
DataMemoryBarrierForCriticalSection();
|
||||
|
||||
AMS_ASSERT((value | ams::svc::HandleWaitMask) == (cur_handle | ams::svc::HandleWaitMask));
|
||||
if (value & ams::svc::HandleWaitMask) {
|
||||
R_ABORT_UNLESS(ams::svc::ArbitrateUnlock(reinterpret_cast<uintptr_t>(std::addressof(this->thread_handle))));
|
||||
}
|
||||
/* Use the libnx impl. */
|
||||
static_assert(std::is_same<decltype(this->thread_handle), ::Mutex>::value);
|
||||
return ::mutexUnlock(std::addressof(this->thread_handle));
|
||||
}
|
||||
|
||||
bool InternalCriticalSectionImpl::IsLockedByCurrentThread() const {
|
||||
const auto cur_handle = GetCurrentThreadHandle();
|
||||
return (this->thread_handle & ~ams::svc::HandleWaitMask) == cur_handle;
|
||||
/* Use the libnx impl. */
|
||||
static_assert(std::is_same<decltype(this->thread_handle), ::Mutex>::value);
|
||||
return ::mutexIsLockedByCurrentThread(std::addressof(this->thread_handle));
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#error "Architecture not yet supported for os::InternalCriticalSectionImpl"
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue