bool __KernelUnlockEventFlagForThread(EventFlag *e, EventFlagTh &th, u32 &error, int result, bool &wokeThreads) { SceUID waitID = __KernelGetWaitID(th.tid, WAITTYPE_EVENTFLAG, error); u32 timeoutPtr = __KernelGetWaitTimeoutPtr(th.tid, error); // The waitID may be different after a timeout. if (waitID != e->GetUID()) return true; // If result is an error code, we're just letting it go. if (result == 0) { if (!__KernelEventFlagMatches(&e->nef.currentPattern, th.bits, th.wait, th.outAddr)) return false; e->nef.numWaitThreads--; } else { // Otherwise, we set the current result since we're bailing. if (Memory::IsValidAddress(th.outAddr)) Memory::Write_U32(e->nef.currentPattern, th.outAddr); } if (timeoutPtr != 0 && eventFlagWaitTimer != 0) { // Remove any event for this thread. u64 cyclesLeft = CoreTiming::UnscheduleEvent(eventFlagWaitTimer, th.tid); Memory::Write_U32((u32) cyclesToUs(cyclesLeft), timeoutPtr); } __KernelResumeThreadFromWait(th.tid, result); wokeThreads = true; return true; }
//int sceKernelPollEventFlag(int evid, u32 bits, u32 wait, u32 *outBits); void sceKernelPollEventFlag() { SceUID id = PARAM(0); u32 bits = PARAM(1); u32 wait = PARAM(2); u32 outBitsPtr = PARAM(3); u32 timeoutPtr = PARAM(4); DEBUG_LOG(HLE,"sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr); u32 error; EventFlag *e = kernelObjects.Get<EventFlag>(id, error); if (e) { if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr)) { if (Memory::IsValidAddress(outBitsPtr)) Memory::Write_U32(e->nef.currentPattern, outBitsPtr); // No match - return that, this is polling, not waiting. RETURN(SCE_KERNEL_ERROR_EVF_COND); } else { RETURN(0); } } else { RETURN(error); } }
//int sceKernelSetEventFlag(SceUID evid, u32 bits); void sceKernelSetEventFlag() { SceUID id = PARAM(0); u32 bitsToSet = PARAM(1); u32 error; DEBUG_LOG(HLE,"sceKernelSetEventFlag(%i, %08x)", id, bitsToSet); EventFlag *e = kernelObjects.Get<EventFlag>(id, error); if (e) { bool wokeThreads = false; e->nef.currentPattern |= bitsToSet; retry: for (size_t i = 0; i < e->waitingThreads.size(); i++) { EventFlagTh *t = &e->waitingThreads[i]; if (__KernelEventFlagMatches(&e->nef.currentPattern, t->bits, t->wait, t->outAddr)) { __KernelResumeThread(t->tid); wokeThreads = true; e->nef.numWaitThreads--; e->waitingThreads.erase(e->waitingThreads.begin() + i); goto retry; } } RETURN(0); } else { RETURN(error); } }
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) { DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr); if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) { WARN_LOG(HLE, "sceKernelWaitEventFlagCB(%i) invalid mode parameter: %08x", id, wait); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } // Can't wait on 0, that's guaranteed to wait forever. if (bits == 0) return SCE_KERNEL_ERROR_EVF_ILPAT; u32 error; EventFlag *e = kernelObjects.Get<EventFlag>(id, error); if (e) { EventFlagTh th; if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr)) { // If this thread was left in waitingThreads after a timeout, remove it. // Otherwise we might write the outBitsPtr in the wrong place. __KernelEventFlagRemoveThread(e, __KernelGetCurThread()); u32 timeout = 0xFFFFFFFF; if (Memory::IsValidAddress(timeoutPtr)) timeout = Memory::Read_U32(timeoutPtr); // Do we allow more than one thread to wait? if (e->nef.numWaitThreads > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) return SCE_KERNEL_ERROR_EVF_MULTI; // No match - must wait. e->nef.numWaitThreads++; th.tid = __KernelGetCurThread(); th.bits = bits; th.wait = wait; // If < 5ms, sometimes hardware doesn't write this, but it's unpredictable. th.outAddr = timeout == 0 ? 0 : outBitsPtr; e->waitingThreads.push_back(th); __KernelSetEventFlagTimeout(e, timeoutPtr); __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, true); } else hleCheckCurrentCallbacks(); return 0; } else { return error; } }
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr) { if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) { WARN_LOG_REPORT(HLE, "sceKernelPollEventFlag(%i) invalid mode parameter: %08x", id, wait); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } // Poll seems to also fail when CLEAR and CLEARALL are used together, but not wait. if ((wait & PSP_EVENT_WAITCLEAR) != 0 && (wait & PSP_EVENT_WAITCLEARALL) != 0) { WARN_LOG_REPORT(HLE, "sceKernelPollEventFlag(%i) invalid mode parameter: %08x", id, wait); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } // Can't wait on 0, it never matches. if (bits == 0) { DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x): bad pattern", id, bits, wait, outBitsPtr); return SCE_KERNEL_ERROR_EVF_ILPAT; } u32 error; EventFlag *e = kernelObjects.Get<EventFlag>(id, error); if (e) { if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr)) { if (Memory::IsValidAddress(outBitsPtr)) Memory::Write_U32(e->nef.currentPattern, outBitsPtr); if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) { DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_EVF_MULTI=sceKernelPollEventFlag(%i, %08x, %i, %08x)", id, bits, wait, outBitsPtr); return SCE_KERNEL_ERROR_EVF_MULTI; } // No match - return that, this is polling, not waiting. DEBUG_LOG(HLE, "SCE_KERNEL_ERROR_EVF_COND=sceKernelPollEventFlag(%i, %08x, %i, %08x)", id, bits, wait, outBitsPtr); return SCE_KERNEL_ERROR_EVF_COND; } else { DEBUG_LOG(HLE, "0=sceKernelPollEventFlag(%i, %08x, %i, %08x)", id, bits, wait, outBitsPtr); return 0; } } else { DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x): invalid event flag", id, bits, wait, outBitsPtr); return error; } }
//int sceKernelWaitEventFlagCB(SceUID evid, u32 bits, u32 wait, u32 *outBits, SceUInt *timeout); void sceKernelWaitEventFlagCB() { SceUID id = PARAM(0); u32 bits = PARAM(1); u32 wait = PARAM(2); u32 outBitsPtr = PARAM(3); u32 timeoutPtr = PARAM(4); DEBUG_LOG(HLE,"sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr); u32 error; EventFlag *e = kernelObjects.Get<EventFlag>(id, error); if (e) { EventFlagTh th; if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr)) { // No match - must wait. e->nef.numWaitThreads++; th.tid = __KernelGetCurThread(); th.bits = bits; th.wait = wait; th.outAddr = outBitsPtr; e->waitingThreads.push_back(th); u32 timeout; if (Memory::IsValidAddress(timeoutPtr)) timeout = Memory::Read_U32(timeoutPtr); __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, 0, true); } RETURN(0); } else { RETURN(error); } }
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr) { if ((wait & ~PSP_EVENT_WAITKNOWN) != 0) { WARN_LOG_REPORT(SCEKERNEL, "sceKernelWaitEventFlagCB(%i) invalid mode parameter: %08x", id, wait); return SCE_KERNEL_ERROR_ILLEGAL_MODE; } // Can't wait on 0, that's guaranteed to wait forever. if (bits == 0) { DEBUG_LOG(SCEKERNEL, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x): bad pattern", id, bits, wait, outBitsPtr, timeoutPtr); return SCE_KERNEL_ERROR_EVF_ILPAT; } if (!__KernelIsDispatchEnabled()) { DEBUG_LOG(SCEKERNEL, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x): dispatch disabled", id, bits, wait, outBitsPtr, timeoutPtr); return SCE_KERNEL_ERROR_CAN_NOT_WAIT; } u32 error; EventFlag *e = kernelObjects.Get<EventFlag>(id, error); if (e) { EventFlagTh th; bool doWait = !__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr); bool doCallbackWait = false; if (__KernelCurHasReadyCallbacks()) { doWait = true; doCallbackWait = true; } if (doWait) { // If this thread was left in waitingThreads after a timeout, remove it. // Otherwise we might write the outBitsPtr in the wrong place. HLEKernel::RemoveWaitingThread(e->waitingThreads, __KernelGetCurThread()); u32 timeout = 0xFFFFFFFF; if (Memory::IsValidAddress(timeoutPtr)) timeout = Memory::Read_U32(timeoutPtr); // Do we allow more than one thread to wait? if (e->waitingThreads.size() > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0) { DEBUG_LOG(SCEKERNEL, "SCE_KERNEL_ERROR_EVF_MULTI=sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr); return SCE_KERNEL_ERROR_EVF_MULTI; } DEBUG_LOG(SCEKERNEL, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x): waiting", id, bits, wait, outBitsPtr, timeoutPtr); // No match - must wait. th.threadID = __KernelGetCurThread(); th.bits = bits; th.wait = wait; // If < 5ms, sometimes hardware doesn't write this, but it's unpredictable. th.outAddr = timeout == 0 ? 0 : outBitsPtr; e->waitingThreads.push_back(th); __KernelSetEventFlagTimeout(e, timeoutPtr); if (doCallbackWait) __KernelWaitCallbacksCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr); else __KernelWaitCurThread(WAITTYPE_EVENTFLAG, id, 0, timeoutPtr, true, "event flag waited"); } else { DEBUG_LOG(SCEKERNEL, "0=sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr); hleCheckCurrentCallbacks(); } return 0; } else { DEBUG_LOG(SCEKERNEL, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x): invalid event flag", id, bits, wait, outBitsPtr, timeoutPtr); return error; } }