|
|
|
@ -118,9 +118,10 @@ ResultCode KAddressArbiter::SignalAndIncrementIfEqual(VAddr addr, s32 value, s32 |
|
|
|
|
|
|
|
// Check the userspace value.
|
|
|
|
s32 user_value{}; |
|
|
|
R_UNLESS(UpdateIfEqual(system, std::addressof(user_value), addr, value, value + 1), |
|
|
|
Svc::ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
if (!UpdateIfEqual(system, &user_value, addr, value, value + 1)) { |
|
|
|
LOG_ERROR(Kernel, "Invalid current memory!"); |
|
|
|
return Svc::ResultInvalidCurrentMemory; |
|
|
|
} |
|
|
|
if (user_value != value) { |
|
|
|
return Svc::ResultInvalidState; |
|
|
|
} |
|
|
|
@ -146,61 +147,34 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 |
|
|
|
// Perform signaling.
|
|
|
|
s32 num_waiters{}; |
|
|
|
{ |
|
|
|
KScopedSchedulerLock sl(kernel); |
|
|
|
[[maybe_unused]] const KScopedSchedulerLock sl(kernel); |
|
|
|
|
|
|
|
auto it = thread_tree.nfind_light({addr, -1}); |
|
|
|
// Determine the updated value.
|
|
|
|
s32 new_value{}; |
|
|
|
if (/*GetTargetFirmware() >= TargetFirmware_7_0_0*/ true) { |
|
|
|
if (count <= 0) { |
|
|
|
if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { |
|
|
|
new_value = value - 2; |
|
|
|
} else { |
|
|
|
new_value = value + 1; |
|
|
|
} |
|
|
|
if (count <= 0) { |
|
|
|
if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) { |
|
|
|
new_value = value - 2; |
|
|
|
} else { |
|
|
|
if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { |
|
|
|
auto tmp_it = it; |
|
|
|
s32 tmp_num_waiters{}; |
|
|
|
while ((++tmp_it != thread_tree.end()) && |
|
|
|
(tmp_it->GetAddressArbiterKey() == addr)) { |
|
|
|
if ((tmp_num_waiters++) >= count) { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (tmp_num_waiters < count) { |
|
|
|
new_value = value - 1; |
|
|
|
} else { |
|
|
|
new_value = value; |
|
|
|
} |
|
|
|
} else { |
|
|
|
new_value = value + 1; |
|
|
|
} |
|
|
|
new_value = value + 1; |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (count <= 0) { |
|
|
|
if ((it != thread_tree.end()) && (it->GetAddressArbiterKey() == addr)) { |
|
|
|
new_value = value - 1; |
|
|
|
} else { |
|
|
|
new_value = value + 1; |
|
|
|
} |
|
|
|
} else { |
|
|
|
if (it != thread_tree.end() && it->GetAddressArbiterKey() == addr) { |
|
|
|
auto tmp_it = it; |
|
|
|
s32 tmp_num_waiters{}; |
|
|
|
while ((tmp_it != thread_tree.end()) && (tmp_it->GetAddressArbiterKey() == addr) && |
|
|
|
(tmp_num_waiters < count + 1)) { |
|
|
|
++tmp_num_waiters; |
|
|
|
++tmp_it; |
|
|
|
while (++tmp_it != thread_tree.end() && tmp_it->GetAddressArbiterKey() == addr) { |
|
|
|
if (tmp_num_waiters++ >= count) { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (tmp_num_waiters == 0) { |
|
|
|
new_value = value + 1; |
|
|
|
} else if (tmp_num_waiters <= count) { |
|
|
|
if (tmp_num_waiters < count) { |
|
|
|
new_value = value - 1; |
|
|
|
} else { |
|
|
|
new_value = value; |
|
|
|
} |
|
|
|
} else { |
|
|
|
new_value = value + 1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -208,13 +182,15 @@ ResultCode KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(VAddr addr, s32 |
|
|
|
s32 user_value{}; |
|
|
|
bool succeeded{}; |
|
|
|
if (value != new_value) { |
|
|
|
succeeded = UpdateIfEqual(system, std::addressof(user_value), addr, value, new_value); |
|
|
|
succeeded = UpdateIfEqual(system, &user_value, addr, value, new_value); |
|
|
|
} else { |
|
|
|
succeeded = ReadFromUser(system, std::addressof(user_value), addr); |
|
|
|
succeeded = ReadFromUser(system, &user_value, addr); |
|
|
|
} |
|
|
|
|
|
|
|
R_UNLESS(succeeded, Svc::ResultInvalidCurrentMemory); |
|
|
|
|
|
|
|
if (!succeeded) { |
|
|
|
LOG_ERROR(Kernel, "Invalid current memory!"); |
|
|
|
return Svc::ResultInvalidCurrentMemory; |
|
|
|
} |
|
|
|
if (user_value != value) { |
|
|
|
return Svc::ResultInvalidState; |
|
|
|
} |
|
|
|
@ -255,9 +231,9 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement |
|
|
|
s32 user_value{}; |
|
|
|
bool succeeded{}; |
|
|
|
if (decrement) { |
|
|
|
succeeded = DecrementIfLessThan(system, std::addressof(user_value), addr, value); |
|
|
|
succeeded = DecrementIfLessThan(system, &user_value, addr, value); |
|
|
|
} else { |
|
|
|
succeeded = ReadFromUser(system, std::addressof(user_value), addr); |
|
|
|
succeeded = ReadFromUser(system, &user_value, addr); |
|
|
|
} |
|
|
|
|
|
|
|
if (!succeeded) { |
|
|
|
@ -278,7 +254,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement |
|
|
|
} |
|
|
|
|
|
|
|
// Set the arbiter.
|
|
|
|
cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); |
|
|
|
cur_thread->SetAddressArbiter(&thread_tree, addr); |
|
|
|
thread_tree.insert(*cur_thread); |
|
|
|
cur_thread->SetState(ThreadState::Waiting); |
|
|
|
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); |
|
|
|
@ -299,7 +275,7 @@ ResultCode KAddressArbiter::WaitIfLessThan(VAddr addr, s32 value, bool decrement |
|
|
|
|
|
|
|
// Get the result.
|
|
|
|
KSynchronizationObject* dummy{}; |
|
|
|
return cur_thread->GetWaitResult(std::addressof(dummy)); |
|
|
|
return cur_thread->GetWaitResult(&dummy); |
|
|
|
} |
|
|
|
|
|
|
|
ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { |
|
|
|
@ -320,7 +296,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { |
|
|
|
|
|
|
|
// Read the value from userspace.
|
|
|
|
s32 user_value{}; |
|
|
|
if (!ReadFromUser(system, std::addressof(user_value), addr)) { |
|
|
|
if (!ReadFromUser(system, &user_value, addr)) { |
|
|
|
slp.CancelSleep(); |
|
|
|
return Svc::ResultInvalidCurrentMemory; |
|
|
|
} |
|
|
|
@ -338,7 +314,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { |
|
|
|
} |
|
|
|
|
|
|
|
// Set the arbiter.
|
|
|
|
cur_thread->SetAddressArbiter(std::addressof(thread_tree), addr); |
|
|
|
cur_thread->SetAddressArbiter(&thread_tree, addr); |
|
|
|
thread_tree.insert(*cur_thread); |
|
|
|
cur_thread->SetState(ThreadState::Waiting); |
|
|
|
cur_thread->SetWaitReasonForDebugging(ThreadWaitReasonForDebugging::Arbitration); |
|
|
|
@ -359,7 +335,7 @@ ResultCode KAddressArbiter::WaitIfEqual(VAddr addr, s32 value, s64 timeout) { |
|
|
|
|
|
|
|
// Get the result.
|
|
|
|
KSynchronizationObject* dummy{}; |
|
|
|
return cur_thread->GetWaitResult(std::addressof(dummy)); |
|
|
|
return cur_thread->GetWaitResult(&dummy); |
|
|
|
} |
|
|
|
|
|
|
|
} // namespace Kernel
|