diff --git a/Core/FileLoaders/CachingFileLoader.cpp b/Core/FileLoaders/CachingFileLoader.cpp index 5e7b1b67e1be..597fafadccc3 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,11 @@ void CachingFileLoader::StartReadAhead(s64 pos) { }); th.detach(); } + +bool CachingFileLoader::IsRemote() { + return backend_->IsRemote(); +} + +void CachingFileLoader::Cancel() { + backend_->Cancel(); +} diff --git a/Core/FileLoaders/CachingFileLoader.h b/Core/FileLoaders/CachingFileLoader.h index c9f30311398b..03d3aa726ed5 100644 --- a/Core/FileLoaders/CachingFileLoader.h +++ b/Core/FileLoaders/CachingFileLoader.h @@ -28,6 +28,7 @@ class CachingFileLoader : public FileLoader { CachingFileLoader(FileLoader *backend); ~CachingFileLoader() override; + bool IsRemote() override; bool Exists() override; bool ExistsFast() override; bool IsDirectory() override; @@ -39,6 +40,8 @@ class CachingFileLoader : public FileLoader { } 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 +60,10 @@ class CachingFileLoader : public FileLoader { 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 +80,6 @@ class CachingFileLoader : public FileLoader { 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 912ca4f509af..b098df4866b2 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,14 @@ size_t DiskCachingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, return readSize; } +bool DiskCachingFileLoader::IsRemote() { + return backend_->IsRemote(); +} + +void DiskCachingFileLoader::Cancel() { + backend_->Cancel(); +} + std::vector DiskCachingFileLoader::GetCachedPathsInUse() { std::lock_guard guard(cachesMutex_); @@ -156,7 +161,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 1ea27ee0cbf8..e396ff5736ad 100644 --- a/Core/FileLoaders/DiskCachingFileLoader.h +++ b/Core/FileLoaders/DiskCachingFileLoader.h @@ -32,6 +32,7 @@ class DiskCachingFileLoader : public FileLoader { DiskCachingFileLoader(FileLoader *backend); ~DiskCachingFileLoader() override; + bool IsRemote() override; bool Exists() override; bool ExistsFast() override; bool IsDirectory() override; @@ -43,6 +44,8 @@ class DiskCachingFileLoader : public FileLoader { } 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 +53,10 @@ class DiskCachingFileLoader : public FileLoader { 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 +142,7 @@ class DiskCachingFileLoaderCache { INVALID_INDEX = 0xFFFFFFFF, }; - int refCount_; + int refCount_ = 0; s64 filesize_; u32 blockSize_; u16 generation_; @@ -176,8 +179,8 @@ class DiskCachingFileLoaderCache { 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 c18e7eef56f0..4dda28584490 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 5b27bf528853..ab4773604f39 100644 --- a/Core/FileLoaders/HTTPFileLoader.h +++ b/Core/FileLoaders/HTTPFileLoader.h @@ -30,6 +30,9 @@ class HTTPFileLoader : public FileLoader { HTTPFileLoader(const std::string &filename); virtual ~HTTPFileLoader() override; + bool IsRemote() override { + return true; + } virtual bool Exists() override; virtual bool ExistsFast() override; virtual bool IsDirectory() override; @@ -41,14 +44,14 @@ class HTTPFileLoader : public FileLoader { } 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 +60,13 @@ class HTTPFileLoader : public FileLoader { 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 1bc01e9749b3..ccaa3c7befbb 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) { @@ -264,3 +270,7 @@ u32 RamCachingFileLoader::NextAheadBlock() { return 0xFFFFFFFF; } + +bool RamCachingFileLoader::IsRemote() { + return backend_->IsRemote(); +} diff --git a/Core/FileLoaders/RamCachingFileLoader.h b/Core/FileLoaders/RamCachingFileLoader.h index 0911b430744e..624305155a96 100644 --- a/Core/FileLoaders/RamCachingFileLoader.h +++ b/Core/FileLoaders/RamCachingFileLoader.h @@ -28,6 +28,7 @@ class RamCachingFileLoader : public FileLoader { RamCachingFileLoader(FileLoader *backend); ~RamCachingFileLoader() override; + bool IsRemote() override; bool Exists() override; bool ExistsFast() override; bool IsDirectory() override; @@ -39,6 +40,8 @@ class RamCachingFileLoader : public FileLoader { } 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 +58,16 @@ class RamCachingFileLoader : public FileLoader { 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 b9c7927cc2d9..4ce1da026148 100644 --- a/Core/FileLoaders/RetryingFileLoader.cpp +++ b/Core/FileLoaders/RetryingFileLoader.cpp @@ -72,3 +72,11 @@ size_t RetryingFileLoader::ReadAt(s64 absolutePos, size_t bytes, void *data, Fla return readSize; } + +bool RetryingFileLoader::IsRemote() { + return backend_->IsRemote(); +} + +void RetryingFileLoader::Cancel() { + backend_->Cancel(); +} diff --git a/Core/FileLoaders/RetryingFileLoader.h b/Core/FileLoaders/RetryingFileLoader.h index 98ed64f036bd..5c8cb5929217 100644 --- a/Core/FileLoaders/RetryingFileLoader.h +++ b/Core/FileLoaders/RetryingFileLoader.h @@ -25,6 +25,7 @@ class RetryingFileLoader : public FileLoader { RetryingFileLoader(FileLoader *backend); ~RetryingFileLoader() override; + bool IsRemote() override; bool Exists() override; bool ExistsFast() override; bool IsDirectory() override; @@ -36,6 +37,8 @@ class RetryingFileLoader : public FileLoader { } 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 fe24872bfd8f..05837433f89c 100644 --- a/Core/Loaders.h +++ b/Core/Loaders.h @@ -66,6 +66,9 @@ class FileLoader { virtual ~FileLoader() {} + virtual bool IsRemote() { + return false; + } virtual bool Exists() = 0; virtual bool ExistsFast() { return Exists(); @@ -86,6 +89,10 @@ class FileLoader { 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) { diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 37f962c874ba..ad5ddd7bd233 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -54,7 +54,7 @@ GameInfo::~GameInfo() { icon.Clear(); pic0.Clear(); pic1.Clear(); - delete fileLoader; + fileLoader.reset(); } bool GameInfo::Delete() { @@ -218,8 +218,7 @@ bool GameInfo::LoadFromPath(const std::string &gamePath) { std::lock_guard guard(lock); // No need to rebuild if we already have it loaded. if (filePath_ != gamePath) { - delete fileLoader; - fileLoader = ConstructFileLoader(gamePath); + fileLoader.reset(ConstructFileLoader(gamePath)); if (!fileLoader) return false; filePath_ = gamePath; @@ -231,16 +230,15 @@ bool GameInfo::LoadFromPath(const std::string &gamePath) { return fileLoader ? fileLoader->Exists() : true; } -FileLoader *GameInfo::GetFileLoader() { +std::shared_ptr GameInfo::GetFileLoader() { if (!fileLoader) { - fileLoader = ConstructFileLoader(filePath_); + fileLoader.reset(ConstructFileLoader(filePath_)); } return fileLoader; } void GameInfo::DisposeFileLoader() { - delete fileLoader; - fileLoader = nullptr; + fileLoader.reset(); } bool GameInfo::DeleteAllSaveData() { @@ -373,24 +371,22 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { { std::lock_guard lock(info_->lock); info_->working = true; - info_->fileType = Identify_File(info_->GetFileLoader()); + info_->fileType = Identify_File(info_->GetFileLoader().get()); } switch (info_->fileType) { case IdentifiedFileType::PSP_PBP: case IdentifiedFileType::PSP_PBP_DIRECTORY: { - FileLoader *pbpLoader = info_->GetFileLoader(); - std::unique_ptr altLoader; + auto pbpLoader = info_->GetFileLoader(); if (info_->fileType == IdentifiedFileType::PSP_PBP_DIRECTORY) { std::string ebootPath = ResolvePBPFile(gamePath_); if (ebootPath != gamePath_) { - pbpLoader = ConstructFileLoader(ebootPath); - altLoader.reset(pbpLoader); + pbpLoader.reset(ConstructFileLoader(ebootPath)); } } - PBPReader pbp(pbpLoader); + PBPReader pbp(pbpLoader.get()); if (!pbp.IsValid()) { if (pbp.IsELF()) { goto handleELF; @@ -559,10 +555,10 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { // Let's assume it's an ISO. // TODO: This will currently read in the whole directory tree. Not really necessary for just a // few files. - FileLoader *fl = info_->GetFileLoader(); + auto fl = info_->GetFileLoader(); if (!fl) return; // Happens with UWP currently, TODO... - BlockDevice *bd = constructBlockDevice(info_->GetFileLoader()); + BlockDevice *bd = constructBlockDevice(info_->GetFileLoader().get()); if (!bd) return; // nothing to do here.. ISOFileSystem umd(&handles, bd); @@ -650,6 +646,11 @@ class GameInfoWorkItem : public PrioritizedWorkQueueItem { } float priority() override { + auto fl = info_->GetFileLoader(); + if (fl && fl->IsRemote()) { + // Increase the value so remote info loads after non-remote. + return info_->lastAccessedTime + 1000.0f; + } return info_->lastAccessedTime; } @@ -674,6 +675,8 @@ void GameInfoCache::Init() { } void GameInfoCache::Shutdown() { + CancelAll(); + if (gameInfoWQ_) { StopProcessingWorkQueue(gameInfoWQ_); delete gameInfoWQ_; @@ -682,6 +685,8 @@ void GameInfoCache::Shutdown() { } void GameInfoCache::Clear() { + CancelAll(); + if (gameInfoWQ_) { gameInfoWQ_->Flush(); gameInfoWQ_->WaitUntilDone(); @@ -689,6 +694,15 @@ void GameInfoCache::Clear() { info_.clear(); } +void GameInfoCache::CancelAll() { + for (auto info : info_) { + auto fl = info.second->GetFileLoader(); + if (fl) { + fl->Cancel(); + } + } +} + void GameInfoCache::FlushBGs() { for (auto iter = info_.begin(); iter != info_.end(); iter++) { std::lock_guard lock(iter->second->lock); diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index f664a1d6210e..0b4201d4a422 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -19,6 +19,7 @@ #include #include +#include #include #include @@ -93,7 +94,7 @@ class GameInfo { bool DeleteAllSaveData(); bool LoadFromPath(const std::string &gamePath); - FileLoader *GetFileLoader(); + std::shared_ptr GetFileLoader(); void DisposeFileLoader(); u64 GetGameSizeInBytes(); @@ -148,7 +149,7 @@ class GameInfo { // Note: this can change while loading, use GetTitle(). std::string title; - FileLoader *fileLoader = nullptr; + std::shared_ptr fileLoader; std::string filePath_; private: @@ -173,6 +174,7 @@ class GameInfoCache { PrioritizedWorkQueue *WorkQueue() { return gameInfoWQ_; } + void CancelAll(); void WaitUntilDone(std::shared_ptr &info); private: diff --git a/UI/NativeApp.cpp b/UI/NativeApp.cpp index fd00432a5444..7d9422ddee5e 100644 --- a/UI/NativeApp.cpp +++ b/UI/NativeApp.cpp @@ -942,15 +942,18 @@ void HandleGlobalMessage(const std::string &msg, const std::string &value) { void NativeUpdate() { PROFILE_END_FRAME(); + std::vector toProcess; { std::lock_guard lock(pendingMutex); - for (size_t i = 0; i < pendingMessages.size(); i++) { - HandleGlobalMessage(pendingMessages[i].msg, pendingMessages[i].value); - screenManager->sendMessage(pendingMessages[i].msg.c_str(), pendingMessages[i].value.c_str()); - } + toProcess = std::move(pendingMessages); pendingMessages.clear(); } + for (size_t i = 0; i < toProcess.size(); i++) { + HandleGlobalMessage(toProcess[i].msg, toProcess[i].value); + screenManager->sendMessage(toProcess[i].msg.c_str(), toProcess[i].value.c_str()); + } + g_DownloadManager.Update(); screenManager->update(); } diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index 5c44abb5a63b..87d5d799c06b 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -1171,8 +1171,6 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J } ILOG("Leaving EGL/Vulkan render loop."); - if (g_gameInfoCache) - g_gameInfoCache->WorkQueue()->Flush(); NativeShutdownGraphics(); renderer_inited = false;