android: deadlock when Emulator::checkStatus is called concurrently

If checkStatus(wait = true) is called, any other thread will be blocked
even when calling with wait = false since the mutex is locked. This
happens on Android when JNIdc.rendinitNative(null) is called by the app
main thread.
Use a shared_future instead and unlock the mutex before waiting.
This commit is contained in:
Flyinghead 2024-08-15 11:55:07 +02:00
parent 138adc28d7
commit 09ab139407
2 changed files with 10 additions and 5 deletions

View File

@ -908,15 +908,20 @@ void Emulator::start()
bool Emulator::checkStatus(bool wait) bool Emulator::checkStatus(bool wait)
{ {
try { try {
const std::lock_guard<std::mutex> lock(mutex); std::unique_lock<std::mutex> lock(mutex);
if (threadResult.valid()) if (threadResult.valid())
{ {
if (!wait) lock.unlock();
{ auto localResult = threadResult;
auto result = threadResult.wait_for(std::chrono::seconds(0)); if (wait) {
localResult.wait();
}
else {
auto result = localResult.wait_for(std::chrono::seconds(0));
if (result == std::future_status::timeout) if (result == std::future_status::timeout)
return true; return true;
} }
lock.lock();
threadResult.get(); threadResult.get();
} }
return false; return false;

View File

@ -179,7 +179,7 @@ private:
Terminated, Terminated,
}; };
State state = Uninitialized; State state = Uninitialized;
std::future<void> threadResult; std::shared_future<void> threadResult;
bool resetRequested = false; bool resetRequested = false;
bool singleStep = false; bool singleStep = false;
u64 startTime = 0; u64 startTime = 0;