os: use ported libnx mutex impl

This commit is contained in:
Michael Scire 2020-05-17 23:20:21 -07:00
parent 8052dd6249
commit 19d8a0fc2b

View file

@ -19,142 +19,42 @@
namespace ams::os::impl {
namespace {
#if defined(ATMOSPHERE_ARCH_ARM64)
ALWAYS_INLINE void DataMemoryBarrierForCriticalSection() {
#if defined(ATMOSPHERE_ARCH_ARM64)
/* ... */
#else
#error "Unknown architecture for os::impl::InternalCriticalSectionImpl DataMemoryBarrier"
#endif
void InternalCriticalSectionImpl::Enter() {
AMS_ASSERT(svc::GetThreadLocalRegion()->disable_count == 0);
/* Use the libnx impl. */
static_assert(std::is_same<decltype(this->thread_handle), ::Mutex>::value);
return ::mutexLock(std::addressof(this->thread_handle));
}
ALWAYS_INLINE u32 LoadExclusive(u32 *ptr) {
u32 value;
bool InternalCriticalSectionImpl::TryEnter() {
AMS_ASSERT(svc::GetThreadLocalRegion()->disable_count == 0);
#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;
/* Use the libnx impl. */
static_assert(std::is_same<decltype(this->thread_handle), ::Mutex>::value);
return ::mutexTryLock(std::addressof(this->thread_handle));
}
ALWAYS_INLINE int StoreExclusive(u32 *ptr, u32 value) {
int result;
void InternalCriticalSectionImpl::Leave() {
AMS_ASSERT(svc::GetThreadLocalRegion()->disable_count == 0);
#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;
/* Use the libnx impl. */
static_assert(std::is_same<decltype(this->thread_handle), ::Mutex>::value);
return ::mutexUnlock(std::addressof(this->thread_handle));
}
ALWAYS_INLINE void ClearExclusive() {
#if defined(ATMOSPHERE_ARCH_ARM64)
__asm__ __volatile__("clrex" ::: "memory");
#else
#error "Unknown architecture for os::impl::InternalCriticalSectionImpl ClearExclusive"
#endif
bool InternalCriticalSectionImpl::IsLockedByCurrentThread() const {
/* Use the libnx impl. */
static_assert(std::is_same<decltype(this->thread_handle), ::Mutex>::value);
return ::mutexIsLockedByCurrentThread(std::addressof(this->thread_handle));
}
}
#else
void InternalCriticalSectionImpl::Enter() {
AMS_ASSERT(svc::GetThreadLocalRegion()->disable_count == 0);
#error "Architecture not yet supported for os::InternalCriticalSectionImpl"
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();
}
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;
}
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))));
}
}
bool InternalCriticalSectionImpl::IsLockedByCurrentThread() const {
const auto cur_handle = GetCurrentThreadHandle();
return (this->thread_handle & ~ams::svc::HandleWaitMask) == cur_handle;
}
#endif
}