citra-emu
/
citra-canary
Archived
1
0
Fork 0

Merge pull request #1300 from Subv/arbitrateaddress

SVC: Fixed ArbitrateAddress to behave as it does on hardware.
This commit is contained in:
bunnei 2015-12-28 22:23:51 -05:00
commit 73740d74ed
2 changed files with 18 additions and 9 deletions

View File

@ -45,30 +45,32 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
// Wait current thread (acquire the arbiter)... // Wait current thread (acquire the arbiter)...
case ArbitrationType::WaitIfLessThan: case ArbitrationType::WaitIfLessThan:
if ((s32)Memory::Read32(address) <= value) { if ((s32)Memory::Read32(address) < value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address); Kernel::WaitCurrentThread_ArbitrateAddress(address);
} }
break; break;
case ArbitrationType::WaitIfLessThanWithTimeout: case ArbitrationType::WaitIfLessThanWithTimeout:
if ((s32)Memory::Read32(address) <= value) { if ((s32)Memory::Read32(address) < value) {
Kernel::WaitCurrentThread_ArbitrateAddress(address); Kernel::WaitCurrentThread_ArbitrateAddress(address);
GetCurrentThread()->WakeAfterDelay(nanoseconds); GetCurrentThread()->WakeAfterDelay(nanoseconds);
} }
break; break;
case ArbitrationType::DecrementAndWaitIfLessThan: case ArbitrationType::DecrementAndWaitIfLessThan:
{ {
s32 memory_value = Memory::Read32(address) - 1; s32 memory_value = Memory::Read32(address);
Memory::Write32(address, memory_value); if (memory_value < value) {
if (memory_value <= value) { // Only change the memory value if the thread should wait
Memory::Write32(address, (s32)memory_value - 1);
Kernel::WaitCurrentThread_ArbitrateAddress(address); Kernel::WaitCurrentThread_ArbitrateAddress(address);
} }
break; break;
} }
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout:
{ {
s32 memory_value = Memory::Read32(address) - 1; s32 memory_value = Memory::Read32(address);
Memory::Write32(address, memory_value); if (memory_value < value) {
if (memory_value <= value) { // Only change the memory value if the thread should wait
Memory::Write32(address, (s32)memory_value - 1);
Kernel::WaitCurrentThread_ArbitrateAddress(address); Kernel::WaitCurrentThread_ArbitrateAddress(address);
GetCurrentThread()->WakeAfterDelay(nanoseconds); GetCurrentThread()->WakeAfterDelay(nanoseconds);
} }
@ -82,6 +84,13 @@ ResultCode AddressArbiter::ArbitrateAddress(ArbitrationType type, VAddr address,
HLE::Reschedule(__func__); HLE::Reschedule(__func__);
// The calls that use a timeout seem to always return a Timeout error even if they did not put the thread to sleep
if (type == ArbitrationType::WaitIfLessThanWithTimeout ||
type == ArbitrationType::DecrementAndWaitIfLessThanWithTimeout) {
return ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
ErrorSummary::StatusChanged, ErrorLevel::Info);
}
return RESULT_SUCCESS; return RESULT_SUCCESS;
} }

View File

@ -300,7 +300,7 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
thread->waitsynch_waited = false; thread->waitsynch_waited = false;
if (thread->status == THREADSTATUS_WAIT_SYNCH) { if (thread->status == THREADSTATUS_WAIT_SYNCH || thread->status == THREADSTATUS_WAIT_ARB) {
thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS,
ErrorSummary::StatusChanged, ErrorLevel::Info)); ErrorSummary::StatusChanged, ErrorLevel::Info));