diff --git a/Core/FileLoaders/CachingFileLoader.cpp b/Core/FileLoaders/CachingFileLoader.cpp index 5e7b1b67e1..55429da251 100644 --- a/Core/FileLoaders/CachingFileLoader.cpp +++ b/Core/FileLoaders/CachingFileLoader.cpp @@ -25,7 +25,7 @@ // Takes ownership of backend. CachingFileLoader::CachingFileLoader(FileLoader *backend) - : filesize_(0), backend_(backend), exists_(-1), isDirectory_(-1), aheadThread_(false) { + : backend_(backend) { } void CachingFileLoader::Prepare() { @@ -288,3 +288,7 @@ void CachingFileLoader::StartReadAhead(s64 pos) { }); th.detach(); } + +void CachingFileLoader::Cancel() { + backend_->Cancel(); +} diff --git a/Core/FileLoaders/CachingFileLoader.h b/Core/FileLoaders/CachingFileLoader.h index c9f3031139..bdfc268daf 100644 --- a/Core/FileLoaders/CachingFileLoader.h +++ b/Core/FileLoaders/CachingFileLoader.h @@ -39,6 +39,8 @@ public: } size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; + void Cancel() override; + private: void Prepare(); void InitCache(); @@ -57,10 +59,10 @@ private: BLOCK_READAHEAD = 4, }; - s64 filesize_; + s64 filesize_ = 0; FileLoader *backend_; - int exists_; - int isDirectory_; + int exists_ = -1; + int isDirectory_ = -1; u64 generation_; u64 oldestGeneration_; size_t cacheSize_; @@ -77,6 +79,6 @@ private: std::map blocks_; std::recursive_mutex blocksMutex_; - bool aheadThread_; + bool aheadThread_ = false; std::once_flag preparedFlag_; }; diff --git a/Core/FileLoaders/DiskCachingFileLoader.cpp b/Core/FileLoaders/DiskCachingFileLoader.cpp index 912ca4f509..6fd2320068 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.cpp +++ b/Core/FileLoaders/DiskCachingFileLoader.cpp @@ -41,19 +41,16 @@ std::mutex DiskCachingFileLoader::cachesMutex_; // Takes ownership of backend. DiskCachingFileLoader::DiskCachingFileLoader(FileLoader *backend) - : prepared_(false), filesize_(0), backend_(backend), cache_(nullptr) { + : backend_(backend) { } void DiskCachingFileLoader::Prepare() { - if (prepared_) { - return; - } - prepared_ = true; - - filesize_ = backend_->FileSize(); - if (filesize_ > 0) { - InitCache(); - } + std::call_once(preparedFlag_, [this]() { + filesize_ = backend_->FileSize(); + if (filesize_ > 0) { + InitCache(); + } + }); } DiskCachingFileLoader::~DiskCachingFileLoader() { @@ -118,6 +115,10 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, return readSize; } +void DiskCachingFileLoader::Cancel() { + backend_->Cancel(); +} + std::vector DiskCachingFileLoader::GetCachedPathsInUse() { std::lock_guard guard(cachesMutex_); @@ -156,7 +157,7 @@ void DiskCachingFileLoader::ShutdownCache() { } DiskCachingFileLoaderCache::DiskCachingFileLoaderCache(const std::string &path, u64 filesize) - : refCount_(0), filesize_(filesize), origPath_(path), f_(nullptr), fd_(0) { + : filesize_(filesize), origPath_(path) { InitCache(path); } diff --git a/Core/FileLoaders/DiskCachingFileLoader.h b/Core/FileLoaders/DiskCachingFileLoader.h index 1ea27ee0cb..fb02c6c33b 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.h +++ b/Core/FileLoaders/DiskCachingFileLoader.h @@ -43,6 +43,8 @@ public: } size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; + void Cancel() override; + static std::vector GetCachedPathsInUse(); private: @@ -50,10 +52,10 @@ private: void InitCache(); void ShutdownCache(); - bool prepared_; - s64 filesize_; + std::once_flag preparedFlag_; + s64 filesize_ = 0; FileLoader *backend_; - DiskCachingFileLoaderCache *cache_; + DiskCachingFileLoaderCache *cache_ = nullptr; // We don't support concurrent disk cache access (we use memory cached indexes.) // So we have to ensure there's only one of these per. @@ -139,7 +141,7 @@ private: INVALID_INDEX = 0xFFFFFFFF, }; - int refCount_; + int refCount_ = 0; s64 filesize_; u32 blockSize_; u16 generation_; @@ -176,8 +178,8 @@ private: std::vector index_; std::vector blockIndexLookup_; - FILE *f_; - int fd_; + FILE *f_ = nullptr; + int fd_ = 0; static std::string cacheDir_; }; diff --git a/Core/FileLoaders/HTTPFileLoader.cpp b/Core/FileLoaders/HTTPFileLoader.cpp index c18e7eef56..4dda285844 100644 --- a/Core/FileLoaders/HTTPFileLoader.cpp +++ b/Core/FileLoaders/HTTPFileLoader.cpp @@ -22,7 +22,7 @@ #include "Core/FileLoaders/HTTPFileLoader.h" HTTPFileLoader::HTTPFileLoader(const std::string &filename) - : filesize_(0), filepos_(0), url_(filename), filename_(filename), connected_(false) { + : url_(filename), filename_(filename) { } void HTTPFileLoader::Prepare() { @@ -33,6 +33,10 @@ void HTTPFileLoader::Prepare() { } Connect(); + if (!connected_) { + return; + } + int err = client_.SendRequest("HEAD", url_.Resource().c_str()); if (err < 0) { Disconnect(); @@ -123,6 +127,9 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f } Connect(); + if (!connected_) { + return 0; + } char requestHeaders[4096]; // Note that the Range header is *inclusive*. @@ -186,3 +193,11 @@ size_t HTTPFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Flags f filepos_ = absolutePos + readBytes; return readBytes; } + +void HTTPFileLoader::Connect() { + if (!connected_) { + cancelConnect_ = false; + // Latency is important here, so reduce the timeout. + connected_ = client_.Connect(3, 10.0, &cancelConnect_); + } +} diff --git a/Core/FileLoaders/HTTPFileLoader.h b/Core/FileLoaders/HTTPFileLoader.h index 5b27bf5288..9befbb1e63 100644 --- a/Core/FileLoaders/HTTPFileLoader.h +++ b/Core/FileLoaders/HTTPFileLoader.h @@ -41,14 +41,14 @@ public: } virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; + void Cancel() override { + cancelConnect_ = true; + } + private: void Prepare(); - void Connect() { - if (!connected_) { - connected_ = client_.Connect(); - } - } + void Connect(); void Disconnect() { if (connected_) { @@ -57,12 +57,13 @@ private: connected_ = false; } - s64 filesize_; - s64 filepos_; + s64 filesize_ = 0; + s64 filepos_ = 0; Url url_; http::Client client_; std::string filename_; - bool connected_; + bool connected_ = false; + bool cancelConnect_ = false; std::once_flag preparedFlag_; std::mutex readAtMutex_; diff --git a/Core/FileLoaders/RamCachingFileLoader.cpp b/Core/FileLoaders/RamCachingFileLoader.cpp index 1bc01e9749..0aad8644c2 100644 --- a/Core/FileLoaders/RamCachingFileLoader.cpp +++ b/Core/FileLoaders/RamCachingFileLoader.cpp @@ -28,7 +28,7 @@ // Takes ownership of backend. RamCachingFileLoader::RamCachingFileLoader(FileLoader *backend) - : filesize_(0), backend_(backend), exists_(-1), isDirectory_(-1), aheadThread_(false) { + : backend_(backend) { filesize_ = backend->FileSize(); if (filesize_ > 0) { InitCache(); @@ -107,11 +107,7 @@ void RamCachingFileLoader::InitCache() { } void RamCachingFileLoader::ShutdownCache() { - { - std::lock_guard guard(blocksMutex_); - // Try to have the thread stop. - aheadRemaining_ = 0; - } + Cancel(); // We can't delete while the thread is running, so have to wait. // This should only happen from the menu. @@ -127,6 +123,15 @@ void RamCachingFileLoader::ShutdownCache() { } } +void RamCachingFileLoader::Cancel() { + if (aheadThread_) { + std::lock_guard guard(blocksMutex_); + aheadCancel_ = true; + } + + backend_->Cancel(); +} + size_t RamCachingFileLoader::ReadFromCache(s64 pos, size_t bytes, void *data) { s64 cacheStartPos = pos >> BLOCK_SHIFT; s64 cacheEndPos = (pos + bytes - 1) >> BLOCK_SHIFT; @@ -220,10 +225,11 @@ void RamCachingFileLoader::StartReadAhead(s64 pos) { } aheadThread_ = true; + aheadCancel_ = false; std::thread th([this] { setCurrentThreadName("FileLoaderReadAhead"); - while (aheadRemaining_ != 0) { + while (aheadRemaining_ != 0 && !aheadCancel_) { // Where should we look? const u32 cacheStartPos = NextAheadBlock(); if (cacheStartPos == 0xFFFFFFFF) { diff --git a/Core/FileLoaders/RamCachingFileLoader.h b/Core/FileLoaders/RamCachingFileLoader.h index 0911b43074..4ea38dee04 100644 --- a/Core/FileLoaders/RamCachingFileLoader.h +++ b/Core/FileLoaders/RamCachingFileLoader.h @@ -39,6 +39,8 @@ public: } size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; + void Cancel() override; + private: void InitCache(); void ShutdownCache(); @@ -55,15 +57,16 @@ private: BLOCK_READAHEAD = 4, }; - s64 filesize_; + s64 filesize_ = 0; FileLoader *backend_; - u8 *cache_; - int exists_; - int isDirectory_; + u8 *cache_ = nullptr; + int exists_ = -1; + int isDirectory_ = -1; std::vector blocks_; std::mutex blocksMutex_; u32 aheadRemaining_; s64 aheadPos_; - bool aheadThread_; + bool aheadThread_ = false; + bool aheadCancel_ = false; }; diff --git a/Core/FileLoaders/RetryingFileLoader.cpp b/Core/FileLoaders/RetryingFileLoader.cpp index b9c7927cc2..d90c852864 100644 --- a/Core/FileLoaders/RetryingFileLoader.cpp +++ b/Core/FileLoaders/RetryingFileLoader.cpp @@ -72,3 +72,7 @@ size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Fla return readSize; } + +void RetryingFileLoader::Cancel() { + backend_->Cancel(); +} diff --git a/Core/FileLoaders/RetryingFileLoader.h b/Core/FileLoaders/RetryingFileLoader.h index 98ed64f036..5e6835dc89 100644 --- a/Core/FileLoaders/RetryingFileLoader.h +++ b/Core/FileLoaders/RetryingFileLoader.h @@ -36,6 +36,8 @@ public: } size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) override; + void Cancel() override; + private: enum { MAX_RETRIES = 3, diff --git a/Core/Loaders.h b/Core/Loaders.h index fe24872bfd..ac24f2f3c9 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -86,6 +86,10 @@ public: virtual size_t ReadAt(s64 absolutePos, size_t bytes, void *data, Flags flags = Flags::NONE) { return ReadAt(absolutePos, 1, bytes, data, flags); } + + // Cancel any operations that might block, if possible. + virtual void Cancel() { + } }; inline u32 operator & (const FileLoader::Flags &a, const FileLoader::Flags &b) {