Merge pull request #3126 from unknownbrackets/io-async

Use a separate thread for reading/writing
This commit is contained in:
Henrik Rydgård 2013-08-11 13:00:41 -07:00
commit 66569b8e59
14 changed files with 399 additions and 70 deletions

View File

@ -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

View File

@ -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

View File

@ -90,6 +90,7 @@ void Config::Load(const char *iniFileName)
cpu->Get("Jit", &bJit, true);
#endif
cpu->Get("SeparateCPUThread", &bSeparateCPUThread, false);
cpu->Get("SeparateIOThread", &bSeparateIOThread, true);
cpu->Get("FastMemory", &bFastMemory, false);
cpu->Get("CPUSpeed", &iLockedCPUSpeed, false);
@ -228,6 +229,7 @@ void Config::Save()
IniFile::Section *cpu = iniFile.GetOrCreateSection("CPU");
cpu->Set("Jit", bJit);
cpu->Set("SeparateCPUThread", bSeparateCPUThread);
cpu->Set("SeparateIOThread", bSeparateIOThread);
cpu->Set("FastMemory", bFastMemory);
cpu->Set("CPUSpeed", iLockedCPUSpeed);

View File

@ -58,6 +58,7 @@ public:
bool bJit;
// Definitely cannot be changed while game is running.
bool bSeparateCPUThread;
bool bSeparateIOThread;
int iLockedCPUSpeed;
bool bAutoSaveSymbolMap;
std::string sReportHost;

View File

@ -251,6 +251,7 @@
<ClCompile Include="HW\MpegDemux.cpp" />
<ClCompile Include="HW\OMAConvert.cpp" />
<ClCompile Include="HW\SasAudio.cpp" />
<ClCompile Include="HW\AsyncIOManager.cpp" />
<ClCompile Include="Loaders.cpp" />
<ClCompile Include="MemMap.cpp" />
<ClCompile Include="MemmapFunctions.cpp" />
@ -437,6 +438,7 @@
<ClInclude Include="HW\OMAConvert.h" />
<ClInclude Include="HW\SasAudio.h" />
<ClInclude Include="HW\MemoryStick.h" />
<ClInclude Include="HW\AsyncIOManager.h" />
<ClInclude Include="Loaders.h" />
<ClInclude Include="MemMap.h" />
<ClInclude Include="MIPS\ARM\ArmAsm.h">

View File

@ -451,6 +451,9 @@
<ClCompile Include="FileSystems\VirtualDiscFileSystem.cpp">
<Filter>FileSystems</Filter>
</ClCompile>
<ClCompile Include="HW\AsyncIOManager.cpp">
<Filter>HW</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="ELF\ElfReader.h">
@ -840,6 +843,9 @@
<ClInclude Include="ThreadEventQueue.h">
<Filter>Core</Filter>
</ClInclude>
<ClInclude Include="HW\AsyncIOManager.h">
<Filter>HW</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="CMakeLists.txt" />

View File

