From e6b42768fe77eeedb430d26f1b47efb5e1b5ca3d Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 11 Aug 2013 11:40:41 -0700 Subject: [PATCH] Add a class to manage IO on a separate thread. Also separate the logic for exiting the loop based on coreState. IO and audio won't necessarily be tied to the frame. --- CMakeLists.txt | 2 + Core/CMakeLists.txt | 1 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 +++ Core/HW/AsyncIOManager.cpp | 97 ++++++++++++++++++++++++++++++++++++++ Core/HW/AsyncIOManager.h | 75 +++++++++++++++++++++++++++++ Core/ThreadEventQueue.h | 3 +- GPU/GPUCommon.h | 3 ++ android/jni/Android.mk | 1 + 9 files changed, 189 insertions(+), 1 deletion(-) create mode 100644 Core/HW/AsyncIOManager.cpp create mode 100644 Core/HW/AsyncIOManager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 36f71bfb8b..95f44d9753 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -898,6 +898,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/scePauth.h Core/HW/atrac3plus.cpp Core/HW/atrac3plus.h + Core/HW/AsyncIOManager.cpp + Core/HW/AsyncIOManager.h Core/HW/MediaEngine.cpp Core/HW/MediaEngine.h Core/HW/MpegDemux.cpp diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt index 9d1b4bf89c..90dbf87d39 100644 --- a/Core/CMakeLists.txt +++ b/Core/CMakeLists.txt @@ -74,6 +74,7 @@ set(SRCS HLE/sceParseHttp.cpp HLE/sceVaudio.cpp HLE/sceAudiocodec.cpp + HW/AsyncIOManager.cpp HW/MemoryStick.cpp HW/MediaEngine.cpp HW/SasAudio.cpp diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 1416bbb4d0..60a98ee845 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -251,6 +251,7 @@ + @@ -437,6 +438,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index d9861b0b99..e96aaf9a55 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -451,6 +451,9 @@ FileSystems + + HW + @@ -840,6 +843,9 @@ Core + + HW + diff --git a/Core/HW/AsyncIOManager.cpp b/Core/HW/AsyncIOManager.cpp new file mode 100644 index 0000000000..062fab6880 --- /dev/null +++ b/Core/HW/AsyncIOManager.cpp @@ -0,0 +1,97 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include "Core/Reporting.h" +#include "Core/System.h" +#include "Core/HW/AsyncIOManager.h" +#include "Core/FileSystems/MetaFileSystem.h" + +void AsyncIOManager::ScheduleOperation(AsyncIOEvent ev) { + lock_guard guard(resultsLock_); + resultsPending_.insert(ev.handle); + ScheduleEvent(ev); +} + +bool AsyncIOManager::PopResult(u32 handle, AsyncIOResult &result) { + lock_guard guard(resultsLock_); + if (results_.find(handle) != results_.end()) { + result = results_[handle]; + results_.erase(handle); + resultsPending_.erase(handle); + return true; + } else { + return false; + } +} + +bool AsyncIOManager::WaitResult(u32 handle, AsyncIOResult &result) { + lock_guard guard(resultsLock_); + ScheduleEvent(IO_EVENT_SYNC); + while (HasEvents() && resultsPending_.find(handle) != resultsPending_.end()) { + if (PopResult(handle, result)) { + return true; + } + resultsWait_.wait_for(resultsLock_, 16); + } + if (PopResult(handle, result)) { + return true; + } + + return false; +} + +void AsyncIOManager::ProcessEvent(AsyncIOEvent ev) { + switch (ev.type) { + case IO_EVENT_READ: + Read(ev.handle, ev.buf, ev.bytes); + break; + + case IO_EVENT_WRITE: + Write(ev.handle, ev.buf, ev.bytes); + break; + + default: + ERROR_LOG(HLE, "Unsupported IO event type"); + } +} + +void AsyncIOManager::Read(u32 handle, u8 *buf, size_t bytes) { + size_t result = pspFileSystem.ReadFile(handle, buf, bytes); + EventResult(handle, result); +} + +void AsyncIOManager::Write(u32 handle, u8 *buf, size_t bytes) { + size_t result = pspFileSystem.WriteFile(handle, buf, bytes); + EventResult(handle, result); +} + +void AsyncIOManager::EventResult(u32 handle, AsyncIOResult result) { + lock_guard guard(resultsLock_); + if (results_.find(handle) != results_.end()) { + ERROR_LOG_REPORT(HLE, "Overwriting previous result for file action on handle %d", handle); + } + results_[handle] = result; + resultsWait_.notify_one(); +} + +void AsyncIOManager::DoState(PointerWrap &p) { + SyncThread(); + lock_guard guard(resultsLock_); + p.Do(resultsPending_); + p.Do(results_); + p.DoMarker("AsyncIOManager"); +} diff --git a/Core/HW/AsyncIOManager.h b/Core/HW/AsyncIOManager.h new file mode 100644 index 0000000000..6c057da9b1 --- /dev/null +++ b/Core/HW/AsyncIOManager.h @@ -0,0 +1,75 @@ +// Copyright (c) 2012- PPSSPP Project. + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, version 2.0 or later versions. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License 2.0 for more details. + +// A copy of the GPL 2.0 should have been included with the program. +// If not, see http://www.gnu.org/licenses/ + +// Official git repository and contact information can be found at +// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. + +#include +#include +#include "native/base/mutex.h" +#include "Core/ThreadEventQueue.h" + +class NoBase { +}; + +enum AsyncIOEventType { + IO_EVENT_INVALID, + IO_EVENT_SYNC, + IO_EVENT_FINISH, + IO_EVENT_READ, + IO_EVENT_WRITE, +}; + +struct AsyncIOEvent { + AsyncIOEvent(AsyncIOEventType t) : type(t) {} + AsyncIOEventType type; + u32 handle; + u8 *buf; + size_t bytes; + + operator AsyncIOEventType() const { + return type; + } +}; + +// TODO: Something better. +typedef size_t AsyncIOResult; + +typedef ThreadEventQueue IOThreadEventQueue; +class AsyncIOManager : public IOThreadEventQueue { +public: + void DoState(PointerWrap &p); + + void ScheduleOperation(AsyncIOEvent ev); + + bool PopResult(u32 handle, AsyncIOResult &result); + bool WaitResult(u32 handle, AsyncIOResult &result); + +protected: + virtual void ProcessEvent(AsyncIOEvent ref); + virtual bool ShouldExitEventLoop() { + return coreState == CORE_ERROR || coreState == CORE_POWERDOWN; + } + +private: + void Read(u32 handle, u8 *buf, size_t bytes); + void Write(u32 handle, u8 *buf, size_t bytes); + + void EventResult(u32 handle, AsyncIOResult result); + + recursive_mutex resultsLock_; + condition_variable resultsWait_; + std::set resultsPending_; + std::map results_; +}; \ No newline at end of file diff --git a/Core/ThreadEventQueue.h b/Core/ThreadEventQueue.h index 11231ea6ac..c0732b6a8c 100644 --- a/Core/ThreadEventQueue.h +++ b/Core/ThreadEventQueue.h @@ -74,7 +74,7 @@ struct ThreadEventQueue : public B { } // Quit the loop if the queue is drained and coreState has tripped, or threading is disabled. - if (coreState != CORE_RUNNING || !threadEnabled_) { + if (ShouldExitEventLoop() || !threadEnabled_) { return; } @@ -104,6 +104,7 @@ struct ThreadEventQueue : public B { protected: virtual void ProcessEvent(Event ev) = 0; + virtual bool ShouldExitEventLoop() = 0; private: bool threadEnabled_; diff --git a/GPU/GPUCommon.h b/GPU/GPUCommon.h index 411021ea1f..dc32975698 100644 --- a/GPU/GPUCommon.h +++ b/GPU/GPUCommon.h @@ -48,6 +48,9 @@ protected: void ProcessDLQueueInternal(); void ReapplyGfxStateInternal(); virtual void ProcessEvent(GPUEvent ev); + virtual bool ShouldExitEventLoop() { + return coreState != CORE_RUNNING; + } // Allows early unlocking with a guard. Do not double unlock. class easy_guard { diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 838d6be0e3..9f99b804fb 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -186,6 +186,7 @@ LOCAL_SRC_FILES := \ $(SRC)/Core/ELF/PrxDecrypter.cpp \ $(SRC)/Core/ELF/ParamSFO.cpp \ $(SRC)/Core/HW/atrac3plus.cpp \ + $(SRC)/Core/HW/AsyncIOManager.cpp \ $(SRC)/Core/HW/MemoryStick.cpp \ $(SRC)/Core/HW/MpegDemux.cpp.arm \ $(SRC)/Core/HW/OMAConvert.cpp.arm \