Merge pull request #3606 from unknownbrackets/callbacks

Wait func docs, sceKernelCreateCallback() cleanup, small refactor
This commit is contained in:
Henrik Rydgård 2013-09-04 01:55:28 -07:00
commit 34f9947ad0
11 changed files with 175 additions and 115 deletions

View File

@ -25,6 +25,29 @@
namespace HLEKernel
{
// Should be called from the CoreTiming handler for the wait func.
template <typename KO, WaitType waitType>
inline void WaitExecTimeout(SceUID threadID) {
u32 error;
SceUID uid = __KernelGetWaitID(threadID, waitType, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
KO *ko = uid == 0 ? NULL : kernelObjects.Get<KO>(uid, error);
if (ko)
{
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
}
// Move a thead from the waiting thread list to the paused thread list.
// This version is for vectors which contain structs, which must have SceUID threadID and u64 pausedTimeout.
// Should not be called directly.
template <typename WaitInfoType, typename PauseType>
inline bool WaitPauseHelperUpdate(SceUID pauseKey, SceUID threadID, std::vector<WaitInfoType> &waitingThreads, std::map<SceUID, PauseType> &pausedWaits, u64 pauseTimeout) {
WaitInfoType waitData = {0};
@ -47,6 +70,9 @@ inline bool WaitPauseHelperUpdate(SceUID pauseKey, SceUID threadID, std::vector<
return true;
}
// Move a thread from the waiting thread list to the paused thread list.
// This version is for a simpler list of SceUIDs. The paused list is a std::map<SceUID, u64>.
// Should not be called directly.
template <>
inline bool WaitPauseHelperUpdate<SceUID, u64>(SceUID pauseKey, SceUID threadID, std::vector<SceUID> &waitingThreads, std::map<SceUID, u64> &pausedWaits, u64 pauseTimeout) {
// TODO: Hmm, what about priority/fifo order? Does it lose its place in line?
@ -55,6 +81,9 @@ inline bool WaitPauseHelperUpdate<SceUID, u64>(SceUID pauseKey, SceUID threadID,
return true;
}
// Retrieve the paused wait info from the list, and pop it.
// Returns the pausedTimeout value.
// Should not be called directly.
template <typename WaitInfoType, typename PauseType>
inline u64 WaitPauseHelperGet(SceUID pauseKey, SceUID threadID, std::map<SceUID, PauseType> &pausedWaits, WaitInfoType &waitData) {
waitData = pausedWaits[pauseKey];
@ -63,6 +92,9 @@ inline u64 WaitPauseHelperGet(SceUID pauseKey, SceUID threadID, std::map<SceUID,
return waitDeadline;
}
// Retrieve the paused wait info from the list, and pop it.
// This version is for a simple std::map paused list.
// Should not be called directly.
template <>
inline u64 WaitPauseHelperGet<SceUID, u64>(SceUID pauseKey, SceUID threadID, std::map<SceUID, u64> &pausedWaits, SceUID &waitData) {
waitData = threadID;
@ -72,17 +104,31 @@ inline u64 WaitPauseHelperGet<SceUID, u64>(SceUID pauseKey, SceUID threadID, std
}
enum WaitBeginEndCallbackResult {
// Returned when the thread cannot be found in the waiting threads list.
// Only returned for struct types, which have other data than the threadID.
WAIT_CB_BAD_WAIT_DATA = -2,
// Returned when the wait ID of the thread no longer matches the kernel object.
WAIT_CB_BAD_WAIT_ID = -1,
// Success, whether that means the wait was paused, deleted, etc.
WAIT_CB_SUCCESS = 0,
// Success, and resumed waiting. Useful for logging.
WAIT_CB_RESUMED_WAIT = 1,
};
// Meant to be called in a registered begin callback function for a wait type.
//
// The goal of this function is to pause the wait. While inside a callback, waits are released.
// Once the callback returns, the wait should be resumed (see WaitEndCallback.)
//
// This assumes the object has been validated already. The primary purpose is if you need
// to use a specific pausedWaits list (for example, sceMsgPipe has two types of waiting per object.)
//
// In most cases, use the other, simpler version of WaitBeginCallback().
template <typename WaitInfoType, typename PauseType>
WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbackId, int waitTimer, std::vector<WaitInfoType> &waitingThreads, std::map<SceUID, PauseType> &pausedWaits, bool doTimeout = true) {
SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId;
// This means two callbacks in a row. PSP crashes if the same callback runs inside itself.
// This means two callbacks in a row. PSP crashes if the same callback waits inside itself (may need more testing.)
// TODO: Handle this better?
if (pausedWaits.find(pauseKey) != pausedWaits.end()) {
return WAIT_CB_SUCCESS;
@ -101,6 +147,12 @@ WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbac
return WAIT_CB_SUCCESS;
}
// Meant to be called in a registered begin callback function for a wait type.
//
// The goal of this function is to pause the wait. While inside a callback, waits are released.
// Once the callback returns, the wait should be resumed (see WaitEndCallback.)
//
// In the majority of cases, calling this function is sufficient for the BeginCallback handler.
template <typename KO, WaitType waitType, typename WaitInfoType>
WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbackId, int waitTimer) {
u32 error;
@ -114,6 +166,15 @@ WaitBeginEndCallbackResult WaitBeginCallback(SceUID threadID, SceUID prevCallbac
}
}
// Meant to be called in a registered end callback function for a wait type.
//
// The goal of this function is to resume the wait, or to complete it if a wait is no longer needed.
//
// This version allows you to specify the pausedWaits and waitingThreads vectors, primarily for
// MsgPipes which have two waiting thread lists. Unlike the matching WaitBeginCallback() function,
// this still validates the wait (since it needs other data from the object.)
//
// In most cases, use the other, simpler version of WaitEndCallback().
template <typename KO, WaitType waitType, typename WaitInfoType, typename PauseType, class TryUnlockFunc>
WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackId, int waitTimer, TryUnlockFunc TryUnlock, std::vector<WaitInfoType> &waitingThreads, std::map<SceUID, PauseType> &pausedWaits) {
SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId;
@ -165,12 +226,19 @@ WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackI
}
}
// Meant to be called in a registered end callback function for a wait type.
//
// The goal of this function is to resume the wait, or to complete it if a wait is no longer needed.
//
// The TryUnlockFunc signature should be (choosen due to similarity to existing funcitons):
// bool TryUnlock(KO *ko, WaitInfoType waitingThreadInfo, u32 &error, int result, bool &wokeThreads)
template <typename KO, WaitType waitType, typename WaitInfoType, class TryUnlockFunc>
WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackId, int waitTimer, TryUnlockFunc TryUnlock) {
u32 error;
SceUID uid = __KernelGetWaitID(threadID, waitType, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
KO *ko = uid == 0 ? NULL : kernelObjects.Get<KO>(uid, error);
// We need the ko for the vectors, but to avoid a null check we validate it here too.
if (!ko) {
// TODO: Since it was deleted, we don't know how long was actually left.
// For now, we just say the full time was taken.

View File

@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <vector>
#include <map>
#include <cmath>
// TODO: Move the relevant parts into common. Don't want the core
@ -50,7 +51,8 @@ struct WaitVBlankInfo
WaitVBlankInfo(u32 tid) : threadID(tid), vcountUnblock(1) {}
WaitVBlankInfo(u32 tid, int vcount) : threadID(tid), vcountUnblock(vcount) {}
u32 threadID;
int vcountUnblock; // what was this for again?
// Number of vcounts to block for.
int vcountUnblock;
void DoState(PointerWrap &p)
{
@ -90,6 +92,9 @@ const float hCountPerVblank = 285.72f; // insprired by jpcsp
std::vector<WaitVBlankInfo> vblankWaitingThreads;
// Key is the callback id it was for, or if no callback, the thread id.
// Value is the goal vcount number (in case the callback takes >= 1 vcount to return.)
std::map<SceUID, int> vblankPausedWaits;
// STATE END
@ -124,6 +129,9 @@ void hleEnterVblank(u64 userdata, int cyclesLate);
void hleLeaveVblank(u64 userdata, int cyclesLate);
void hleAfterFlip(u64 userdata, int cyclesLate);
void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId);
void __DisplayVblankEndCallback(SceUID threadID, SceUID prevCallbackId);
void __DisplayInit() {
gpuStats.Reset();
hasSetMode = false;
@ -162,6 +170,8 @@ void __DisplayInit() {
fpsHistoryValid = 0;
InitGfxState();
__KernelRegisterWaitTypeFuncs(WAITTYPE_VBLANK, __DisplayVblankBeginCallback, __DisplayVblankEndCallback);
}
void __DisplayDoState(PointerWrap &p) {
@ -180,6 +190,7 @@ void __DisplayDoState(PointerWrap &p) {
p.Do(height);
WaitVBlankInfo wvi(0);
p.Do(vblankWaitingThreads, wvi);
p.Do(vblankPausedWaits);
p.Do(enterVblankEvent);
CoreTiming::RestoreRegisterEvent(enterVblankEvent, "EnterVBlank", &hleEnterVblank);
@ -222,6 +233,56 @@ void __DisplayFireVblank() {
}
}
void __DisplayVblankBeginCallback(SceUID threadID, SceUID prevCallbackId) {
SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId;
// This means two callbacks in a row. PSP crashes if the same callback waits inside itself (may need more testing.)
// TODO: Handle this better?
if (vblankPausedWaits.find(pauseKey) != vblankPausedWaits.end()) {
return;
}
WaitVBlankInfo waitData(0);
for (size_t i = 0; i < vblankWaitingThreads.size(); i++) {
WaitVBlankInfo *t = &vblankWaitingThreads[i];
if (t->threadID == threadID)
{
waitData = *t;
vblankWaitingThreads.erase(vblankWaitingThreads.begin() + i);
break;
}
}
if (waitData.threadID != threadID)
{
WARN_LOG_REPORT(HLE, "sceDisplayWaitVblankCB: could not find waiting thread info.");
return;
}
vblankPausedWaits[pauseKey] = vCount + waitData.vcountUnblock;
DEBUG_LOG(HLE, "sceDisplayWaitVblankCB: Suspending vblank wait for callback")
}
void __DisplayVblankEndCallback(SceUID threadID, SceUID prevCallbackId) {
SceUID pauseKey = prevCallbackId == 0 ? threadID : prevCallbackId;
// Probably should not be possible.
if (vblankPausedWaits.find(pauseKey) == vblankPausedWaits.end()) {
__KernelResumeThreadFromWait(threadID, 0);
return;
}
int vcountUnblock = vblankPausedWaits[pauseKey];
if (vcountUnblock <= vCount) {
__KernelResumeThreadFromWait(threadID, 0);
return;
}
// Still have to wait a bit longer.
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vcountUnblock - vCount));
DEBUG_LOG(HLE, "sceDisplayWaitVblankCB: Resuming vblank wait from callback")
}
// TODO: Also average actualFps
void __DisplayGetFPS(float *out_vps, float *out_fps, float *out_actual_fps) {
*out_vps = fps;
@ -424,9 +485,14 @@ void hleEnterVblank(u64 userdata, int cyclesLate) {
__DisplayFireVblank();
// Wake up threads waiting for VBlank
u32 error;
for (size_t i = 0; i < vblankWaitingThreads.size(); i++) {
if (--vblankWaitingThreads[i].vcountUnblock == 0) {
__KernelResumeThreadFromWait(vblankWaitingThreads[i].threadID, 0);
// Only wake it if it wasn't already released by someone else.
SceUID waitID = __KernelGetWaitID(vblankWaitingThreads[i].threadID, WAITTYPE_VBLANK, error);
if (waitID == 1) {
__KernelResumeThreadFromWait(vblankWaitingThreads[i].threadID, 0);
}
vblankWaitingThreads.erase(vblankWaitingThreads.begin() + i--);
}
}
@ -611,7 +677,7 @@ u32 sceDisplayGetFramebuf(u32 topaddrPtr, u32 linesizePtr, u32 pixelFormatPtr, i
u32 sceDisplayWaitVblankStart() {
VERBOSE_LOG(HLE,"sceDisplayWaitVblankStart()");
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread()));
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false, "vblank start waited");
__KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, false, "vblank start waited");
return 0;
}
@ -619,7 +685,7 @@ u32 sceDisplayWaitVblank() {
if (!isVblank) {
VERBOSE_LOG(HLE,"sceDisplayWaitVblank()");
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread()));
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false, "vblank waited");
__KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, false, "vblank waited");
return 0;
} else {
DEBUG_LOG(HLE,"sceDisplayWaitVblank() - not waiting since in vBlank");
@ -639,7 +705,7 @@ u32 sceDisplayWaitVblankStartMulti(int vblanks) {
if (__IsInInterrupt())
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vblanks));
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, false, "vblank start multi waited");
__KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, false, "vblank start multi waited");
return 0;
}
@ -647,7 +713,7 @@ u32 sceDisplayWaitVblankCB() {
if (!isVblank) {
VERBOSE_LOG(HLE,"sceDisplayWaitVblankCB()");
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread()));
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true, "vblank waited");
__KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, true, "vblank waited");
return 0;
} else {
DEBUG_LOG(HLE,"sceDisplayWaitVblank() - not waiting since in vBlank");
@ -659,7 +725,7 @@ u32 sceDisplayWaitVblankCB() {
u32 sceDisplayWaitVblankStartCB() {
VERBOSE_LOG(HLE,"sceDisplayWaitVblankStartCB()");
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread()));
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true, "vblank start waited");
__KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, true, "vblank start waited");
return 0;
}
@ -674,7 +740,7 @@ u32 sceDisplayWaitVblankStartMultiCB(int vblanks) {
if (__IsInInterrupt())
return SCE_KERNEL_ERROR_ILLEGAL_CONTEXT;
vblankWaitingThreads.push_back(WaitVBlankInfo(__KernelGetCurThread(), vblanks));
__KernelWaitCurThread(WAITTYPE_VBLANK, 0, 0, 0, true, "vblank start multi waited");
__KernelWaitCurThread(WAITTYPE_VBLANK, 1, 0, 0, true, "vblank start multi waited");
return 0;
}

