mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-23 18:31:50 +01:00
Fix result returned by MutexLock
`MutexLock` incorrectly returned `InvalidCurrentMemory` for cases where the userspace value didn't match the expected value. It's been corrected to return no error in those cases while preserving the error code for usage in `ConditionalVariableWait`.
This commit is contained in:
parent
08ef88b156
commit
6bbe9de881
@ -111,15 +111,15 @@ namespace skyline::kernel::type {
|
|||||||
|
|
||||||
constexpr u32 HandleWaitersBit{1UL << 30}; //!< A bit which denotes if a mutex psuedo-handle has waiters or not
|
constexpr u32 HandleWaitersBit{1UL << 30}; //!< A bit which denotes if a mutex psuedo-handle has waiters or not
|
||||||
|
|
||||||
Result KProcess::MutexLock(u32 *mutex, KHandle ownerHandle, KHandle tag) {
|
Result KProcess::MutexLock(u32 *mutex, KHandle ownerHandle, KHandle tag, bool failOnOutdated) {
|
||||||
TRACE_EVENT_FMT("kernel", "MutexLock 0x{:X}", mutex);
|
TRACE_EVENT_FMT("kernel", "MutexLock 0x{:X}", mutex);
|
||||||
|
|
||||||
std::shared_ptr<KThread> owner;
|
std::shared_ptr<KThread> owner;
|
||||||
try {
|
try {
|
||||||
owner = GetHandle<KThread>(ownerHandle);
|
owner = GetHandle<KThread>(ownerHandle);
|
||||||
} catch (const std::out_of_range &) {
|
} catch (const std::out_of_range &) {
|
||||||
if (*mutex != (ownerHandle | HandleWaitersBit))
|
if (__atomic_load_n(mutex, __ATOMIC_SEQ_CST) != (ownerHandle | HandleWaitersBit))
|
||||||
return result::InvalidCurrentMemory;
|
return failOnOutdated ? result::InvalidCurrentMemory : Result{};
|
||||||
|
|
||||||
return result::InvalidHandle;
|
return result::InvalidHandle;
|
||||||
}
|
}
|
||||||
@ -128,13 +128,10 @@ namespace skyline::kernel::type {
|
|||||||
{
|
{
|
||||||
std::scoped_lock lock{owner->waiterMutex, state.thread->waiterMutex}; // We need to lock both mutexes at the same time as we mutate the owner and the current thread, the ordering of locks **must** match MutexUnlock to avoid deadlocks
|
std::scoped_lock lock{owner->waiterMutex, state.thread->waiterMutex}; // We need to lock both mutexes at the same time as we mutate the owner and the current thread, the ordering of locks **must** match MutexUnlock to avoid deadlocks
|
||||||
|
|
||||||
u32 value{};
|
u32 value{__atomic_load_n(mutex, __ATOMIC_SEQ_CST)};
|
||||||
if (__atomic_compare_exchange_n(mutex, &value, tag, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
|
|
||||||
// We try to do a CAS to get ownership of the mutex in the case that it's unoccupied
|
|
||||||
return {};
|
|
||||||
if (value != (ownerHandle | HandleWaitersBit))
|
if (value != (ownerHandle | HandleWaitersBit))
|
||||||
// We ensure that the mutex's value is the handle with the waiter bit set
|
// We ensure that the mutex's value is the handle with the waiter bit set
|
||||||
return result::InvalidCurrentMemory;
|
return failOnOutdated ? result::InvalidCurrentMemory : Result{};
|
||||||
|
|
||||||
auto &waiters{owner->waiters};
|
auto &waiters{owner->waiters};
|
||||||
isHighestPriority = waiters.insert(std::upper_bound(waiters.begin(), waiters.end(), state.thread->priority.load(), KThread::IsHigherPriority), state.thread) == waiters.begin();
|
isHighestPriority = waiters.insert(std::upper_bound(waiters.begin(), waiters.end(), state.thread->priority.load(), KThread::IsHigherPriority), state.thread) == waiters.begin();
|
||||||
@ -250,7 +247,7 @@ namespace skyline::kernel::type {
|
|||||||
|
|
||||||
KHandle value{};
|
KHandle value{};
|
||||||
if (!__atomic_compare_exchange_n(mutex, &value, tag, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
|
if (!__atomic_compare_exchange_n(mutex, &value, tag, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
|
||||||
while (MutexLock(mutex, value & ~HandleWaitersBit, tag) != Result{})
|
while (MutexLock(mutex, value & ~HandleWaitersBit, tag, true) != Result{})
|
||||||
if ((value = __atomic_or_fetch(mutex, HandleWaitersBit, __ATOMIC_SEQ_CST)) == HandleWaitersBit)
|
if ((value = __atomic_or_fetch(mutex, HandleWaitersBit, __ATOMIC_SEQ_CST)) == HandleWaitersBit)
|
||||||
if (__atomic_compare_exchange_n(mutex, &value, tag, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
|
if (__atomic_compare_exchange_n(mutex, &value, tag, false, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST))
|
||||||
break;
|
break;
|
||||||
|
@ -212,8 +212,9 @@ namespace skyline {
|
|||||||
* @brief Locks the mutex at the specified address
|
* @brief Locks the mutex at the specified address
|
||||||
* @param ownerHandle The psuedo-handle of the current mutex owner
|
* @param ownerHandle The psuedo-handle of the current mutex owner
|
||||||
* @param tag The handle of the thread which is requesting this lock
|
* @param tag The handle of the thread which is requesting this lock
|
||||||
|
* @param failOnOutdated If true, the function will return InvalidCurrentMemory if the supplied ownerHandle is outdated
|
||||||
*/
|
*/
|
||||||
Result MutexLock(u32 *mutex, KHandle ownerHandle, KHandle tag);
|
Result MutexLock(u32 *mutex, KHandle ownerHandle, KHandle tag, bool failOnOutdated = false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Unlocks the mutex at the specified address
|
* @brief Unlocks the mutex at the specified address
|
||||||
|
Loading…
Reference in New Issue
Block a user