From d348b9d47a059cee42355e2f1c79bbc86bc7b758 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 8 Sep 2013 14:58:43 -0700 Subject: [PATCH] Add callback handlers for msgpipes. --- Core/HLE/sceKernelMsgPipe.cpp | 129 ++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) diff --git a/Core/HLE/sceKernelMsgPipe.cpp b/Core/HLE/sceKernelMsgPipe.cpp index 70953c1e02..eec9cc7176 100644 --- a/Core/HLE/sceKernelMsgPipe.cpp +++ b/Core/HLE/sceKernelMsgPipe.cpp @@ -531,9 +531,138 @@ int __KernelReceiveMsgPipe(MsgPipe *m, u32 receiveBufAddr, u32 receiveSize, int return 0; } +void __KernelMsgPipeBeginCallback(SceUID threadID, SceUID prevCallbackId) +{ + u32 error; + u32 waitValue = __KernelGetWaitValue(threadID, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_MSGPIPE, error); + MsgPipe *ko = uid == 0 ? NULL : kernelObjects.Get(uid, error); + + switch (waitValue) + { + case MSGPIPE_WAIT_VALUE_SEND: + if (ko) + { + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, waitTimer, ko->sendWaitingThreads, ko->pausedSendWaits, timeoutPtr != 0); + if (result == HLEKernel::WAIT_CB_SUCCESS) + DEBUG_LOG(SCEKERNEL, "sceKernelSendMsgPipeCB: Suspending wait for callback") + else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) + ERROR_LOG_REPORT(SCEKERNEL, "sceKernelSendMsgPipeCB: wait not found to pause for callback") + } + else + WARN_LOG_REPORT(SCEKERNEL, "sceKernelSendMsgPipeCB: beginning callback with bad wait id?"); + break; + + case MSGPIPE_WAIT_VALUE_RECV: + if (ko) + { + auto result = HLEKernel::WaitBeginCallback(threadID, prevCallbackId, waitTimer, ko->receiveWaitingThreads, ko->pausedReceiveWaits, timeoutPtr != 0); + if (result == HLEKernel::WAIT_CB_SUCCESS) + DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMsgPipeCB: Suspending wait for callback") + else if (result == HLEKernel::WAIT_CB_BAD_WAIT_DATA) + ERROR_LOG_REPORT(SCEKERNEL, "sceKernelReceiveMsgPipeCB: wait not found to pause for callback") + } + else + WARN_LOG_REPORT(SCEKERNEL, "sceKernelReceiveMsgPipeCB: beginning callback with bad wait id?"); + break; + + default: + ERROR_LOG_REPORT(SCEKERNEL, "__KernelMsgPipeBeginCallback: Unexpected wait value"); + } +} + +bool __KernelCheckResumeMsgPipeSend(MsgPipe *m, MsgPipeWaitingThread &waitInfo, u32 &error, int result, bool &wokeThreads) +{ + if (!waitInfo.IsStillWaiting(m->GetUID())) + return true; + + bool needsResched = false; + bool needsWait = false; + + result = __KernelSendMsgPipe(m, waitInfo.bufAddr, waitInfo.bufSize, waitInfo.waitMode, waitInfo.transferredBytes.ptr, 0, true, false, needsResched, needsWait); + + if (needsResched) + hleReSchedule(true, "msgpipe data sent"); + + // Could not wake up. May have sent some stuff. + if (needsWait) + return false; + + waitInfo.Complete(m->GetUID(), result); + wokeThreads = true; + return true; +} + +bool __KernelCheckResumeMsgPipeReceive(MsgPipe *m, MsgPipeWaitingThread &waitInfo, u32 &error, int result, bool &wokeThreads) +{ + if (!waitInfo.IsStillWaiting(m->GetUID())) + return true; + + bool needsResched = false; + bool needsWait = false; + + result = __KernelReceiveMsgPipe(m, waitInfo.bufAddr, waitInfo.bufSize, waitInfo.waitMode, waitInfo.transferredBytes.ptr, 0, true, false, needsResched, needsWait); + + if (needsResched) + hleReSchedule(true, "msgpipe data received"); + + if (needsWait) + return false; + + waitInfo.Complete(m->GetUID(), result); + wokeThreads = true; + return true; +} + +void __KernelMsgPipeEndCallback(SceUID threadID, SceUID prevCallbackId) +{ + u32 error; + u32 waitValue = __KernelGetWaitValue(threadID, error); + u32 timeoutPtr = __KernelGetWaitTimeoutPtr(threadID, error); + SceUID uid = __KernelGetWaitID(threadID, WAITTYPE_MSGPIPE, error); + MsgPipe *ko = uid == 0 ? NULL : kernelObjects.Get(uid, error); + + switch (waitValue) + { + case MSGPIPE_WAIT_VALUE_SEND: + { + MsgPipeWaitingThread dummy; + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, waitTimer, __KernelCheckResumeMsgPipeSend, dummy, ko->sendWaitingThreads, ko->pausedSendWaits); + if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) + DEBUG_LOG(SCEKERNEL, "sceKernelSendMsgPipeCB: Resuming wait from callback") + else if (result == HLEKernel::WAIT_CB_TIMED_OUT) + { + // It was re-added to the the waiting threads list, but it timed out. Let's remove it. + ko->RemoveSendWaitingThread(threadID); + } + } + break; + + case MSGPIPE_WAIT_VALUE_RECV: + { + MsgPipeWaitingThread dummy; + auto result = HLEKernel::WaitEndCallback(threadID, prevCallbackId, waitTimer, __KernelCheckResumeMsgPipeReceive, dummy, ko->receiveWaitingThreads, ko->pausedReceiveWaits); + if (result == HLEKernel::WAIT_CB_RESUMED_WAIT) + DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMsgPipeCB: Resuming wait from callback") + else if (result == HLEKernel::WAIT_CB_TIMED_OUT) + { + // It was re-added to the the waiting threads list, but it timed out. Let's remove it. + ko->RemoveReceiveWaitingThread(threadID); + } + } + break; + + default: + ERROR_LOG_REPORT(SCEKERNEL, "__KernelMsgPipeEndCallback: Unexpected wait value"); + } +} + void __KernelMsgPipeInit() { waitTimer = CoreTiming::RegisterEvent("MsgPipeTimeout", __KernelMsgPipeTimeout); + + __KernelRegisterWaitTypeFuncs(WAITTYPE_MSGPIPE, __KernelMsgPipeBeginCallback, __KernelMsgPipeEndCallback); } void __KernelMsgPipeDoState(PointerWrap &p)