mirror of
https://github.com/libretro/ppsspp.git
synced 2024-11-23 16:19:44 +00:00
Add a class to create helper threads from HLE.
This should be usable from sceIo as well.
This commit is contained in:
parent
a2031cdc62
commit
b9ede6aade
@ -1016,6 +1016,8 @@ add_library(${CoreLibName} ${CoreLinkType}
|
||||
Core/HLE/HLE.h
|
||||
Core/HLE/ReplaceTables.cpp
|
||||
Core/HLE/ReplaceTables.h
|
||||
Core/HLE/HLEHelperThread.cpp
|
||||
Core/HLE/HLEHelperThread.h
|
||||
Core/HLE/HLETables.cpp
|
||||
Core/HLE/HLETables.h
|
||||
Core/HLE/KernelWaitHelpers.h
|
||||
|
@ -27,6 +27,7 @@ set(SRCS
|
||||
ELF/PrxDecrypter.cpp
|
||||
Font/PGF.cpp
|
||||
HLE/HLE.cpp
|
||||
HLE/HLEHelperThread.cpp
|
||||
HLE/HLETables.cpp
|
||||
HLE/sceAtrac.cpp
|
||||
HLE/__sceAudio.cpp
|
||||
|
@ -199,6 +199,7 @@
|
||||
<ClCompile Include="Font\PGF.cpp" />
|
||||
<ClCompile Include="HDRemaster.cpp" />
|
||||
<ClCompile Include="HLE\HLE.cpp" />
|
||||
<ClCompile Include="HLE\HLEHelperThread.cpp" />
|
||||
<ClCompile Include="HLE\HLETables.cpp" />
|
||||
<ClCompile Include="HLE\proAdhoc.cpp" />
|
||||
<ClCompile Include="HLE\ReplaceTables.cpp" />
|
||||
@ -472,6 +473,7 @@
|
||||
<ClInclude Include="HDRemaster.h" />
|
||||
<ClInclude Include="HLE\FunctionWrappers.h" />
|
||||
<ClInclude Include="HLE\HLE.h" />
|
||||
<ClInclude Include="HLE\HLEHelperThread.h" />
|
||||
<ClInclude Include="HLE\HLETables.h" />
|
||||
<ClInclude Include="HLE\KernelWaitHelpers.h" />
|
||||
<ClInclude Include="HLE\proAdhoc.h" />
|
||||
@ -640,4 +642,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
@ -526,6 +526,9 @@
|
||||
<ClCompile Include="MIPS\x86\JitSafeMem.cpp">
|
||||
<Filter>MIPS\x86</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HLE\HLEHelperThread.cpp">
|
||||
<Filter>HLE</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="ELF\ElfReader.h">
|
||||
@ -972,6 +975,9 @@
|
||||
<ClInclude Include="MIPS\x86\JitSafeMem.h">
|
||||
<Filter>MIPS\x86</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HLE\HLEHelperThread.h">
|
||||
<Filter>HLE</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="CMakeLists.txt" />
|
||||
@ -979,4 +985,4 @@
|
||||
<None Include="..\android\jni\Android.mk" />
|
||||
<None Include="GameLogNotes.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
82
Core/HLE/HLEHelperThread.cpp
Normal file
82
Core/HLE/HLEHelperThread.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
// Copyright (c) 2014- 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/.
|
||||
|
||||
#pragma once
|
||||
#include "Common/ChunkFile.h"
|
||||
#include "Core/MemMap.h"
|
||||
#include "Core/HLE/HLE.h"
|
||||
#include "Core/HLE/HLEHelperThread.h"
|
||||
#include "Core/HLE/sceKernelThread.h"
|
||||
#include "Core/HLE/sceKernelMemory.h"
|
||||
#include "Core/MIPS/MIPSCodeUtils.h"
|
||||
|
||||
HLEHelperThread::HLEHelperThread() : id_(-1), entry_(0) {
|
||||
}
|
||||
|
||||
HLEHelperThread::HLEHelperThread(const char *threadName, u32 instructions[], u32 instrCount, u32 prio, int stacksize) {
|
||||
u32 bytes = instrCount * sizeof(u32);
|
||||
u32 size = bytes + sizeof(u32) * 2;
|
||||
AllocEntry(bytes);
|
||||
Memory::Memcpy(entry_, instructions, bytes);
|
||||
|
||||
// Just to simplify things, we add the return here.
|
||||
Memory::Write_U32(MIPS_MAKE_JR_RA(), entry_ + bytes + 0);
|
||||
Memory::Write_U32(MIPS_MAKE_NOP(), entry_ + bytes + 4);
|
||||
|
||||
Create(threadName, prio, stacksize);
|
||||
}
|
||||
|
||||
HLEHelperThread::HLEHelperThread(const char *threadName, const char *module, const char *func, u32 prio, int stacksize) {
|
||||
const u32 bytes = sizeof(u32) * 2;
|
||||
AllocEntry(bytes);
|
||||
Memory::Write_U32(MIPS_MAKE_JR_RA(), entry_ + 0);
|
||||
Memory::Write_U32(MIPS_MAKE_SYSCALL(module, func), entry_ + 4);
|
||||
|
||||
Create(threadName, prio, stacksize);
|
||||
}
|
||||
|
||||
HLEHelperThread::~HLEHelperThread() {
|
||||
__KernelDeleteThread(id_, SCE_KERNEL_ERROR_THREAD_TERMINATED, "helper deleted");
|
||||
kernelMemory.Free(entry_);
|
||||
}
|
||||
|
||||
void HLEHelperThread::AllocEntry(u32 size) {
|
||||
entry_ = kernelMemory.Alloc(size);
|
||||
currentMIPS->InvalidateICache(entry_, size);
|
||||
}
|
||||
|
||||
void HLEHelperThread::Create(const char *threadName, u32 prio, int stacksize) {
|
||||
id_ = __KernelCreateThreadInternal(threadName, __KernelGetCurThreadModuleId(), entry_, prio, stacksize, 0);
|
||||
}
|
||||
|
||||
void HLEHelperThread::DoState(PointerWrap &p) {
|
||||
auto s = p.Section("HLEHelperThread", 1);
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
|
||||
p.Do(id_);
|
||||
p.Do(entry_);
|
||||
}
|
||||
|
||||
void HLEHelperThread::Start(u32 a0, u32 a1) {
|
||||
__KernelStartThread(id_, a0, a1, true);
|
||||
}
|
||||
|
||||
void HLEHelperThread::Terminate() {
|
||||
__KernelStopThread(id_, SCE_KERNEL_ERROR_THREAD_TERMINATED, "helper terminated");
|
||||
}
|
41
Core/HLE/HLEHelperThread.h
Normal file
41
Core/HLE/HLEHelperThread.h
Normal file
@ -0,0 +1,41 @@
|
||||
// Copyright (c) 2014- 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/.
|
||||
|
||||
#pragma once
|
||||
#include "Core/HLE/sceKernel.h"
|
||||
|
||||
class PointerWrap;
|
||||
|
||||
class HLEHelperThread {
|
||||
public:
|
||||
// For savestates.
|
||||
HLEHelperThread();
|
||||
HLEHelperThread(const char *threadName, u32 instructions[], u32 instrCount, u32 prio, int stacksize);
|
||||
HLEHelperThread(const char *threadName, const char *module, const char *func, u32 prio, int stacksize);
|
||||
~HLEHelperThread();
|
||||
void DoState(PointerWrap &p);
|
||||
|
||||
void Start(u32 a0, u32 a1);
|
||||
void Terminate();
|
||||
|
||||
private:
|
||||
void AllocEntry(u32 size);
|
||||
void Create(const char *threadName, u32 prio, int stacksize);
|
||||
|
||||
SceUID id_;
|
||||
u32 entry_;
|
||||
};
|
@ -2080,6 +2080,16 @@ SceUID __KernelSetupRootThread(SceUID moduleID, int args, const char *argp, int
|
||||
return id;
|
||||
}
|
||||
|
||||
SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr)
|
||||
{
|
||||
SceUID id;
|
||||
Thread *newThread = __KernelCreateThread(id, moduleID, threadName, entry, prio, stacksize, attr);
|
||||
if (newThread->currentStack.start == 0)
|
||||
return SCE_KERNEL_ERROR_NO_MEMORY;
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr)
|
||||
{
|
||||
if (threadName == NULL)
|
||||
@ -2125,9 +2135,8 @@ int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32
|
||||
if ((attr & PSP_THREAD_ATTR_KERNEL) == 0)
|
||||
attr |= PSP_THREAD_ATTR_USER;
|
||||
|
||||
SceUID id;
|
||||
Thread *newThread = __KernelCreateThread(id, moduleID, threadName, entry, prio, stacksize, attr);
|
||||
if (newThread->currentStack.start == 0)
|
||||
SceUID id = __KernelCreateThreadInternal(threadName, moduleID, entry, prio, stacksize, attr);
|
||||
if (id == SCE_KERNEL_ERROR_NO_MEMORY)
|
||||
{
|
||||
ERROR_LOG_REPORT(SCEKERNEL, "sceKernelCreateThread(name=%s): out of memory, %08x stack requested", threadName, stacksize);
|
||||
return SCE_KERNEL_ERROR_NO_MEMORY;
|
||||
@ -2152,6 +2161,54 @@ int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stack
|
||||
return __KernelCreateThread(threadName, __KernelGetCurThreadModuleId(), entry, prio, stacksize, attr, optionAddr);
|
||||
}
|
||||
|
||||
int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bool forceArgs)
|
||||
{
|
||||
u32 error;
|
||||
Thread *startThread = kernelObjects.Get<Thread>(threadToStartID, error);
|
||||
if (startThread == 0)
|
||||
return error;
|
||||
|
||||
Thread *cur = __GetCurrentThread();
|
||||
__KernelResetThread(startThread, cur ? cur->nt.currentPriority : 0);
|
||||
|
||||
u32 &sp = startThread->context.r[MIPS_REG_SP];
|
||||
// Force args means just use those as a0/a1 without any special treatment.
|
||||
// This is a hack to avoid allocating memory for helper threads which take args.
|
||||
if ((argBlockPtr && argSize > 0) || forceArgs)
|
||||
{
|
||||
// Make room for the arguments, always 0x10 aligned.
|
||||
if (!forceArgs)
|
||||
sp -= (argSize + 0xf) & ~0xf;
|
||||
startThread->context.r[MIPS_REG_A0] = argSize;
|
||||
startThread->context.r[MIPS_REG_A1] = sp;
|
||||
}
|
||||
else
|
||||
{
|
||||
startThread->context.r[MIPS_REG_A0] = 0;
|
||||
startThread->context.r[MIPS_REG_A1] = 0;
|
||||
}
|
||||
|
||||
// Now copy argument to stack.
|
||||
if (!forceArgs && Memory::IsValidAddress(argBlockPtr))
|
||||
Memory::Memcpy(sp, Memory::GetPointer(argBlockPtr), argSize);
|
||||
|
||||
// On the PSP, there's an extra 64 bytes of stack eaten after the args.
|
||||
// This could be stack overflow safety, or just stack eaten by the kernel entry func.
|
||||
sp -= 64;
|
||||
|
||||
// Smaller is better for priority. Only switch if the new thread is better.
|
||||
if (cur && cur->nt.currentPriority > startThread->nt.currentPriority)
|
||||
{
|
||||
__KernelChangeReadyState(cur, currentThread, true);
|
||||
hleReSchedule("thread started");
|
||||
}
|
||||
|
||||
// Starting a thread automatically resumes the dispatch thread.
|
||||
dispatchEnabled = true;
|
||||
|
||||
__KernelChangeReadyState(startThread, threadToStartID, true);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// int sceKernelStartThread(SceUID threadToStartID, SceSize argSize, void *argBlock)
|
||||
int sceKernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr)
|
||||
@ -2185,44 +2242,7 @@ int sceKernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr)
|
||||
}
|
||||
|
||||
INFO_LOG(SCEKERNEL, "sceKernelStartThread(thread=%i, argSize=%i, argPtr=%08x)", threadToStartID, argSize, argBlockPtr);
|
||||
|
||||
Thread *cur = __GetCurrentThread();
|
||||
__KernelResetThread(startThread, cur ? cur->nt.currentPriority : 0);
|
||||
|
||||
u32 &sp = startThread->context.r[MIPS_REG_SP];
|
||||
if (argBlockPtr && argSize > 0)
|
||||
{
|
||||
// Make room for the arguments, always 0x10 aligned.
|
||||
sp -= (argSize + 0xf) & ~0xf;
|
||||
startThread->context.r[MIPS_REG_A0] = argSize;
|
||||
startThread->context.r[MIPS_REG_A1] = sp;
|
||||
}
|
||||
else
|
||||
{
|
||||
startThread->context.r[MIPS_REG_A0] = 0;
|
||||
startThread->context.r[MIPS_REG_A1] = 0;
|
||||
}
|
||||
|
||||
// Now copy argument to stack.
|
||||
if (Memory::IsValidAddress(argBlockPtr))
|
||||
Memory::Memcpy(sp, Memory::GetPointer(argBlockPtr), argSize);
|
||||
|
||||
// On the PSP, there's an extra 64 bytes of stack eaten after the args.
|
||||
// This could be stack overflow safety, or just stack eaten by the kernel entry func.
|
||||
sp -= 64;
|
||||
|
||||
// Smaller is better for priority. Only switch if the new thread is better.
|
||||
if (cur && cur->nt.currentPriority > startThread->nt.currentPriority)
|
||||
{
|
||||
__KernelChangeReadyState(cur, currentThread, true);
|
||||
hleReSchedule("thread started");
|
||||
}
|
||||
|
||||
// Starting a thread automatically resumes the dispatch thread.
|
||||
dispatchEnabled = true;
|
||||
|
||||
__KernelChangeReadyState(startThread, threadToStartID, true);
|
||||
return 0;
|
||||
return __KernelStartThread(threadToStartID, argSize, argBlockPtr);
|
||||
}
|
||||
|
||||
int sceKernelGetThreadStackFreeSize(SceUID threadID)
|
||||
|
@ -27,18 +27,22 @@
|
||||
// http://code.google.com/p/jpcsp/source/browse/trunk/src/jpcsp/HLE/modules150/ThreadManForUser.java
|
||||
|
||||
int sceKernelChangeThreadPriority(SceUID threadID, int priority);
|
||||
SceUID __KernelCreateThreadInternal(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr);
|
||||
int __KernelCreateThread(const char *threadName, SceUID moduleID, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr);
|
||||
int sceKernelCreateThread(const char *threadName, u32 entry, u32 prio, int stacksize, u32 attr, u32 optionAddr);
|
||||
int sceKernelDelayThread(u32 usec);
|
||||
int sceKernelDelayThreadCB(u32 usec);
|
||||
int sceKernelDelaySysClockThread(u32 sysclockAddr);
|
||||
int sceKernelDelaySysClockThreadCB(u32 sysclockAddr);
|
||||
void __KernelStopThread(SceUID threadID, int exitStatus, const char *reason);
|
||||
u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason);
|
||||
int sceKernelDeleteThread(int threadHandle);
|
||||
void sceKernelExitDeleteThread(int exitStatus);
|
||||
void sceKernelExitThread(int exitStatus);
|
||||
void _sceKernelExitThread(int exitStatus);
|
||||
SceUID sceKernelGetThreadId();
|
||||
void sceKernelGetThreadCurrentPriority();
|
||||
int __KernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr, bool forceArgs = false);
|
||||
int sceKernelStartThread(SceUID threadToStartID, int argSize, u32 argBlockPtr);
|
||||
u32 sceKernelSuspendDispatchThread();
|
||||
u32 sceKernelResumeDispatchThread(u32 suspended);
|
||||
|
@ -197,6 +197,7 @@ EXEC_AND_LIB_FILES := \
|
||||
$(SRC)/Core/Dialog/PSPSaveDialog.cpp \
|
||||
$(SRC)/Core/Dialog/SavedataParam.cpp \
|
||||
$(SRC)/Core/Font/PGF.cpp \
|
||||
$(SRC)/Core/HLE/HLEHelperThread.cpp \
|
||||
$(SRC)/Core/HLE/HLETables.cpp \
|
||||
$(SRC)/Core/HLE/ReplaceTables.cpp \
|
||||
$(SRC)/Core/HLE/HLE.cpp \
|
||||
|
Loading…
Reference in New Issue
Block a user