mirror of
https://github.com/hrydgard/ppsspp.git
synced 2025-02-01 19:23:04 +00:00
Merge pull request #3606 from unknownbrackets/callbacks
Wait func docs, sceKernelCreateCallback() cleanup, small refactor
This commit is contained in:
commit
34f9947ad0
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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];
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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
|
2
test.py
2
test.py
@ -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",
|
||||
|
Loading…
x
Reference in New Issue
Block a user