cdvdgigaherz: Use a queue to manage sector requests

Fixes a data race.

Also avoid copying from the cache when it's unnecessary to do so.
This commit is contained in:
Jonathan Li 2016-11-17 20:07:31 +00:00 committed by Gregory Hainaut
parent 3919a32dc3
commit 29c2ccb310
2 changed files with 40 additions and 34 deletions

View File

@ -114,7 +114,6 @@ extern void (*newDiscCB)();
bool cdvdStartThread(); bool cdvdStartThread();
void cdvdStopThread(); void cdvdStopThread();
s32 cdvdRequestSector(u32 sector, s32 mode); s32 cdvdRequestSector(u32 sector, s32 mode);
s32 cdvdRequestComplete();
u8 *cdvdGetSector(u32 sector, s32 mode); u8 *cdvdGetSector(u32 sector, s32 mode);
s32 cdvdDirectReadSector(u32 first, s32 mode, u8 *buffer); s32 cdvdDirectReadSector(u32 first, s32 mode, u8 *buffer);
s32 cdvdGetMediaType(); s32 cdvdGetMediaType();

View File

@ -17,8 +17,15 @@
#include <atomic> #include <atomic>
#include <condition_variable> #include <condition_variable>
#include <limits> #include <limits>
#include <queue>
#include <thread> #include <thread>
struct CacheRequest
{
u32 lsn;
s32 mode;
};
struct SectorInfo struct SectorInfo
{ {
u32 lsn; u32 lsn;
@ -37,6 +44,7 @@ static std::thread s_thread;
static std::mutex s_notify_lock; static std::mutex s_notify_lock;
static std::condition_variable s_notify_cv; static std::condition_variable s_notify_cv;
static std::mutex s_request_lock; static std::mutex s_request_lock;
static std::queue<CacheRequest> s_request_queue;
static std::mutex s_cache_lock; static std::mutex s_cache_lock;
static std::atomic<bool> cdvd_is_open; static std::atomic<bool> cdvd_is_open;
@ -47,9 +55,6 @@ static std::atomic<bool> cdvd_is_open;
const u32 CacheSize = 1U << CACHE_SIZE; const u32 CacheSize = 1U << CACHE_SIZE;
SectorInfo Cache[CacheSize]; SectorInfo Cache[CacheSize];
bool threadRequestPending;
SectorInfo threadRequestInfo;
u32 cdvdSectorHash(u32 lsn, s32 mode) u32 cdvdSectorHash(u32 lsn, s32 mode)
{ {
u32 t = 0; u32 t = 0;
@ -149,6 +154,12 @@ bool cdvdUpdateDiscStatus()
disc_has_changed = false; disc_has_changed = false;
cdvdRefreshData(); cdvdRefreshData();
{
std::lock_guard<std::mutex> request_guard(s_request_lock);
s_request_queue = std::queue<CacheRequest>();
}
cdvdCallNewDiscCB(); cdvdCallNewDiscCB();
} }
} }
@ -157,6 +168,8 @@ bool cdvdUpdateDiscStatus()
void cdvdThread() void cdvdThread()
{ {
u8 buffer[2352 * 16];
printf(" * CDVD: IO thread started...\n"); printf(" * CDVD: IO thread started...\n");
std::unique_lock<std::mutex> guard(s_notify_lock); std::unique_lock<std::mutex> guard(s_notify_lock);
@ -173,30 +186,29 @@ void cdvdThread()
if (!cdvd_is_open) if (!cdvd_is_open)
break; break;
static SectorInfo info; bool handling_request = false;
CacheRequest request;
bool handlingRequest = false; {
std::lock_guard<std::mutex> request_guard(s_request_lock);
if (threadRequestPending) { if (!s_request_queue.empty()) {
info = threadRequestInfo; request = s_request_queue.front();
handlingRequest = true; s_request_queue.pop();
handling_request = true;
} else { } else {
info.lsn = prefetch_last_lba; request.lsn = prefetch_last_lba;
info.mode = prefetch_last_mode; request.mode = prefetch_last_mode;
}
} }
if (threadRequestPending || prefetch_left) { if (handling_request || prefetch_left) {
if (cdvdReadBlockOfSectors(info.lsn, info.mode, info.data)) if (!cdvdCacheCheck(request.lsn, request.mode))
cdvdCacheUpdate(info.lsn, info.mode, info.data); if (cdvdReadBlockOfSectors(request.lsn, request.mode, buffer))
cdvdCacheUpdate(request.lsn, request.mode, buffer);
if (handlingRequest) { if (handling_request) {
threadRequestInfo = info; prefetch_last_lba = request.lsn;
prefetch_last_mode = request.mode;
handlingRequest = false;
threadRequestPending = false;
prefetch_last_lba = info.lsn;
prefetch_last_mode = info.mode;
prefetch_left = prefetch_max_blocks; prefetch_left = prefetch_max_blocks;
} else { } else {
@ -237,24 +249,19 @@ s32 cdvdRequestSector(u32 sector, s32 mode)
sector &= ~15; //align to 16-sector block sector &= ~15; //align to 16-sector block
threadRequestInfo.lsn = sector; if (cdvdCacheCheck(sector, mode))
threadRequestInfo.mode = mode;
threadRequestPending = false;
if (cdvdCacheFetch(sector, mode, threadRequestInfo.data)) {
return 0; return 0;
{
std::lock_guard<std::mutex> guard(s_request_lock);
s_request_queue.push({sector, mode});
} }
threadRequestPending = true;
s_notify_cv.notify_one(); s_notify_cv.notify_one();
return 0; return 0;
} }
s32 cdvdRequestComplete()
{
return !threadRequestPending;
}
u8 *cdvdGetSector(u32 sector, s32 mode) u8 *cdvdGetSector(u32 sector, s32 mode)
{ {
static u8 buffer[2352 * 16]; static u8 buffer[2352 * 16];