@ -16,33 +16,36 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <cstdlib>
#include "native/thread/thread.h"
#include "native/thread/threadutil.h"
#include "Core/Config.h"
#include "Core/System.h"
#include "Core/Host.h"
#include "Core/SaveState.h"
#include "HLE.h"
#include "Core/HLE/HLE.h"
#include "Core/MIPS/MIPS.h"
#include "Core/HW/MemoryStick.h"
#include "Core/HW/AsyncIOManager.h"
#include "Core/CoreTiming.h"
#include "Core/Reporting.h"
#include "../FileSystems/FileSystem.h"
#include "../FileSystems/MetaFileSystem.h"
#include "../FileSystems/ISOFileSystem.h"
#include "../FileSystems/DirectoryFileSystem.h"
#include "Core/FileSystems/FileSystem.h"
#include "Core/FileSystems/MetaFileSystem.h"
#include "Core/FileSystems/ISOFileSystem.h"
#include "Core/FileSystems/DirectoryFileSystem.h"
extern "C" {
#include "ext/libkirk/amctrl.h"
};
#include "sceIo.h"
#include "sceRtc.h"
#include "sceKernel.h"
#include "sceKernelMemory.h"
#include "sceKernelThread.h"
#include "Core/HLE/sceIo.h"
#include "Core/HLE/sceRtc.h"
#include "Core/HLE/sceKernel.h"
#include "Core/HLE/sceKernelMemory.h"
#include "Core/HLE/sceKernelThread.h"
// For headless screenshots.
#include "sceDisplay.h"
#include "Core/HLE/sceDisplay.h"
const int ERROR_ERRNO_FILE_NOT_FOUND = 0x80010002;
const int ERROR_ERRNO_FILE_ALREADY_EXISTS = 0x80010011;
@ -101,7 +104,14 @@ const int PSP_COUNT_FDS = 64;
// TODO: Should be 3, and stdin/stdout/stderr are special values aliased to 0?
const int PSP_MIN_FD = 4;
static int asyncNotifyEvent = -1;
static int syncNotifyEvent = -1;
static SceUID fds[PSP_COUNT_FDS];
static AsyncIOManager ioManager;
static bool ioManagerThreadEnabled = false;
static std::thread *ioManagerThread;
// TODO: Is it better to just put all on the thread?
const int IO_THREAD_MIN_DATA_SIZE = 256;
#define SCE_STM_FDIR 0x1000
#define SCE_STM_FREG 0x2000
@ -292,6 +302,31 @@ void __IoAsyncNotify(u64 userdata, int cyclesLate) {
}
}
void __IoSyncNotify(u64 userdata, int cyclesLate) {
SceUID threadID = userdata >> 32;
int fd = (int) (userdata & 0xFFFFFFFF);
s64 result = -1;
u32 error;
FileNode *f = __IoGetFd(fd, error);
if (f) {
f->pendingAsyncResult = false;
f->hasAsyncResult = true;
AsyncIOResult managerResult;
if (ioManager.WaitResult(f->handle, managerResult)) {
result = managerResult;
} else {
ERROR_LOG(HLE, "Unable to complete IO operation.");
}
}
SceUID waitID = __KernelGetWaitID(threadID, WAITTYPE_IO, error);
if (waitID == fd && error == 0) {
__KernelResumeThreadFromWait(threadID, result);
}
}
static DirectoryFileSystem *memstickSystem = NULL;
#ifdef ANDROID
static VFSFileSystem *flash0System = NULL;
@ -299,12 +334,20 @@ static VFSFileSystem *flash0System = NULL;
static DirectoryFileSystem *flash0System = NULL;
#endif
void __IoManagerThread() {
setCurrentThreadName("IOThread");
while (ioManagerThreadEnabled) {
ioManager.RunEventsUntil(CoreTiming::GetTicks() + msToCycles(1000));
}
}
void __IoInit() {
INFO_LOG(HLE, "Starting up I/O...");
MemoryStick_SetFatState(PSP_FAT_MEMORYSTICK_STATE_ASSIGNED);
asyncNotifyEvent = CoreTiming::RegisterEvent("IoAsyncNotify", __IoAsyncNotify);
syncNotifyEvent = CoreTiming::RegisterEvent("IoSyncNotify", __IoSyncNotify);
std::string memstickpath;
std::string flash0path;
@ -324,15 +367,33 @@ void __IoInit() {
__KernelListenThreadEnd(&TellFsThreadEnded);
memset(fds, 0, sizeof(fds));
ioManagerThreadEnabled = g_Config.bSeparateIOThread;
ioManager.SetThreadEnabled(ioManagerThreadEnabled);
if (ioManagerThreadEnabled) {
ioManagerThread = new std::thread(&__IoManagerThread);
}
}
void __IoDoState(PointerWrap &p) {
ioManager.DoState(p);
p.DoArray(fds, ARRAY_SIZE(fds));
p.Do(asyncNotifyEvent);
CoreTiming::RestoreRegisterEvent(asyncNotifyEvent, "IoAsyncNotify", __IoAsyncNotify);
p.Do(syncNotifyEvent);
CoreTiming::RestoreRegisterEvent(syncNotifyEvent, "IoSyncNotify", __IoSyncNotify);
p.DoMarker("sceIo");
}
void __IoShutdown() {
ioManagerThreadEnabled = false;
ioManager.SyncThread();
ioManager.FinishEventLoop();
if (ioManagerThread != NULL) {
delete ioManagerThread;
ioManagerThread = NULL;
}
pspFileSystem.Unmount("ms0:", memstickSystem);
pspFileSystem.Unmount("fatms0:", memstickSystem);
pspFileSystem.Unmount("fatms:", memstickSystem);
@ -400,6 +461,12 @@ void __IoCompleteAsyncIO(int fd) {
u32 error;
FileNode *f = __IoGetFd(fd, error);
if (f) {
AsyncIOResult managerResult;
if (ioManager.WaitResult(f->handle, managerResult)) {
f->asyncResult = managerResult;
} else {
// It's okay, not all operations are deferred.
}
if (f->callbackID) {
__KernelNotifyCallback(THREAD_CALLBACK_IO, f->callbackID, f->callbackArg);
}
@ -446,6 +513,14 @@ void __IoSchedAsync(FileNode *f, int fd, int usec) {
f->hasAsyncResult = false;
}
void __IoSchedSync(FileNode *f, int fd, int usec) {
u64 param = ((u64)__KernelGetCurThread()) << 32 | fd;
CoreTiming::ScheduleEvent(usToCycles(usec), syncNotifyEvent, param);
f->pendingAsyncResult = true;
f->hasAsyncResult = false;
}
u32 sceIoGetstat(const char *filename, u32 addr) {
// TODO: Improve timing (although this seems normally slow..)
int usec = 1000;
@ -525,7 +600,7 @@ u32 npdrmRead(FileNode *f, u8 *data, int size) {
return size;
}
int __IoRead(int id, u32 data_addr, int size) {
bool __IoRead(int &result, int id, u32 data_addr, int size) {
if (id == 3) {
DEBUG_LOG(HLE, "sceIoRead STDIN");
return 0; //stdin
@ -534,58 +609,88 @@ int __IoRead(int id, u32 data_addr, int size) {
u32 error;
FileNode *f = __IoGetFd(id, error);
if (f) {
if(!(f->openMode & FILEACCESS_READ))
{
return ERROR_KERNEL_BAD_FILE_DESCRIPTOR;
}
else if (Memory::IsValidAddress(data_addr)) {
if (!(f->openMode & FILEACCESS_READ)) {
result = ERROR_KERNEL_BAD_FILE_DESCRIPTOR;
return true;
} else if (Memory::IsValidAddress(data_addr)) {
u8 *data = (u8*) Memory::GetPointer(data_addr);
if(f->npdrm){
return npdrmRead(f, data, size);
}else{
return (int) pspFileSystem.ReadFile(f->handle, data, size);
if (f->npdrm) {
result = npdrmRead(f, data, size);
return true;
} else if (__KernelIsDispatchEnabled() && ioManagerThreadEnabled && size > IO_THREAD_MIN_DATA_SIZE) {
AsyncIOEvent ev = IO_EVENT_READ;
ev.handle = f->handle;
ev.buf = data;
ev.bytes = size;
ioManager.ScheduleOperation(ev);
return false;
} else {
result = (int) pspFileSystem.ReadFile(f->handle, data, size);
return true;
}
} else {
ERROR_LOG(HLE, "sceIoRead Reading into bad pointer %08x", data_addr);
// TODO: Returning 0 because it wasn't being sign-extended in async result before.
// What should this do?
return 0;
result = 0;
return true;
}
} else {
ERROR_LOG(HLE, "sceIoRead ERROR: no file open");
return error;
result = error;
return true;
}
}
u32 sceIoRead(int id, u32 data_addr, int size) {
// TODO: Check id is valid first?
if (!__KernelIsDispatchEnabled() && id > 2)
if (!__KernelIsDispatchEnabled() && id > 2) {
return -1;
int result = __IoRead(id, data_addr, size);
if (result >= 0) {
DEBUG_LOG(HLE, "%x=sceIoRead(%d, %08x, %x)", result, id, data_addr, size);
// TODO: Timing is probably not very accurate, low estimate.
int us = result/100;
if(us==0)
us = 100;
return hleDelayResult(result, "io read", us);
}
else
// TODO: Timing is probably not very accurate, low estimate.
int us = size / 100;
if (us < 100) {
us = 100;
}
int result;
bool complete = __IoRead(result, id, data_addr, size);
if (!complete) {
DEBUG_LOG(HLE, "sceIoRead(%d, %08x, %x): deferring result", id, data_addr, size);
u32 error;
FileNode *f = __IoGetFd(id, error);
__IoSchedSync(f, id, us);
__KernelWaitCurThread(WAITTYPE_IO, id, 0, 0, false, "io read");
return 0;
} else if (result >= 0) {
DEBUG_LOG(HLE, "%x=sceIoRead(%d, %08x, %x)", result, id, data_addr, size);
return hleDelayResult(result, "io read", us);
} else {
return result;
}
}
u32 sceIoReadAsync(int id, u32 data_addr, int size) {
// TODO: Not sure what the correct delay is (and technically we shouldn't read into the buffer yet...)
int us = size / 100;
if (us < 100) {
us = 100;
}
u32 error;
FileNode *f = __IoGetFd(id, error);
if (f) {
f->asyncResult = __IoRead(id, data_addr, size);
// TODO: Not sure what the correct delay is (and technically we shouldn't read into the buffer yet...)
int us = f->asyncResult/100;
if(us==0)
us = 100;
int result;
bool complete = __IoRead(result, id, data_addr, size);
if (complete) {
f->asyncResult = result;
DEBUG_LOG(HLE, "%llx=sceIoReadAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size);
} else {
DEBUG_LOG(HLE, "sceIoReadAsync(%d, %08x, %x): deferring result", id, data_addr, size);
}
__IoSchedAsync(f, id, us);
DEBUG_LOG(HLE, "%llx=sceIoReadAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size);
return 0;
} else {
ERROR_LOG(HLE, "sceIoReadAsync: bad file %d", id);
@ -593,24 +698,37 @@ u32 sceIoReadAsync(int id, u32 data_addr, int size) {
}
}
int __IoWrite(int id, void *data_ptr, int size) {
bool __IoWrite(int &result, int id, void *data_ptr, int size) {
// Let's handle stdout/stderr specially.
if (id == 1 || id == 2) {
const char *str = (const char *) data_ptr;
const int str_size = size == 0 ? 0 : (str[size - 1] == '\n' ? size - 1 : size);
INFO_LOG(HLE, "%s: %.*s", id == 1 ? "stdout" : "stderr", str_size, str);
return size;
result = size;
return true;
}
u32 error;
FileNode *f = __IoGetFd(id, error);
if (f) {
if(!(f->openMode & FILEACCESS_WRITE)) {
return ERROR_KERNEL_BAD_FILE_DESCRIPTOR;
if (!(f->openMode & FILEACCESS_WRITE)) {
result = ERROR_KERNEL_BAD_FILE_DESCRIPTOR;
return true;
}
return (int) pspFileSystem.WriteFile(f->handle, (u8*) data_ptr, size);
if (__KernelIsDispatchEnabled() && ioManagerThreadEnabled && size > IO_THREAD_MIN_DATA_SIZE) {
AsyncIOEvent ev = IO_EVENT_WRITE;
ev.handle = f->handle;
ev.buf = (u8 *) data_ptr;
ev.bytes = size;
ioManager.ScheduleOperation(ev);
return false;
} else {
result = (int) pspFileSystem.WriteFile(f->handle, (u8 *) data_ptr, size);
}
return true;
} else {
ERROR_LOG(HLE, "sceIoWrite ERROR: no file open");
return (s32) error;
result = (s32) error;
return true;
}
}
@ -619,33 +737,53 @@ u32 sceIoWrite(int id, u32 data_addr, int size) {
if (!__KernelIsDispatchEnabled() && id > 2)
return -1;
int result = __IoWrite(id, Memory::GetPointer(data_addr), size);
if (result >= 0) {
DEBUG_LOG(HLE, "%x=sceIoWrite(%d, %08x, %x)", result, id, data_addr, size);
// TODO: Timing is probably not very accurate, low estimate.
int us = result/100;
if(us==0)
us = 100;
if (__KernelIsDispatchEnabled())
return hleDelayResult(result, "io write", us);
else
return result;
// TODO: Timing is probably not very accurate, low estimate.
int us = size / 100;
if (us < 100) {
us = 100;
}
else
int result;
bool complete = __IoWrite(result, id, Memory::GetPointer(data_addr), size);
if (!complete) {
DEBUG_LOG(HLE, "sceIoWrite(%d, %08x, %x): deferring result", id, data_addr, size);
u32 error;
FileNode *f = __IoGetFd(id, error);
__IoSchedSync(f, id, us);
__KernelWaitCurThread(WAITTYPE_IO, id, 0, 0, false, "io write");
return 0;
} else if (result >= 0) {
DEBUG_LOG(HLE, "%x=sceIoWrite(%d, %08x, %x)", result, id, data_addr, size);
if (__KernelIsDispatchEnabled()) {
return hleDelayResult(result, "io write", us);
} else {
return result;
}
} else {
return result;
}
}
u32 sceIoWriteAsync(int id, u32 data_addr, int size) {
// TODO: Not sure what the correct delay is (and technically we shouldn't read from the buffer yet...)
int us = size / 100;
if (us < 100) {
us = 100;
}
u32 error;
FileNode *f = __IoGetFd(id, error);
if (f) {
f->asyncResult = __IoWrite(id, Memory::GetPointer(data_addr), size);
// TODO: Not sure what the correct delay is (and technically we shouldn't read into the buffer yet...)
int us = f->asyncResult/100;
if(us==0)
us = 100;
int result;
bool complete = __IoWrite(result, id, Memory::GetPointer(data_addr), size);
if (complete) {
f->asyncResult = result;
DEBUG_LOG(HLE, "%llx=sceIoWriteAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size);
} else {
DEBUG_LOG(HLE, "sceIoWriteAsync(%d, %08x, %x): deferring result", id, data_addr, size);
}
__IoSchedAsync(f, id, us);
DEBUG_LOG(HLE, "%llx=sceIoWriteAsync(%d, %08x, %x)", f->asyncResult, id, data_addr, size);
return 0;
} else {
ERROR_LOG(HLE, "sceIoWriteAsync: bad file %d", id);

View File

@ -19,9 +19,9 @@
#include <string>
#include "../System.h"
#include "HLE.h"
#include "sceKernel.h"
#include "Core/System.h"
#include "Core/HLE/HLE.h"
#include "Core/HLE/sceKernel.h"
void __IoInit();
void __IoDoState(PointerWrap &p);

View File

@ -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");
}

75
Core/HW/AsyncIOManager.h Normal file
View File

@ -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 <map>
#include <set>
#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<NoBase, AsyncIOEvent, AsyncIOEventType, IO_EVENT_INVALID, IO_EVENT_SYNC, IO_EVENT_FINISH> 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<u32> resultsPending_;
std::map<u32, AsyncIOResult> results_;
};

View File

@ -20,6 +20,7 @@
#endif
#include "native/thread/thread.h"
#include "native/thread/threadutil.h"
#include "native/base/mutex.h"
#include "Core/MemMap.h"
@ -42,7 +43,6 @@
#include "Core/PSPLoaders.h"
#include "Core/ELF/ParamSFO.h"
#include "Core/SaveState.h"
#include "Common/Thread.h"
#include "Common/LogManager.h"
#include "GPU/GPUState.h"
@ -196,7 +196,7 @@ void CPU_Shutdown() {
}
void CPU_RunLoop() {
Common::SetCurrentThreadName("CPUThread");
setCurrentThreadName("CPUThread");
if (!CPU_NextState(CPU_THREAD_PENDING, CPU_THREAD_STARTING)) {
ERROR_LOG(CPU, "CPU thread in unexpected state: %d", cpuThreadState);
return;

View File

@ -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_;

View File

@ -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 {

View File

@ -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 \