mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Cleanup behavior in sceKernel*EventFlag() funcs.
Biggest change is just that sceKernelSetEventFlag() rescheds.
This commit is contained in:
parent
18bd6cdc98
commit
45258bb61f
@ -329,7 +329,7 @@ const HLEFunction ThreadManForUser[] =
|
||||
{0x402FCF22,&WrapI_IUUUU<sceKernelWaitEventFlag>, "sceKernelWaitEventFlag"},
|
||||
{0x328C546A,&WrapI_IUUUU<sceKernelWaitEventFlagCB>, "sceKernelWaitEventFlagCB"},
|
||||
{0x30FD48F0,&WrapI_IUUUU<sceKernelPollEventFlag>, "sceKernelPollEventFlag"},
|
||||
{0xCD203292,&WrapU_V<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"},
|
||||
{0xCD203292,&WrapU_IUU<sceKernelCancelEventFlag>, "sceKernelCancelEventFlag"},
|
||||
{0xA66B0120,&WrapU_IU<sceKernelReferEventFlagStatus>, "sceKernelReferEventFlagStatus"},
|
||||
|
||||
{0x8FFDF9A2,&WrapI_IIU<sceKernelCancelSema>, "sceKernelCancelSema"},
|
||||
|
@ -97,6 +97,54 @@ void __KernelEventFlagInit()
|
||||
eventFlagInitComplete = true;
|
||||
}
|
||||
|
||||
void __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;
|
||||
|
||||
// If result is an error code, we're just letting it go.
|
||||
if (result == 0)
|
||||
{
|
||||
if ((th.wait & PSP_EVENT_WAITCLEAR) != 0)
|
||||
e->nef.currentPattern &= ~th.bits;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool __KernelClearEventFlagThreads(EventFlag *e, int reason)
|
||||
{
|
||||
u32 error;
|
||||
bool wokeThreads = false;
|
||||
std::vector<EventFlagTh>::iterator iter, end;
|
||||
for (iter = e->waitingThreads.begin(), end = e->waitingThreads.end(); iter != end; ++iter)
|
||||
__KernelUnlockEventFlagForThread(e, *iter, error, reason, wokeThreads);
|
||||
e->waitingThreads.clear();
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
//SceUID sceKernelCreateEventFlag(const char *name, int attr, int bits, SceKernelEventFlagOptParam *opt);
|
||||
int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPattern, u32 optPtr)
|
||||
{
|
||||
@ -137,13 +185,36 @@ int sceKernelCreateEventFlag(const char *name, u32 flag_attr, u32 flag_initPatte
|
||||
return id;
|
||||
}
|
||||
|
||||
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE, "sceKernelCancelEventFlag(%i, %08X, %08X)", uid, pattern, numWaitThreadsPtr);
|
||||
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
|
||||
if (e)
|
||||
{
|
||||
if (Memory::IsValidAddress(numWaitThreadsPtr))
|
||||
Memory::Write_U32(e->nef.numWaitThreads, numWaitThreadsPtr);
|
||||
|
||||
e->nef.currentPattern = pattern;
|
||||
e->nef.numWaitThreads = 0;
|
||||
|
||||
if (__KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_CANCEL))
|
||||
hleReSchedule("event flag canceled");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return error;
|
||||
}
|
||||
|
||||
u32 sceKernelClearEventFlag(SceUID id, u32 bits)
|
||||
{
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
if (e)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelClearEventFlag(%i, %08x)", id, bits);
|
||||
DEBUG_LOG(HLE, "sceKernelClearEventFlag(%i, %08x)", id, bits);
|
||||
e->nef.currentPattern &= bits;
|
||||
// Note that it's not possible for threads to get woken up by this action.
|
||||
return 0;
|
||||
@ -157,23 +228,13 @@ u32 sceKernelClearEventFlag(SceUID id, u32 bits)
|
||||
|
||||
u32 sceKernelDeleteEventFlag(SceUID uid)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelDeleteEventFlag(%i)", uid);
|
||||
DEBUG_LOG(HLE, "sceKernelDeleteEventFlag(%i)", uid);
|
||||
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
|
||||
if (e)
|
||||
{
|
||||
bool wokeThreads = false;
|
||||
std::vector<EventFlagTh>::iterator iter, end;
|
||||
for (iter = e->waitingThreads.begin(), end = e->waitingThreads.end(); iter != end; ++iter)
|
||||
{
|
||||
// TODO: timeoutPtr, outPtr? Check still waiting.
|
||||
__KernelResumeThreadFromWait(iter->tid, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
wokeThreads = true;
|
||||
}
|
||||
|
||||
e->waitingThreads.clear();
|
||||
|
||||
bool wokeThreads = __KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("event flag deleted");
|
||||
|
||||
@ -183,7 +244,7 @@ u32 sceKernelDeleteEventFlag(SceUID uid)
|
||||
return error;
|
||||
}
|
||||
|
||||
u8 __KernelEventFlagMatches(u32 *pattern, u32 bits, u8 wait, u32 outAddr)
|
||||
bool __KernelEventFlagMatches(u32 *pattern, u32 bits, u8 wait, u32 outAddr)
|
||||
{
|
||||
if ((wait & PSP_EVENT_WAITOR)
|
||||
? (bits & *pattern) /* one or more bits of the mask */
|
||||
@ -194,15 +255,15 @@ u8 __KernelEventFlagMatches(u32 *pattern, u32 bits, u8 wait, u32 outAddr)
|
||||
|
||||
if (wait & PSP_EVENT_WAITCLEAR)
|
||||
*pattern &= ~bits;
|
||||
return 1;
|
||||
return true;
|
||||
}
|
||||
return 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet)
|
||||
{
|
||||
u32 error;
|
||||
DEBUG_LOG(HLE,"sceKernelSetEventFlag(%i, %08x)", id, bitsToSet);
|
||||
DEBUG_LOG(HLE, "sceKernelSetEventFlag(%i, %08x)", id, bitsToSet);
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
if (e)
|
||||
{
|
||||
@ -210,19 +271,21 @@ u32 sceKernelSetEventFlag(SceUID id, u32 bitsToSet)
|
||||
|
||||
e->nef.currentPattern |= bitsToSet;
|
||||
|
||||
retry:
|
||||
for (size_t i = 0; i < e->waitingThreads.size(); i++)
|
||||
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))
|
||||
{
|
||||
__KernelResumeThreadFromWait(t->tid);
|
||||
wokeThreads = true;
|
||||
e->nef.numWaitThreads--;
|
||||
__KernelUnlockEventFlagForThread(e, *t, error, 0, wokeThreads);
|
||||
e->waitingThreads.erase(e->waitingThreads.begin() + i);
|
||||
goto retry;
|
||||
// Try the one that used to be in this place next.
|
||||
--i;
|
||||
}
|
||||
}
|
||||
|
||||
if (wokeThreads)
|
||||
hleReSchedule("event flag set");
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
@ -249,16 +312,16 @@ void __KernelEventFlagTimeout(u64 userdata, int cycleslate)
|
||||
EventFlagTh *t = &e->waitingThreads[i];
|
||||
if (t->tid == threadID)
|
||||
{
|
||||
if (Memory::IsValidAddress(t->outAddr))
|
||||
Memory::Write_U32(e->nef.currentPattern, t->outAddr);
|
||||
e->nef.numWaitThreads--;
|
||||
bool wokeThreads;
|
||||
|
||||
// This thread isn't waiting anymore, but we'll remove it from waitingThreads later.
|
||||
__KernelUnlockEventFlagForThread(e, *t, error, SCE_KERNEL_ERROR_WAIT_TIMEOUT, wokeThreads);
|
||||
e->waitingThreads.erase(e->waitingThreads.begin() + i);
|
||||
e->nef.numWaitThreads--;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
|
||||
}
|
||||
|
||||
void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr)
|
||||
@ -298,7 +361,7 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
|
||||
EventFlagTh th;
|
||||
if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr))
|
||||
{
|
||||
u32 timeout;
|
||||
u32 timeout = 0xFFFFFFFF;
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
timeout = Memory::Read_U32(timeoutPtr);
|
||||
|
||||
@ -329,7 +392,7 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
|
||||
|
||||
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);
|
||||
DEBUG_LOG(HLE, "sceKernelWaitEventFlagCB(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
|
||||
|
||||
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
|
||||
{
|
||||
@ -347,7 +410,7 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
|
||||
EventFlagTh th;
|
||||
if (!__KernelEventFlagMatches(&e->nef.currentPattern, bits, wait, outBitsPtr))
|
||||
{
|
||||
u32 timeout;
|
||||
u32 timeout = 0xFFFFFFFF;
|
||||
if (Memory::IsValidAddress(timeoutPtr))
|
||||
timeout = Memory::Read_U32(timeoutPtr);
|
||||
|
||||
@ -380,7 +443,16 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
|
||||
|
||||
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
|
||||
DEBUG_LOG(HLE, "sceKernelPollEventFlag(%i, %08x, %i, %08x, %08x)", id, bits, wait, outBitsPtr, timeoutPtr);
|
||||
|
||||
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
|
||||
{
|
||||
WARN_LOG(HLE, "sceKernelWaitEventFlag(%i) invalid mode parameter: %08x", id, wait);
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_MODE;
|
||||
}
|
||||
// Can't wait on 0, it never matches.
|
||||
if (bits == 0)
|
||||
return SCE_KERNEL_ERROR_EVF_ILPAT;
|
||||
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
@ -390,6 +462,10 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
|
||||
{
|
||||
if (Memory::IsValidAddress(outBitsPtr))
|
||||
Memory::Write_U32(e->nef.currentPattern, outBitsPtr);
|
||||
|
||||
if (e->nef.numWaitThreads > 0 && (e->nef.attr & PSP_EVENT_WAITMULTIPLE) == 0)
|
||||
return SCE_KERNEL_ERROR_EVF_MULTI;
|
||||
|
||||
// No match - return that, this is polling, not waiting.
|
||||
return SCE_KERNEL_ERROR_EVF_COND;
|
||||
}
|
||||
@ -407,7 +483,7 @@ int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
|
||||
//int sceKernelReferEventFlagStatus(SceUID event, SceKernelEventFlagInfo *status);
|
||||
u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr)
|
||||
{
|
||||
DEBUG_LOG(HLE,"sceKernelReferEventFlagStatus(%i, %08x)", id, statusPtr);
|
||||
DEBUG_LOG(HLE, "sceKernelReferEventFlagStatus(%i, %08x)", id, statusPtr);
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(id, error);
|
||||
if (e)
|
||||
@ -420,10 +496,3 @@ u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr)
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
// never seen this one
|
||||
u32 sceKernelCancelEventFlag()
|
||||
{
|
||||
ERROR_LOG(HLE,"UNIMPL: sceKernelCancelEventFlag()");
|
||||
return 0;
|
||||
}
|
||||
|
@ -25,4 +25,4 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
|
||||
int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
|
||||
int sceKernelPollEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr);
|
||||
u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr);
|
||||
u32 sceKernelCancelEventFlag();
|
||||
u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr);
|
||||
|
@ -149,7 +149,7 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
|
||||
if (newCount > s->ns.maxCount)
|
||||
return SCE_KERNEL_ERROR_ILLEGAL_COUNT;
|
||||
|
||||
if (numWaitThreadsPtr)
|
||||
if (Memory::IsValidAddress(numWaitThreadsPtr))
|
||||
Memory::Write_U32(s->ns.numWaitThreads, numWaitThreadsPtr);
|
||||
|
||||
if (newCount < 0)
|
||||
|
2
test.py
2
test.py
@ -57,6 +57,7 @@ tests_good = [
|
||||
"misc/testgp",
|
||||
"string/string",
|
||||
"gpu/callbacks/ge_callbacks",
|
||||
"threads/events/events",
|
||||
"threads/lwmutex/create/create",
|
||||
"threads/lwmutex/delete/delete",
|
||||
"threads/lwmutex/lock/lock",
|
||||
@ -114,7 +115,6 @@ tests_next = [
|
||||
"video/pmf_simple/pmf_simple",
|
||||
|
||||
# Currently hang or crash.
|
||||
"threads/events/events",
|
||||
"audio/atrac/atractest",
|
||||
]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user