mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-04-29 14:59:26 -04:00
coreinit: Time to tick conversion is unsigned
The result is treated as signed in most cases, but the calculation uses unsigned arithmetic. As a concrete example where this matters, DS VC passes -1 (2^64-1) to OSWaitEventWithTimeout which internally causes an overflow. But only with unsigned arithmetic this will result in a large positive number that behaves like the intended infinite timeout. With signed arithmetic the result is negative and the events will timeout immediately.
This commit is contained in:
parent
e834515f43
commit
c714e8cb6b
2 changed files with 5 additions and 7 deletions
|
@ -73,8 +73,6 @@ namespace coreinit
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64 coreinit_getOSTime();
|
|
||||||
|
|
||||||
bool OSWaitEventWithTimeout(OSEvent* event, uint64 timeout)
|
bool OSWaitEventWithTimeout(OSEvent* event, uint64 timeout)
|
||||||
{
|
{
|
||||||
__OSLockScheduler();
|
__OSLockScheduler();
|
||||||
|
@ -95,14 +93,14 @@ namespace coreinit
|
||||||
|
|
||||||
// workaround for a bad implementation in some Unity games (like Qube Directors Cut, see FEventWiiU::Wait)
|
// workaround for a bad implementation in some Unity games (like Qube Directors Cut, see FEventWiiU::Wait)
|
||||||
// where the the return value of OSWaitEventWithTimeout is ignored and instead the game measures the elapsed time to determine if a timeout occurred
|
// where the the return value of OSWaitEventWithTimeout is ignored and instead the game measures the elapsed time to determine if a timeout occurred
|
||||||
|
if (timeout < 0x00FFFFFFFFFFFFFFULL)
|
||||||
timeout = timeout * 98ULL / 100ULL; // 98% (we want the function to return slightly before the actual timeout)
|
timeout = timeout * 98ULL / 100ULL; // 98% (we want the function to return slightly before the actual timeout)
|
||||||
|
|
||||||
WaitEventWithTimeoutData data;
|
WaitEventWithTimeoutData data;
|
||||||
data.thread = OSGetCurrentThread();
|
data.thread = OSGetCurrentThread();
|
||||||
data.threadQueue = &event->threadQueue;
|
data.threadQueue = &event->threadQueue;
|
||||||
data.hasTimeout = false;
|
data.hasTimeout = false;
|
||||||
|
auto hostAlarm = coreinit::OSHostAlarmCreate(OSGetTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout), 0, _OSWaitEventWithTimeoutHandler, &data);
|
||||||
auto hostAlarm = coreinit::OSHostAlarmCreate(coreinit::coreinit_getOSTime() + coreinit::EspressoTime::ConvertNsToTimerTicks(timeout), 0, _OSWaitEventWithTimeoutHandler, &data);
|
|
||||||
event->threadQueue.queueAndWait(OSGetCurrentThread());
|
event->threadQueue.queueAndWait(OSGetCurrentThread());
|
||||||
coreinit::OSHostAlarmDestroy(hostAlarm);
|
coreinit::OSHostAlarmDestroy(hostAlarm);
|
||||||
if (data.hasTimeout)
|
if (data.hasTimeout)
|
||||||
|
|
|
@ -40,12 +40,12 @@ namespace coreinit
|
||||||
|
|
||||||
inline TimerTicks ConvertNsToTimerTicks(uint64 ns)
|
inline TimerTicks ConvertNsToTimerTicks(uint64 ns)
|
||||||
{
|
{
|
||||||
return ((GetTimerClock() / 31250LL) * ((TimerTicks)ns) / 32000LL);
|
return static_cast<TimerTicks>((static_cast<uint64>(GetTimerClock()) / 31250ULL) * (ns) / 32000ULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline TimerTicks ConvertMsToTimerTicks(uint64 ms)
|
inline TimerTicks ConvertMsToTimerTicks(uint64 ms)
|
||||||
{
|
{
|
||||||
return (TimerTicks)ms * GetTimerClock() / 1000LL;
|
return static_cast<TimerTicks>(ms * static_cast<uint64>(GetTimerClock()) / 1000ULL);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue