Fix waitForFences crash on Mali drivers

Mali GPU drivers utilize the `ppoll()` syscall inside `waitForFences` which isn't correctly restarted after a signal, which we can receive at any time on a guest thread. This commit fixes that by recursively calling the function on failure till it succeeds or returns an unexpected error.

Co-authored-by: PixelyIon <pixelyion@protonmail.com>
Co-authored-by: Billy Laws <blaws05@gmail.com>
This commit is contained in:
lynxnb 2022-07-14 20:01:48 +02:00
parent 942e22f275
commit cbc896c8f8

View File

@ -68,7 +68,20 @@ namespace skyline::gpu {
void Wait() { void Wait() {
if (signalled.test(std::memory_order_consume)) if (signalled.test(std::memory_order_consume))
return; return;
while (device.waitForFences(fence, false, std::numeric_limits<u64>::max()) != vk::Result::eSuccess);
vk::Result waitResult;
while ((waitResult = (*device).waitForFences(1, &fence, false, std::numeric_limits<u64>::max(), *device.getDispatcher())) != vk::Result::eSuccess) {
if (waitResult == vk::Result::eTimeout)
// Retry if the waiting time out
continue;
if (waitResult == vk::Result::eErrorInitializationFailed)
// eErrorInitializationFailed occurs on Mali GPU drivers due to them using the ppoll() syscall which isn't correctly restarted after a signal, we need to manually retry waiting in that case
continue;
throw exception("An error occurred while waiting for fence 0x{:X}: {}", static_cast<VkFence>(fence), vk::to_string(waitResult));
}
if (!signalled.test_and_set(std::memory_order_release)) if (!signalled.test_and_set(std::memory_order_release))
DestroyDependencies(); DestroyDependencies();
} }
@ -80,7 +93,7 @@ namespace skyline::gpu {
bool Wait(std::chrono::duration<u64, std::nano> timeout) { bool Wait(std::chrono::duration<u64, std::nano> timeout) {
if (signalled.test(std::memory_order_consume)) if (signalled.test(std::memory_order_consume))
return true; return true;
if (device.waitForFences(fence, false, timeout.count()) == vk::Result::eSuccess) { if ((*device).waitForFences(1, &fence, false, std::numeric_limits<u64>::max(), *device.getDispatcher()) == vk::Result::eSuccess) {
if (!signalled.test_and_set(std::memory_order_release)) if (!signalled.test_and_set(std::memory_order_release))
DestroyDependencies(); DestroyDependencies();
return true; return true;