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) if (m_quit)
return; return;
u64 requestOffset = m_requestOffset; void* ptr;
u32 requestSize = m_requestSize; u64 requestOffset;
void* ptr = m_requestPtr.load(std::memory_order_relaxed); u32 requestSize;
m_running = true;
lock.unlock();
bool ok = true; 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); if (ptr)
m_condition.notify_one(); 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) if (ok)
{ {
@ -326,7 +339,7 @@ int ThreadedFileReader::FinishRead(void)
if (m_requestPtr.load(std::memory_order_acquire) == nullptr) if (m_requestPtr.load(std::memory_order_acquire) == nullptr)
return m_amtRead; return m_amtRead;
std::unique_lock<std::mutex> lock(m_mtx); std::unique_lock<std::mutex> lock(m_mtx);
while (m_requestPtr) while (m_requestPtr.load(std::memory_order_acquire))
m_condition.wait(lock); m_condition.wait(lock);
return m_amtRead; return m_amtRead;
} }