mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-01 20:44:18 +01:00
Allow locking external thread in MutexLock
We want the ability to lock mutexes on behalf of other threads to refactor condition variables to match HOS on waking behavior.
This commit is contained in:
parent
6bbe9de881
commit
1eb4eec103
@ -751,7 +751,7 @@ namespace skyline::kernel::svc {
|
|||||||
|
|
||||||
KHandle ownerHandle{state.ctx->gpr.w0};
|
KHandle ownerHandle{state.ctx->gpr.w0};
|
||||||
KHandle requesterHandle{state.ctx->gpr.w2};
|
KHandle requesterHandle{state.ctx->gpr.w2};
|
||||||
auto result{state.process->MutexLock(mutex, ownerHandle, requesterHandle)};
|
auto result{state.process->MutexLock(state.thread, mutex, ownerHandle, requesterHandle)};
|
||||||
if (result == Result{})
|
if (result == Result{})
|
||||||
Logger::Debug("Locked 0x{:X}", mutex);
|
Logger::Debug("Locked 0x{:X}", mutex);
|
||||||
else if (result == result::InvalidCurrentMemory)
|
else if (result == result::InvalidCurrentMemory)
|
||||||
|
@ -111,8 +111,8 @@ 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, bool failOnOutdated) {
|
Result KProcess::MutexLock(const std::shared_ptr<KThread> &thread, u32 *mutex, KHandle ownerHandle, KHandle tag, bool failOnOutdated) {
|
||||||
TRACE_EVENT_FMT("kernel", "MutexLock 0x{:X}", mutex);
|
TRACE_EVENT_FMT("kernel", "MutexLock 0x{:X} @ 0x{:X}", mutex, thread->id);
|
||||||
|
|
||||||
std::shared_ptr<KThread> owner;
|
std::shared_ptr<KThread> owner;
|
||||||
try {
|
try {
|
||||||
@ -126,7 +126,7 @@ namespace skyline::kernel::type {
|
|||||||
|
|
||||||
bool isHighestPriority;
|
bool isHighestPriority;
|
||||||
{
|
{
|
||||||
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, 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{__atomic_load_n(mutex, __ATOMIC_SEQ_CST)};
|
u32 value{__atomic_load_n(mutex, __ATOMIC_SEQ_CST)};
|
||||||
if (value != (ownerHandle | HandleWaitersBit))
|
if (value != (ownerHandle | HandleWaitersBit))
|
||||||
@ -134,19 +134,21 @@ namespace skyline::kernel::type {
|
|||||||
return failOnOutdated ? result::InvalidCurrentMemory : Result{};
|
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(), thread->priority.load(), KThread::IsHigherPriority), thread) == waiters.begin();
|
||||||
state.scheduler->RemoveThread();
|
if (thread == state.thread)
|
||||||
|
state.scheduler->RemoveThread();
|
||||||
|
|
||||||
state.thread->waitThread = owner;
|
thread->waitThread = owner;
|
||||||
state.thread->waitKey = mutex;
|
thread->waitKey = mutex;
|
||||||
state.thread->waitTag = tag;
|
thread->waitTag = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isHighestPriority)
|
if (isHighestPriority)
|
||||||
// If we were the highest priority thread then we need to inherit priorities for all threads we're waiting on recursively
|
// If we were the highest priority thread then we need to inherit priorities for all threads we're waiting on recursively
|
||||||
state.thread->UpdatePriorityInheritance();
|
thread->UpdatePriorityInheritance();
|
||||||
|
|
||||||
state.scheduler->WaitSchedule();
|
if (thread == state.thread)
|
||||||
|
state.scheduler->WaitSchedule();
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@ -247,7 +249,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, true) != Result{})
|
while (MutexLock(state.thread, 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;
|
||||||
|
@ -210,11 +210,12 @@ namespace skyline {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Locks the mutex at the specified address
|
* @brief Locks the mutex at the specified address
|
||||||
|
* @param thread The thread that is locking the mutex
|
||||||
* @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
|
* @param failOnOutdated If true, the function will return InvalidCurrentMemory if the supplied ownerHandle is outdated
|
||||||
*/
|
*/
|
||||||
Result MutexLock(u32 *mutex, KHandle ownerHandle, KHandle tag, bool failOnOutdated = false);
|
Result MutexLock(const std::shared_ptr<KThread> &thread, 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