Add a class to create helper threads from HLE.

This should be usable from sceIo as well.
This commit is contained in:
Unknown W. Brackets 2014-05-22 23:38:21 -07:00
parent a2031cdc62
commit b9ede6aade
9 changed files with 202 additions and 43 deletions

View File

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

View File

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

View File

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

View File

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

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

View 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_;
};

View File

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

View File

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

View File

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