ThreadedFileReader: Fix possible race with synchronous reads

This commit is contained in:
Connor McLaughlin 2022-05-01 23:33:19 +10:00 committed by refractionpcsx2
parent 576bcc6979
commit 008beb4896
1 changed files with 25 additions and 12 deletions

View File

@ -70,22 +70,35 @@ void ThreadedFileReader::Loop()
if (m_quit)
return;
u64 requestOffset = m_requestOffset;
u32 requestSize = m_requestSize;
void* ptr = m_requestPtr.load(std::memory_order_relaxed);
m_running = true;
lock.unlock();
void* ptr;
u64 requestOffset;
u32 requestSize;
bool ok = true;
m_running = true;
if (ptr)
for (;;)
{
ok = Decompress(ptr, requestOffset, requestSize);
}
ptr = m_requestPtr.load(std::memory_order_acquire);
requestOffset = m_requestOffset;
requestSize = m_requestSize;
lock.unlock();
m_requestPtr.store(nullptr, std::memory_order_release);
m_condition.notify_one();
if (ptr)
ok = Decompress(ptr, requestOffset, requestSize);
// There's a potential for a race here when doing synchronous reads. Basically, another request can come in,
// after we release the lock, but before we store null to indicate we're finished. So, we do a compare-exchange
// instead, to detect when this happens, and if so, reload all the inputs and try again.
if (!m_requestPtr.compare_exchange_strong(ptr, nullptr, std::memory_order_release))
{
lock.lock();
continue;
}
m_condition.notify_one();
break;
}
if (ok)
{
@ -326,7 +339,7 @@ int ThreadedFileReader::FinishRead(void)
if (m_requestPtr.load(std::memory_order_acquire) == nullptr)
return m_amtRead;
std::unique_lock<std::mutex> lock(m_mtx);
while (m_requestPtr)
while (m_requestPtr.load(std::memory_order_acquire))
m_condition.wait(lock);
return m_amtRead;
}