View File

@ -355,15 +355,16 @@ void __KernelEventFlagTimeout(u64 userdata, int cycleslate)
{
SceUID threadID = (SceUID)userdata;
// This still needs to set the result pointer from the wait.
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID flagID = __KernelGetWaitID(threadID, WAITTYPE_EVENTFLAG, error);
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
EventFlag *e = kernelObjects.Get<EventFlag>(flagID, error);
if (e)
{
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
for (size_t i = 0; i < e->waitingThreads.size(); i++)
{
EventFlagTh *t = &e->waitingThreads[i];

View File

@ -257,24 +257,7 @@ void __KernelMbxEndCallback(SceUID threadID, SceUID prevCallbackId)
void __KernelMbxTimeout(u64 userdata, int cyclesLate)
{
SceUID threadID = (SceUID)userdata;
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID mbxID = __KernelGetWaitID(threadID, WAITTYPE_MBX, error);
Mbx *m = kernelObjects.Get<Mbx>(mbxID, error);
if (m)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
// TODO: Should numWaitThreads be decreased yet?
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
HLEKernel::WaitExecTimeout<Mbx, WAITTYPE_MBX>(threadID);
}
void __KernelWaitMbx(Mbx *m, u32 timeoutPtr)

View File

@ -457,22 +457,7 @@ int sceKernelDeleteFpl(SceUID uid)
void __KernelFplTimeout(u64 userdata, int cyclesLate)
{
SceUID threadID = (SceUID) userdata;
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_FPL, error);
FPL *fpl = kernelObjects.Get<FPL>(uid, error);
if (fpl)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but while it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
HLEKernel::WaitExecTimeout<FPL, WAITTYPE_FPL>(threadID);
}
void __KernelSetFplTimeout(u32 timeoutPtr)
@ -1383,22 +1368,7 @@ bool __KernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 &error, const ch
void __KernelVplTimeout(u64 userdata, int cyclesLate)
{
SceUID threadID = (SceUID) userdata;
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_VPL, error);
VPL *vpl = kernelObjects.Get<VPL>(uid, error);
if (vpl)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but while it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
HLEKernel::WaitExecTimeout<VPL, WAITTYPE_VPL>(threadID);
}
void __KernelSetVplTimeout(u32 timeoutPtr)

View File

@ -25,6 +25,7 @@
#include "Core/HLE/sceKernelMemory.h"
#include "Core/HLE/sceKernelInterrupt.h"
#include "Core/HLE/sceKernelThread.h"
#include "Core/HLE/KernelWaitHelpers.h"
#include "Common/ChunkFile.h"
#define SCE_KERNEL_MPA_THFIFO_S 0x0000
@ -297,23 +298,8 @@ KernelObject *__KernelMsgPipeObject()
void __KernelMsgPipeTimeout(u64 userdata, int cyclesLate)
{
SceUID threadID = (SceUID) (userdata & 0xFFFFFFFF);
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_MSGPIPE, error);
MsgPipe *m = kernelObjects.Get<MsgPipe>(uid, error);
if (m)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but whhile it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
SceUID threadID = (SceUID) userdata;
HLEKernel::WaitExecTimeout<MsgPipe, WAITTYPE_MSGPIPE>(threadID);
}
bool __KernelSetMsgPipeTimeout(u32 timeoutPtr)

