Change "blocking" BlockingLoop::Stop to give up and die after a timeout.

This fixes the global-static fifo object causing infinite hangs in some
cases. Notably, failure to initialize a graphics backend would result in
BlockingLoop::Prepare being called but never executing Run(), leaving the
object in a bad state.
This commit is contained in:
Shawn Hoffman 2017-06-22 05:42:14 -07:00
parent 88b442e1a8
commit ed8f293b4f
2 changed files with 21 additions and 4 deletions

View file

@ -22,8 +22,15 @@ namespace Common
class BlockingLoop
{
public:
enum StopMode
{
kNonBlock,
kBlock,
kBlockAndGiveUp,
};
BlockingLoop() { m_stopped.Set(); }
~BlockingLoop() { Stop(); }
~BlockingLoop() { Stop(kBlockAndGiveUp); }
// Triggers to rerun the payload of the Run() function at least once again.
// This function will never block and is designed to finish as fast as possible.
void Wakeup()
@ -192,7 +199,7 @@ public:
// Quits the main loop.
// By default, it will wait until the main loop quits.
// Be careful to not use the blocking way within the payload of the Run() method.
void Stop(bool block = true)
void Stop(StopMode mode = kBlock)
{
if (m_stopped.IsSet())
return;
@ -202,8 +209,18 @@ public:
// We have to interrupt the sleeping call to let the worker shut down soon.
Wakeup();
if (block)
switch (mode)
{
case kBlock:
Wait();
break;
case kBlockAndGiveUp:
WaitYield(std::chrono::milliseconds(100), [&] {
// If timed out, assume no one will come along to call Run, so force a break
m_stopped.Set();
});
break;
}
}
bool IsRunning() const { return !m_stopped.IsSet() && !m_shutdown.IsSet(); }

View file

@ -144,7 +144,7 @@ void ExitGpuLoop()
// Terminate GPU thread loop
s_emu_running_state.Set();
s_gpu_mainloop.Stop(false);
s_gpu_mainloop.Stop(s_gpu_mainloop.kNonBlock);
}
void EmulatorState(bool running)