#include "CDvdFile.hpp" #include "CDvdRequest.hpp" #include "CStopwatch.hpp" namespace urde { hecl::ProjectPath CDvdFile::m_DvdRoot; class CFileDvdRequest : public IDvdRequest { std::shared_ptr m_reader; void* m_buf; u32 m_len; ESeekOrigin m_whence; int m_offset; std::atomic_bool m_cancel = {false}; std::atomic_bool m_complete = {false}; std::function m_callback; public: ~CFileDvdRequest() { PostCancelRequest(); } void WaitUntilComplete() { while (!m_complete.load() && !m_cancel.load()) { std::unique_lock lk(CDvdFile::m_WaitMutex); } } bool IsComplete() {return m_complete.load();} void PostCancelRequest() { std::unique_lock waitlk(CDvdFile::m_WaitMutex); m_cancel.store(true); } EMediaType GetMediaType() const { return EMediaType::File; } CFileDvdRequest(CDvdFile& file, void* buf, u32 len, ESeekOrigin whence, int off, std::function&& cb) : m_reader(file.m_reader), m_buf(buf), m_len(len), m_whence(whence), m_offset(off), m_callback(std::move(cb)) {} void DoRequest() { if (m_cancel.load()) return; u32 readLen; if (m_whence == ESeekOrigin::Cur && m_offset == 0) { readLen = m_reader->readBytesToBuf(m_buf, m_len); } else { m_reader->seek(m_offset, athena::SeekOrigin(m_whence)); readLen = m_reader->readBytesToBuf(m_buf, m_len); } if (m_callback) m_callback(readLen); m_complete.store(true); } }; std::thread CDvdFile::m_WorkerThread; std::mutex CDvdFile::m_WorkerMutex; std::condition_variable CDvdFile::m_WorkerCV; std::mutex CDvdFile::m_WaitMutex; std::atomic_bool CDvdFile::m_WorkerRun = {false}; std::vector> CDvdFile::m_RequestQueue; void CDvdFile::WorkerProc() { logvisor::RegisterThreadName("CDvdFile"); while (m_WorkerRun.load()) { std::unique_lock lk(CDvdFile::m_WorkerMutex); while (CDvdFile::m_RequestQueue.size()) { std::vector> swapQueue; swapQueue.swap(CDvdFile::m_RequestQueue); lk.unlock(); std::unique_lock waitlk(CDvdFile::m_WaitMutex); for (std::shared_ptr& req : swapQueue) { CFileDvdRequest& concreteReq = static_cast(*req); concreteReq.DoRequest(); } waitlk.unlock(); swapQueue.clear(); lk.lock(); } if (!m_WorkerRun.load()) break; m_WorkerCV.wait(lk); } } std::shared_ptr CDvdFile::AsyncSeekRead(void* buf, u32 len, ESeekOrigin whence, int off, std::function&& cb) { std::shared_ptr ret = std::make_shared(*this, buf, len, whence, off, std::move(cb)); std::unique_lock lk(CDvdFile::m_WorkerMutex); m_RequestQueue.emplace_back(ret); lk.unlock(); m_WorkerCV.notify_one(); return ret; } void CDvdFile::Initialize(const hecl::ProjectPath& path) { m_DvdRoot = path; if (m_WorkerRun.load()) return; m_WorkerRun.store(true); m_WorkerThread = std::thread(WorkerProc); } void CDvdFile::Shutdown() { if (!m_WorkerRun.load()) return; m_WorkerRun.store(false); m_WorkerCV.notify_one(); if (m_WorkerThread.joinable()) m_WorkerThread.join(); m_RequestQueue.clear(); } }