From ee5b68f1fcbc4d4f0d08fef9d1d0fb4d745ca868 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sat, 9 Dec 2017 16:47:37 -0800 Subject: [PATCH] Loaders: Add cancelation to all file loaders. Mainly, for HTTP which might be stalled trying to connect (especially if you're not near your PC right now and it's in your recent, for example.) --- Core/FileLoaders/CachingFileLoader.cpp | 6 +++++- Core/FileLoaders/CachingFileLoader.h | 10 ++++++---- Core/FileLoaders/DiskCachingFileLoader.cpp | 23 +++++++++++----------- Core/FileLoaders/DiskCachingFileLoader.h | 14 +++++++------ Core/FileLoaders/HTTPFileLoader.cpp | 17 +++++++++++++++- Core/FileLoaders/HTTPFileLoader.h | 17 ++++++++-------- Core/FileLoaders/RamCachingFileLoader.cpp | 20 ++++++++++++------- Core/FileLoaders/RamCachingFileLoader.h | 13 +++++++----- Core/FileLoaders/RetryingFileLoader.cpp | 4 ++++ Core/FileLoaders/RetryingFileLoader.h | 2 ++ Core/Loaders.h | 4 ++++ 11 files changed, 87 insertions(+), 43 deletions(-) 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) {