View File

@ -334,22 +334,7 @@ retry:
void __KernelSemaTimeout(u64 userdata, int cycleslate)
{
SceUID threadID = (SceUID)userdata;
u32 error;
u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error);
if (timeoutPtr != 0)
Memory::Write_U32(0, timeoutPtr);
SceUID semaID = __KernelGetWaitID(threadID, WAITTYPE_SEMA, error);
Semaphore *s = kernelObjects.Get<Semaphore>(semaID, error);
if (s)
{
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
// The reason is, if it times out, but what it was waiting on is DELETED prior to it
// actually running, it will get a DELETE result instead of a TIMEOUT.
// So, we need to remember it or we won't be able to mark it DELETE instead later.
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
}
HLEKernel::WaitExecTimeout<Semaphore, WAITTYPE_SEMA>(threadID);
}
void __KernelSetSemaTimeout(Semaphore *s, u32 timeoutPtr)

View File

@ -2816,28 +2816,31 @@ int sceKernelResumeThread(SceUID threadID)
// CALLBACKS
//////////////////////////////////////////////////////////////////////////
// Internal API
u32 __KernelCreateCallback(const char *name, u32 entrypoint, u32 commonArg)
SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg)
{
if (!name)
{
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateCallback(): invalid name", SCE_KERNEL_ERROR_ERROR);
return SCE_KERNEL_ERROR_ERROR;
}
if (entrypoint & 0xF0000000)
{
WARN_LOG_REPORT(HLE, "%08x=sceKernelCreateCallback(): invalid func %08x", SCE_KERNEL_ERROR_ILLEGAL_ADDR, entrypoint);
return SCE_KERNEL_ERROR_ILLEGAL_ADDR;
}
Callback *cb = new Callback;
SceUID id = kernelObjects.Create(cb);
strncpy(cb->nc.name, name, KERNELOBJECT_MAX_NAME_LENGTH);
cb->nc.name[KERNELOBJECT_MAX_NAME_LENGTH] = 0;
cb->nc.size = sizeof(NativeCallback);
strncpy(cb->nc.name, name, 32);
cb->nc.entrypoint = entrypoint;
cb->nc.threadId = __KernelGetCurThread();
cb->nc.commonArgument = commonArg;
cb->nc.commonArgument = signalArg;
cb->nc.notifyCount = 0;
cb->nc.notifyArg = 0;
return id;
}
SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg)
{
SceUID id = __KernelCreateCallback(name, entrypoint, signalArg);
DEBUG_LOG(HLE, "%i=sceKernelCreateCallback(name=%s, entry=%08x, callbackArg=%08x)", id, name, entrypoint, signalArg);
return id;
@ -2901,10 +2904,9 @@ int sceKernelReferCallbackStatus(SceUID cbId, u32 statusAddr)
Callback *c = kernelObjects.Get<Callback>(cbId, error);
if (c) {
DEBUG_LOG(HLE, "sceKernelReferCallbackStatus(%i, %08x)", cbId, statusAddr);
// TODO: Maybe check size parameter?
if (Memory::IsValidAddress(statusAddr)) {
if (Memory::IsValidAddress(statusAddr) && Memory::Read_U32(statusAddr) != 0) {
Memory::WriteStruct(statusAddr, &c->nc);
} // else TODO
}
return 0;
} else {
ERROR_LOG(HLE, "sceKernelReferCallbackStatus(%i, %08x) - bad cbId", cbId, statusAddr);

View File

@ -214,9 +214,6 @@ void __KernelIdle();
u32 __KernelMipsCallReturnAddress();
u32 __KernelInterruptReturnAddress(); // TODO: remove
// Internal access - used by sceSetGeCallback
u32 __KernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg);
SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg);
int sceKernelDeleteCallback(SceUID cbId);
int sceKernelNotifyCallback(SceUID cbId, int notifyArg);

@ -1 +1 @@
Subproject commit 7c6ba3fdf78c0b3315e1166cd4770ddebeb947b1
Subproject commit 596de8a28c62421f8dc511ebbfeb84e1786681f1

View File

@ -78,6 +78,7 @@ tests_good = [
"display/display",
"display/vblankmulti",
"dmac/dmactest",
"hash/hash",
"hle/check_not_used_uids",
"intr/intr",
"intr/vblank/vblank",
@ -190,6 +191,7 @@ tests_next = [
"audio/sceaudio/datalen",
"audio/sceaudio/output",
"audio/sceaudio/reserve",
"display/hcount",
"threads/scheduling/dispatch",
"threads/scheduling/scheduling",
"threads/threads/change",