DVDThread: Remove s_dvd_thread_done_working and fix race condition
s_dvd_thread_done_working makes the logic more complicated, and degasus pointed out a race condition that can happen if the CPU thread calls WaitForIdle right in between the DVD thread executing done_working.Set() and done_working.Reset() while there is work left to do. To avoid this, let's just get rid of s_dvd_thread_done_working. It's a relic from the old DVDThread design. Thanks to the last few commits, WaitUntilIdle only gets called rarely (disc change and savestate), so it's not a problem if WaitUntilIdle ends up being slower.
This commit is contained in:
parent
f1879cc356
commit
e1f6ab5592
|
@ -56,6 +56,9 @@ struct ReadRequest
|
||||||
|
|
||||||
using ReadResult = std::pair<ReadRequest, std::vector<u8>>;
|
using ReadResult = std::pair<ReadRequest, std::vector<u8>>;
|
||||||
|
|
||||||
|
static void StartDVDThread();
|
||||||
|
static void StopDVDThread();
|
||||||
|
|
||||||
static void DVDThread();
|
static void DVDThread();
|
||||||
|
|
||||||
static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
|
static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
|
||||||
|
@ -70,7 +73,6 @@ static u64 s_next_id = 0;
|
||||||
static std::thread s_dvd_thread;
|
static std::thread s_dvd_thread;
|
||||||
static Common::Event s_request_queue_expanded; // Is set by CPU thread
|
static Common::Event s_request_queue_expanded; // Is set by CPU thread
|
||||||
static Common::Event s_result_queue_expanded; // Is set by DVD thread
|
static Common::Event s_result_queue_expanded; // Is set by DVD thread
|
||||||
static Common::Event s_dvd_thread_done_working; // Is set by DVD thread
|
|
||||||
static Common::Flag s_dvd_thread_exiting(false); // Is set by CPU thread
|
static Common::Flag s_dvd_thread_exiting(false); // Is set by CPU thread
|
||||||
|
|
||||||
static Common::FifoQueue<ReadRequest, false> s_request_queue;
|
static Common::FifoQueue<ReadRequest, false> s_request_queue;
|
||||||
|
@ -81,7 +83,6 @@ void Start()
|
||||||
{
|
{
|
||||||
s_finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead);
|
s_finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead);
|
||||||
|
|
||||||
s_dvd_thread_exiting.Clear();
|
|
||||||
s_request_queue_expanded.Reset();
|
s_request_queue_expanded.Reset();
|
||||||
s_result_queue_expanded.Reset();
|
s_result_queue_expanded.Reset();
|
||||||
s_request_queue.Clear();
|
s_request_queue.Clear();
|
||||||
|
@ -91,11 +92,22 @@ void Start()
|
||||||
// much, because this will never get exposed to the emulated game.
|
// much, because this will never get exposed to the emulated game.
|
||||||
s_next_id = 0;
|
s_next_id = 0;
|
||||||
|
|
||||||
|
StartDVDThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void StartDVDThread()
|
||||||
|
{
|
||||||
_assert_(!s_dvd_thread.joinable());
|
_assert_(!s_dvd_thread.joinable());
|
||||||
|
s_dvd_thread_exiting.Clear();
|
||||||
s_dvd_thread = std::thread(DVDThread);
|
s_dvd_thread = std::thread(DVDThread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Stop()
|
void Stop()
|
||||||
|
{
|
||||||
|
StopDVDThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void StopDVDThread()
|
||||||
{
|
{
|
||||||
_assert_(s_dvd_thread.joinable());
|
_assert_(s_dvd_thread.joinable());
|
||||||
|
|
||||||
|
@ -131,6 +143,9 @@ void DoState(PointerWrap& p)
|
||||||
// TODO: Savestates can be smaller if the buffers of results aren't saved,
|
// TODO: Savestates can be smaller if the buffers of results aren't saved,
|
||||||
// but instead get re-read from the disc when loading the savestate.
|
// but instead get re-read from the disc when loading the savestate.
|
||||||
|
|
||||||
|
// TODO: It would be possible to create a savestate faster by stopping
|
||||||
|
// the DVD thread regardless of whether there are pending requests.
|
||||||
|
|
||||||
// After loading a savestate, the debug log in FinishRead will report
|
// After loading a savestate, the debug log in FinishRead will report
|
||||||
// screwed up times for requests that were submitted before the savestate
|
// screwed up times for requests that were submitted before the savestate
|
||||||
// was made. Handling that properly may be more effort than it's worth.
|
// was made. Handling that properly may be more effort than it's worth.
|
||||||
|
@ -140,13 +155,11 @@ void WaitUntilIdle()
|
||||||
{
|
{
|
||||||
_assert_(Core::IsCPUThread());
|
_assert_(Core::IsCPUThread());
|
||||||
|
|
||||||
// Wait until DVD thread isn't working
|
while (!s_request_queue.Empty())
|
||||||
s_dvd_thread_done_working.Wait();
|
s_result_queue_expanded.Wait();
|
||||||
|
|
||||||
// Set the event again so that we still know that the DVD thread
|
StopDVDThread();
|
||||||
// isn't working. This is needed in case this function gets called
|
StartDVDThread();
|
||||||
// again before the DVD thread starts working.
|
|
||||||
s_dvd_thread_done_working.Set();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartRead(u64 dvd_offset, u32 length, bool decrypt, DVDInterface::ReplyType reply_type,
|
void StartRead(u64 dvd_offset, u32 length, bool decrypt, DVDInterface::ReplyType reply_type,
|
||||||
|
@ -162,8 +175,9 @@ void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length, bool
|
||||||
ticks_until_completion);
|
ticks_until_completion);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
|
static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
|
||||||
bool decrypt, DVDInterface::ReplyType reply_type, s64 ticks_until_completion)
|
bool decrypt, DVDInterface::ReplyType reply_type,
|
||||||
|
s64 ticks_until_completion)
|
||||||
{
|
{
|
||||||
_assert_(Core::IsCPUThread());
|
_assert_(Core::IsCPUThread());
|
||||||
|
|
||||||
|
@ -255,15 +269,11 @@ static void DVDThread()
|
||||||
|
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
s_dvd_thread_done_working.Set();
|
|
||||||
|
|
||||||
s_request_queue_expanded.Wait();
|
s_request_queue_expanded.Wait();
|
||||||
|
|
||||||
if (s_dvd_thread_exiting.IsSet())
|
if (s_dvd_thread_exiting.IsSet())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
s_dvd_thread_done_working.Reset();
|
|
||||||
|
|
||||||
ReadRequest request;
|
ReadRequest request;
|
||||||
while (s_request_queue.Pop(request))
|
while (s_request_queue.Pop(request))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue