Merge pull request #3700 from unknownbrackets/callbacks

Improve callbacks (still not rescheduling properly inside one)
This commit is contained in:
Henrik Rydgård committed 2013-09-09 00:30:14 -07:00
commit 628f77e2b0
13 files changed
+171 -301

No files matched your search

+33 -1
View File
@@ -259,7 +259,17 @@ WaitBeginEndCallbackResult WaitEndCallback(SceUID threadID, SceUID prevCallbackI
}
// Verify that a thread has not been released from waiting, e.g. by sceKernelReleaseWaitThread().
inline bool VerifyWait(SceUID threadID, WaitType waitType, SceUID uid) {
// For a waiting thread info struct.
template <typename T>
inline bool VerifyWait(const T &waitInfo, WaitType waitType, SceUID uid) {
u32 error;
SceUID waitID = __KernelGetWaitID(waitInfo.threadID, waitType, error);
return waitID == uid && error == 0;
}
// Verify that a thread has not been released from waiting, e.g. by sceKernelReleaseWaitThread().
template <>
inline bool VerifyWait(const SceUID &threadID, WaitType waitType, SceUID uid) {
u32 error;
SceUID waitID = __KernelGetWaitID(threadID, waitType, error);
return waitID == uid && error == 0;
@@ -275,4 +285,26 @@ inline bool ResumeFromWait(SceUID threadID, WaitType waitType, SceUID uid, T res
return false;
}
// Removes threads that are not waiting anymore from a waitingThreads list.
template <typename T>
inline void CleanupWaitingThreads(WaitType waitType, SceUID uid, std::vector<T> &waitingThreads) {
size_t size = waitingThreads.size();
for (size_t i = 0; i < size; ++i) {
if (!VerifyWait(waitingThreads[i], waitType, uid)) {
// Decrement size and swap what was there with i.
if (--size != i) {
std::swap(waitingThreads[i], waitingThreads[size]);
}
// Now we haven't checked the new i, so go back and do i again.
--i;
}
}
waitingThreads.resize(size);
}
template <typename T>
inline void RemoveWaitingThread(std::vector<T> &waitingThreads, const SceUID threadID) {
waitingThreads.erase(std::remove(waitingThreads.begin(), waitingThreads.end(), threadID), waitingThreads.end());
}
};
+23 -7
View File
@@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include <cstdlib>
#include <set>
#include "native/thread/thread.h"
#include "native/thread/threadutil.h"
#include "Core/Config.h"
@@ -108,6 +109,8 @@ const int PSP_MIN_FD = 4;
static int asyncNotifyEvent = -1;
static int syncNotifyEvent = -1;
static SceUID fds[PSP_COUNT_FDS];
static std::set<SceUID> memStickCallbacks;
static std::set<SceUID> memStickFatCallbacks;
static AsyncIOManager ioManager;
static bool ioManagerThreadEnabled = false;
static std::thread *ioManagerThread;
@@ -466,6 +469,8 @@ void __IoDoState(PointerWrap &p) {
CoreTiming::RestoreRegisterEvent(asyncNotifyEvent, "IoAsyncNotify", __IoAsyncNotify);
p.Do(syncNotifyEvent);
CoreTiming::RestoreRegisterEvent(syncNotifyEvent, "IoSyncNotify", __IoSyncNotify);
p.Do(memStickCallbacks);
p.Do(memStickFatCallbacks);
p.DoMarker("sceIo");
}
@@ -487,6 +492,9 @@ void __IoShutdown() {
memstickSystem = NULL;
delete flash0System;
flash0System = NULL;
memStickCallbacks.clear();
memStickFatCallbacks.clear();
}
u32 __IoGetFileHandleFromId(u32 id, u32 &outError)
@@ -552,7 +560,7 @@ void __IoCompleteAsyncIO(int fd) {
// It's okay, not all operations are deferred.
}
if (f->callbackID) {
__KernelNotifyCallback(THREAD_CALLBACK_IO, f->callbackID, f->callbackArg);
__KernelNotifyCallback(f->callbackID, f->callbackArg);
}
f->pendingAsyncResult = false;
f->hasAsyncResult = true;
@@ -1262,10 +1270,12 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr,
case 0x02015804:
// Register MemoryStick's insert/eject callback (mscmhc0)
if (Memory::IsValidAddress(argAddr) && argLen == 4) {
// TODO: Verify how duplicates work / how many are allowed.
u32 cbId = Memory::Read_U32(argAddr);
if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) {
if (memStickCallbacks.find(cbId) == memStickCallbacks.end()) {
memStickCallbacks.insert(cbId);
DEBUG_LOG(SCEIO, "sceIoDevCtl: Memstick callback %i registered, notifying immediately.", cbId);
__KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK, cbId, MemoryStick_State());
__KernelNotifyCallback(cbId, MemoryStick_State());
return 0;
} else {
return ERROR_MEMSTICK_DEVCTL_TOO_MANY_CALLBACKS;
@@ -1277,8 +1287,10 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr,
case 0x02025805:
// Unregister MemoryStick's insert/eject callback (mscmhc0)
if (Memory::IsValidAddress(argAddr) && argLen == 4) {
// TODO: Verify how duplicates work / how many are allowed.
u32 cbId = Memory::Read_U32(argAddr);
if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK, cbId)) {
if (memStickCallbacks.find(cbId) != memStickCallbacks.end()) {
memStickCallbacks.erase(cbId);
DEBUG_LOG(SCEIO, "sceIoDevCtl: Unregistered memstick callback %i", cbId);
return 0;
} else {
@@ -1337,10 +1349,12 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr,
switch (cmd) {
case 0x02415821: // MScmRegisterMSInsertEjectCallback
{
// TODO: Verify how duplicates work / how many are allowed.
u32 cbId = Memory::Read_U32(argAddr);
if (0 == __KernelRegisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) {
if (memStickFatCallbacks.find(cbId) == memStickFatCallbacks.end()) {
memStickFatCallbacks.insert(cbId);
DEBUG_LOG(SCEIO, "sceIoDevCtl: Memstick FAT callback %i registered, notifying immediately.", cbId);
__KernelNotifyCallbackType(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId, MemoryStick_FatState());
__KernelNotifyCallback(cbId, MemoryStick_FatState());
return 0;
} else {
return -1;
@@ -1350,8 +1364,10 @@ u32 sceIoDevctl(const char *name, int cmd, u32 argAddr, int argLen, u32 outPtr,
case 0x02415822:
{
// MScmUnregisterMSInsertEjectCallback
// TODO: Verify how duplicates work / how many are allowed.
u32 cbId = Memory::Read_U32(argAddr);
if (0 == __KernelUnregisterCallback(THREAD_CALLBACK_MEMORYSTICK_FAT, cbId)) {
if (memStickFatCallbacks.find(cbId) != memStickFatCallbacks.end()) {
memStickFatCallbacks.erase(cbId);
DEBUG_LOG(SCEIO, "sceIoDevCtl: Unregistered memstick FAT callback %i", cbId);
return 0;
} else {
+3 -4
View File
@@ -86,6 +86,7 @@
static bool kernelRunning = false;
KernelObjectPool kernelObjects;
KernelStats kernelStats;
// TODO: Savestate this?
u32 registeredExitCbId;
void __KernelInit()
@@ -261,10 +262,8 @@ int LoadExecForUser_362A956B()
u32 sceKernelRegisterExitCallback(u32 cbId)
{
DEBUG_LOG(SCEKERNEL, "sceKernelRegisterExitCallback(%i)", cbId);
if (__KernelRegisterCallback(THREAD_CALLBACK_EXIT, cbId) == 0) {
registeredExitCbId = cbId;
}
DEBUG_LOG(SCEKERNEL,"sceKernelRegisterExitCallback(%i)", cbId);
registeredExitCbId = cbId;
return 0;
}
+8 -21
View File
@@ -47,6 +47,11 @@ struct EventFlagTh
u32 wait;
u32 outAddr;
u64 pausedTimeout;
bool operator ==(const SceUID &otherThreadID) const
{
return threadID == otherThreadID;
}
};
class EventFlag : public KernelObject
@@ -397,19 +402,6 @@ void __KernelSetEventFlagTimeout(EventFlag *e, u32 timeoutPtr)
CoreTiming::ScheduleEvent(usToCycles(micro), eventFlagWaitTimer, __KernelGetCurThread());
}
void __KernelEventFlagRemoveThread(EventFlag *e, SceUID threadID)
{
for (size_t i = 0; i < e->waitingThreads.size(); i++)
{
EventFlagTh *t = &e->waitingThreads[i];
if (t->threadID == threadID)
{
e->waitingThreads.erase(e->waitingThreads.begin() + i);
break;
}
}
}
int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 timeoutPtr)
{
if ((wait & ~PSP_EVENT_WAITKNOWN) != 0)
@@ -439,7 +431,7 @@ int sceKernelWaitEventFlag(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32 ti
{
// 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());
HLEKernel::RemoveWaitingThread(e->waitingThreads, __KernelGetCurThread());
u32 timeout = 0xFFFFFFFF;
if (Memory::IsValidAddress(timeoutPtr))
@@ -514,7 +506,7 @@ int sceKernelWaitEventFlagCB(SceUID id, u32 bits, u32 wait, u32 outBitsPtr, u32
{
// 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());
HLEKernel::RemoveWaitingThread(e->waitingThreads, __KernelGetCurThread());
u32 timeout = 0xFFFFFFFF;
if (Memory::IsValidAddress(timeoutPtr))
@@ -622,12 +614,7 @@ u32 sceKernelReferEventFlagStatus(SceUID id, u32 statusPtr)
if (!Memory::IsValidAddress(statusPtr))
return -1;
for (auto iter = e->waitingThreads.begin(); iter != e->waitingThreads.end(); ++iter)
{
// The thread is no longer waiting for this, clean it up.
if (!HLEKernel::VerifyWait(iter->threadID, WAITTYPE_EVENTFLAG, id))
e->waitingThreads.erase(iter--);
}
HLEKernel::CleanupWaitingThreads(WAITTYPE_EVENTFLAG, id, e->waitingThreads);
e->nef.numWaitThreads = (int) e->waitingThreads.size();
if (Memory::Read_U32(statusPtr) != 0)
+8 -21
View File
@@ -37,6 +37,11 @@ struct MbxWaitingThread
SceUID threadID;
u32 packetAddr;
u64 pausedTimeout;
bool operator ==(const SceUID &otherThreadID) const
{
return threadID == otherThreadID;
}
};
void __KernelMbxTimeout(u64 userdata, int cyclesLate);
@@ -274,19 +279,6 @@ void __KernelWaitMbx(Mbx *m, u32 timeoutPtr)
CoreTiming::ScheduleEvent(usToCycles(micro), mbxWaitTimer, __KernelGetCurThread());
}
void __KernelMbxRemoveThread(Mbx *m, SceUID threadID)
{
for (size_t i = 0; i < m->waitingThreads.size(); i++)
{
MbxWaitingThread *t = &m->waitingThreads[i];
if (t->threadID == threadID)
{
m->waitingThreads.erase(m->waitingThreads.begin() + i);
break;
}
}
}
std::vector<MbxWaitingThread>::iterator __KernelMbxFindPriority(std::vector<MbxWaitingThread> &waiting)
{
_dbg_assert_msg_(SCEKERNEL, !waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads.");
@@ -480,7 +472,7 @@ int sceKernelReceiveMbx(SceUID id, u32 packetAddrPtr, u32 timeoutPtr)
else
{
DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbx(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr);
__KernelMbxRemoveThread(m, __KernelGetCurThread());
HLEKernel::RemoveWaitingThread(m->waitingThreads, __KernelGetCurThread());
m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr);
__KernelWaitMbx(m, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, false, "mbx waited");
@@ -508,7 +500,7 @@ int sceKernelReceiveMbxCB(SceUID id, u32 packetAddrPtr, u32 timeoutPtr)
else
{
DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB(%i, %08x, %08x): no message in queue, waiting", id, packetAddrPtr, timeoutPtr);
__KernelMbxRemoveThread(m, __KernelGetCurThread());
HLEKernel::RemoveWaitingThread(m->waitingThreads, __KernelGetCurThread());
m->AddWaitingThread(__KernelGetCurThread(), packetAddrPtr);
__KernelWaitMbx(m, timeoutPtr);
__KernelWaitCurThread(WAITTYPE_MBX, id, 0, timeoutPtr, true, "mbx waited");
@@ -583,12 +575,7 @@ int sceKernelReferMbxStatus(SceUID id, u32 infoAddr)
for (int i = 0, n = m->nmb.numMessages; i < n; ++i)
m->nmb.packetListHead = Memory::Read_U32(m->nmb.packetListHead);
for (auto iter = m->waitingThreads.begin(); iter != m->waitingThreads.end(); ++iter)
{
// The thread is no longer waiting for this, clean it up.
if (!HLEKernel::VerifyWait(iter->threadID, WAITTYPE_MBX, id))
m->waitingThreads.erase(iter--);
}
HLEKernel::CleanupWaitingThreads(WAITTYPE_MBX, id, m->waitingThreads);
// For whatever reason, it won't write if the size (first member) is 0.
if (Memory::Read_U32(infoAddr) != 0)
+16 -46
View File
@@ -57,6 +57,11 @@ struct FplWaitingThread
SceUID threadID;
u32 addrPtr;
u64 pausedTimeout;
bool operator ==(const SceUID &otherThreadID) const
{
return threadID == otherThreadID;
}
};
struct NativeFPL
@@ -141,6 +146,11 @@ struct VplWaitingThread
SceUID threadID;
u32 addrPtr;
u64 pausedTimeout;
bool operator ==(const SceUID &otherThreadID) const
{
return threadID == otherThreadID;
}
};
struct SceKernelVplInfo
@@ -292,19 +302,6 @@ void __KernelFplEndCallback(SceUID threadID, SceUID prevCallbackId)
DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB: Resuming mbx wait from callback");
}
void __KernelFplRemoveThread(FPL *fpl, SceUID threadID)
{
for (size_t i = 0; i < fpl->waitingThreads.size(); i++)
{
FplWaitingThread *t = &fpl->waitingThreads[i];
if (t->threadID == threadID)
{
fpl->waitingThreads.erase(fpl->waitingThreads.begin() + i);
break;
}
}
}
bool __FplThreadSortPriority(FplWaitingThread thread1, FplWaitingThread thread2)
{
return __KernelThreadSortPriority(thread1.threadID, thread2.threadID);
@@ -325,14 +322,7 @@ void __KernelSortFplThreads(FPL *fpl)
{
// Remove any that are no longer waiting.
SceUID uid = fpl->GetUID();
for (size_t i = 0; i < fpl->waitingThreads.size(); i++)
{
if (!HLEKernel::VerifyWait(fpl->waitingThreads[i].threadID, WAITTYPE_FPL, uid))
{
fpl->waitingThreads.erase(fpl->waitingThreads.begin() + i);
--i;
}
}
HLEKernel::CleanupWaitingThreads(WAITTYPE_FPL, uid, fpl->waitingThreads);
if ((fpl->nf.attr & PSP_FPL_ATTR_PRIORITY) != 0)
std::stable_sort(fpl->waitingThreads.begin(), fpl->waitingThreads.end(), __FplThreadSortPriority);
@@ -489,7 +479,7 @@ int sceKernelAllocateFpl(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr)
Memory::Write_U32(blockPtr, blockPtrAddr);
} else {
SceUID threadID = __KernelGetCurThread();
__KernelFplRemoveThread(fpl, threadID);
HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID);
FplWaitingThread waiting = {threadID, blockPtrAddr};
fpl->waitingThreads.push_back(waiting);
@@ -520,7 +510,7 @@ int sceKernelAllocateFplCB(SceUID uid, u32 blockPtrAddr, u32 timeoutPtr)
Memory::Write_U32(blockPtr, blockPtrAddr);
} else {
SceUID threadID = __KernelGetCurThread();
__KernelFplRemoveThread(fpl, threadID);
HLEKernel::RemoveWaitingThread(fpl->waitingThreads, threadID);
FplWaitingThread waiting = {threadID, blockPtrAddr};
fpl->waitingThreads.push_back(waiting);
@@ -1179,19 +1169,6 @@ void __KernelVplEndCallback(SceUID threadID, SceUID prevCallbackId)
DEBUG_LOG(SCEKERNEL, "sceKernelReceiveMbxCB: Resuming mbx wait from callback");
}
void __KernelVplRemoveThread(VPL *vpl, SceUID threadID)
{
for (size_t i = 0; i < vpl->waitingThreads.size(); i++)
{
VplWaitingThread *t = &vpl->waitingThreads[i];
if (t->threadID == threadID)
{
vpl->waitingThreads.erase(vpl->waitingThreads.begin() + i);
break;
}
}
}
bool __VplThreadSortPriority(VplWaitingThread thread1, VplWaitingThread thread2)
{
return __KernelThreadSortPriority(thread1.threadID, thread2.threadID);
@@ -1212,14 +1189,7 @@ void __KernelSortFplThreads(VPL *vpl)
{
// Remove any that are no longer waiting.
SceUID uid = vpl->GetUID();
for (size_t i = 0; i < vpl->waitingThreads.size(); i++)
{
if (!HLEKernel::VerifyWait(vpl->waitingThreads[i].threadID, WAITTYPE_VPL, uid))
{
vpl->waitingThreads.erase(vpl->waitingThreads.begin() + i);
--i;
}
}
HLEKernel::CleanupWaitingThreads(WAITTYPE_VPL, uid, vpl->waitingThreads);
if ((vpl->nv.attr & PSP_VPL_ATTR_PRIORITY) != 0)
std::stable_sort(vpl->waitingThreads.begin(), vpl->waitingThreads.end(), __VplThreadSortPriority);
@@ -1391,7 +1361,7 @@ int sceKernelAllocateVpl(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
if (vpl)
{
SceUID threadID = __KernelGetCurThread();
__KernelVplRemoveThread(vpl, threadID);
HLEKernel::RemoveWaitingThread(vpl->waitingThreads, threadID);
VplWaitingThread waiting = {threadID, addrPtr};
vpl->waitingThreads.push_back(waiting);
}
@@ -1416,7 +1386,7 @@ int sceKernelAllocateVplCB(SceUID uid, u32 size, u32 addrPtr, u32 timeoutPtr)
if (vpl)
{
SceUID threadID = __KernelGetCurThread();
__KernelVplRemoveThread(vpl, threadID);
HLEKernel::RemoveWaitingThread(vpl->waitingThreads, threadID);
VplWaitingThread waiting = {threadID, addrPtr};
vpl->waitingThreads.push_back(waiting);
}
+3 -19
View File
@@ -241,18 +241,7 @@ struct MsgPipe : public KernelObject
void SortThreads(std::vector<MsgPipeWaitingThread> &waitingThreads, bool usePrio)
{
// Clean up any not waiting at the same time.
size_t size = waitingThreads.size();
for (size_t i = 0; i < size; ++i)
{
if (!waitingThreads[i].IsStillWaiting(GetUID()))
{
// Decrement size and swap what was there with i.
std::swap(waitingThreads[i], waitingThreads[--size]);
// Now we haven't checked the new i, so go back and do i again.
--i;
}
}
waitingThreads.resize(size);
HLEKernel::CleanupWaitingThreads(WAITTYPE_MSGPIPE, GetUID(), waitingThreads);
if (usePrio)
std::stable_sort(waitingThreads.begin(), waitingThreads.end(), __KernelMsgPipeThreadSortPriority);
@@ -270,19 +259,14 @@ struct MsgPipe : public KernelObject
SortThreads(sendWaitingThreads, usePrio);
}
void RemoveWaitingThread(std::vector<MsgPipeWaitingThread> &waitingThreads, SceUID threadID)
{
waitingThreads.erase(std::remove(waitingThreads.begin(), waitingThreads.end(), threadID), waitingThreads.end());
}
void RemoveReceiveWaitingThread(SceUID threadID)
{
RemoveWaitingThread(receiveWaitingThreads, threadID);
HLEKernel::RemoveWaitingThread(receiveWaitingThreads, threadID);
}
void RemoveSendWaitingThread(SceUID threadID)
{
RemoveWaitingThread(sendWaitingThreads, threadID);
HLEKernel::RemoveWaitingThread(sendWaitingThreads, threadID);
}
virtual void DoState(PointerWrap &p)
+4 -19
View File
@@ -461,7 +461,7 @@ void __KernelMutexThreadEnd(SceUID threadID)
{
Mutex *mutex = kernelObjects.Get<Mutex>(waitingMutexID, error);
if (mutex)
mutex->waitingThreads.erase(std::remove(mutex->waitingThreads.begin(), mutex->waitingThreads.end(), threadID), mutex->waitingThreads.end());
HLEKernel::RemoveWaitingThread(mutex->waitingThreads, threadID);
}
// Unlock all mutexes the thread had locked.
@@ -517,12 +517,7 @@ int sceKernelCancelMutex(SceUID uid, int count, u32 numWaitThreadsPtr)
DEBUG_LOG(SCEKERNEL, "sceKernelCancelMutex(%i, %d, %08x)", uid, count, numWaitThreadsPtr);
// Remove threads no longer waiting on this first (so the numWaitThreads value is correct.)
for (auto iter = mutex->waitingThreads.begin(); iter != mutex->waitingThreads.end(); ++iter)
{
// The thread is no longer waiting for this, clean it up.
if (!HLEKernel::VerifyWait(*iter, WAITTYPE_MUTEX, uid))
mutex->waitingThreads.erase(iter--);
}
HLEKernel::CleanupWaitingThreads(WAITTYPE_MUTEX, uid, mutex->waitingThreads);
if (Memory::IsValidAddress(numWaitThreadsPtr))
Memory::Write_U32((u32)mutex->waitingThreads.size(), numWaitThreadsPtr);
@@ -682,12 +677,7 @@ int sceKernelReferMutexStatus(SceUID id, u32 infoAddr)
// Don't write if the size is 0. Anything else is A-OK, though, apparently.
if (Memory::Read_U32(infoAddr) != 0)
{
for (auto iter = m->waitingThreads.begin(); iter != m->waitingThreads.end(); ++iter)
{
// The thread is no longer waiting for this, clean it up.
if (!HLEKernel::VerifyWait(*iter, WAITTYPE_MUTEX, id))
m->waitingThreads.erase(iter--);
}
HLEKernel::CleanupWaitingThreads(WAITTYPE_MUTEX, id, m->waitingThreads);
m->nm.numWaitThreads = (int) m->waitingThreads.size();
Memory::WriteStruct(infoAddr, &m->nm);
@@ -1065,12 +1055,7 @@ int __KernelReferLwMutexStatus(SceUID uid, u32 infoPtr)
{
auto workarea = m->nm.workarea;
for (auto iter = m->waitingThreads.begin(); iter != m->waitingThreads.end(); ++iter)
{
// The thread is no longer waiting for this, clean it up.
if (!HLEKernel::VerifyWait(*iter, WAITTYPE_LWMUTEX, uid))
m->waitingThreads.erase(iter--);
}
HLEKernel::CleanupWaitingThreads(WAITTYPE_LWMUTEX, uid, m->waitingThreads);
// Refresh and write
m->nm.currentCount = workarea->lockLevel;
+1 -6
View File
@@ -266,12 +266,7 @@ int sceKernelReferSemaStatus(SceUID id, u32 infoPtr)
if (!Memory::IsValidAddress(infoPtr))
return -1;
for (auto iter = s->waitingThreads.begin(); iter != s->waitingThreads.end(); ++iter)
{
// The thread is no longer waiting for this, clean it up.
if (!HLEKernel::VerifyWait(*iter, WAITTYPE_SEMA, id))
s->waitingThreads.erase(iter--);
}
HLEKernel::CleanupWaitingThreads(WAITTYPE_SEMA, id, s->waitingThreads);
s->ns.numWaitThreads = (int) s->waitingThreads.size();
if (Memory::Read_U32(infoPtr) != 0)
+60 -111
View File
@@ -464,6 +464,10 @@ public:
~Thread()
{
// Callbacks are automatically deleted when their owning thread is deleted.
for (auto it = callbacks.begin(), end = callbacks.end(); it != end; ++it)
kernelObjects.Destroy<Callback>(*it);
if (pushedStacks.size() != 0)
{
WARN_LOG_REPORT(SCEKERNEL, "Thread ended within an extended stack");
@@ -498,20 +502,7 @@ public:
p.Do(currentCallbackId);
p.Do(context);
u32 numCallbacks = THREAD_CALLBACK_NUM_TYPES;
p.Do(numCallbacks);
if (numCallbacks != THREAD_CALLBACK_NUM_TYPES)
{
p.SetError(p.ERROR_FAILURE);
ERROR_LOG(SCEKERNEL, "Unable to load state: different thread callback storage.");
return;
}
for (size_t i = 0; i < THREAD_CALLBACK_NUM_TYPES; ++i)
{
p.Do(registeredCallbacks[i]);
p.Do(readyCallbacks[i]);
}
p.Do(callbacks);
p.Do(pendingMipsCalls);
p.Do(pushedStacks);
@@ -531,8 +522,7 @@ public:
ThreadContext context;
std::set<SceUID> registeredCallbacks[THREAD_CALLBACK_NUM_TYPES];
std::list<SceUID> readyCallbacks[THREAD_CALLBACK_NUM_TYPES];
std::vector<SceUID> callbacks;
std::list<u32> pendingMipsCalls;
@@ -1765,9 +1755,12 @@ u32 __KernelDeleteThread(SceUID threadID, int exitStatus, const char *reason)
Thread *t = kernelObjects.Get<Thread>(threadID, error);
if (t)
{
// TODO: Unless they should be run before deletion?
for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++)
readyCallbacksCount -= (int)t->readyCallbacks[i].size();
for (auto it = t->callbacks.begin(), end = t->callbacks.end(); it != end; ++it)
{
Callback *callback = kernelObjects.Get<Callback>(*it, error);
if (callback && callback->nc.notifyCount != 0)
readyCallbacksCount--;
}
}
return kernelObjects.Destroy<Thread>(threadID);
@@ -2828,6 +2821,10 @@ SceUID sceKernelCreateCallback(const char *name, u32 entrypoint, u32 signalArg)
cb->nc.notifyCount = 0;
cb->nc.notifyArg = 0;
Thread *thread = __GetCurrentThread();
if (thread)
thread->callbacks.push_back(id);
DEBUG_LOG(SCEKERNEL, "%i=sceKernelCreateCallback(name=%s, entry=%08x, callbackArg=%08x)", id, name, entrypoint, signalArg);
return id;
@@ -2837,9 +2834,19 @@ int sceKernelDeleteCallback(SceUID cbId)
{
DEBUG_LOG(SCEKERNEL, "sceKernelDeleteCallback(%i)", cbId);
// TODO: Make sure it's gone from all threads first!
u32 error;
Callback *cb = kernelObjects.Get<Callback>(cbId, error);
if (cb)
{
Thread *thread = kernelObjects.Get<Thread>(cb->nc.threadId, error);
if (thread)
thread->callbacks.erase(std::find(thread->callbacks.begin(), thread->callbacks.end(), cbId), thread->callbacks.end());
if (cb->nc.notifyCount != 0)
readyCallbacksCount--;
return kernelObjects.Destroy<Callback>(cbId);
return kernelObjects.Destroy<Callback>(cbId);
}
return error;
}
// Generally very rarely used, but Numblast uses it like candy.
@@ -2849,8 +2856,7 @@ int sceKernelNotifyCallback(SceUID cbId, int notifyArg)
u32 error;
Callback *cb = kernelObjects.Get<Callback>(cbId, error);
if (cb) {
// TODO: Should this notify other existing callbacks too?
__KernelNotifyCallback(THREAD_CALLBACK_USER_DEFINED, cbId, notifyArg);
__KernelNotifyCallback(cbId, notifyArg);
return 0;
} else {
ERROR_LOG(SCEKERNEL, "sceKernelCancelCallback(%i) - bad cbId", cbId);
@@ -2988,7 +2994,7 @@ void ActionAfterMipsCall::run(MipsCall &call) {
ActionAfterMipsCall *Thread::getRunningCallbackAction()
{
if (this->GetUID() == currentThread && g_inCbCount > 0) {
if (this->GetUID() == currentThread && g_inCbCount > 0) {
MipsCall *call = mipsCalls.get(this->currentMipscallId);
ActionAfterMipsCall *action = 0;
if (call)
@@ -3440,42 +3446,37 @@ void ActionAfterCallback::run(MipsCall &call) {
}
bool __KernelCurHasReadyCallbacks() {
if (readyCallbacksCount == 0)
if (readyCallbacksCount == 0) {
return false;
}
Thread *thread = __GetCurrentThread();
for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) {
if (thread->readyCallbacks[i].size()) {
u32 error;
for (auto it = thread->callbacks.begin(), end = thread->callbacks.end(); it != end; ++it) {
Callback *callback = kernelObjects.Get<Callback>(*it, error);
if (callback && callback->nc.notifyCount != 0) {
return true;
}
}
return false;
}
// Check callbacks on the current thread only.
// Returns true if any callbacks were processed on the current thread.
bool __KernelCheckThreadCallbacks(Thread *thread, bool force)
{
if (!thread || (!thread->isProcessingCallbacks && !force))
bool __KernelCheckThreadCallbacks(Thread *thread, bool force) {
if (!thread || (!thread->isProcessingCallbacks && !force)) {
return false;
}
for (int i = 0; i < THREAD_CALLBACK_NUM_TYPES; i++) {
if (thread->readyCallbacks[i].size()) {
SceUID readyCallback = thread->readyCallbacks[i].front();
thread->readyCallbacks[i].pop_front();
readyCallbacksCount--;
// If the callback was deleted, we're good. Just skip it.
if (kernelObjects.IsValid(readyCallback))
{
__KernelRunCallbackOnThread(readyCallback, thread, !force); // makes pending
if (!thread->callbacks.empty()) {
u32 error;
for (auto it = thread->callbacks.begin(), end = thread->callbacks.end(); it != end; ++it) {
Callback *callback = kernelObjects.Get<Callback>(*it, error);
if (callback && callback->nc.notifyCount != 0) {
__KernelRunCallbackOnThread(callback->GetUID(), thread, !force);
readyCallbacksCount--;
return true;
}
else
{
WARN_LOG(SCEKERNEL, "Ignoring deleted callback %08x", readyCallback);
}
}
}
return false;
@@ -3491,23 +3492,20 @@ bool __KernelCheckCallbacks() {
ERROR_LOG_REPORT(SCEKERNEL, "readyCallbacksCount became negative: %i", readyCallbacksCount);
}
// SceUID currentThread = __KernelGetCurThread();
// __GetCurrentThread()->isProcessingCallbacks = true;
// do {
bool processed = false;
bool processed = false;
u32 error;
for (std::vector<SceUID>::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) {
Thread *thread = kernelObjects.Get<Thread>(*iter, error);
if (thread && __KernelCheckThreadCallbacks(thread, false)) {
processed = true;
}
u32 error;
for (std::vector<SceUID>::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) {
Thread *thread = kernelObjects.Get<Thread>(*iter, error);
if (thread && __KernelCheckThreadCallbacks(thread, false)) {
processed = true;
}
// } while (processed && currentThread == __KernelGetCurThread());
}
if (processed)
if (processed) {
return __KernelExecutePendingMipsCalls(__GetCurrentThread(), true);
return processed;
}
return false;
}
bool __KernelForceCallbacks()
@@ -3549,30 +3547,7 @@ bool __KernelInCallback()
return (g_inCbCount != 0);
}
u32 __KernelRegisterCallback(RegisteredCallbackType type, SceUID cbId)
{
Thread *t = __GetCurrentThread();
if (cbId > 0 && t->registeredCallbacks[type].find(cbId) == t->registeredCallbacks[type].end()) {
t->registeredCallbacks[type].insert(cbId);
return 0;
} else {
return SCE_KERNEL_ERROR_INVAL;
}
}
u32 __KernelUnregisterCallback(RegisteredCallbackType type, SceUID cbId)
{
Thread *t = __GetCurrentThread();
if (t->registeredCallbacks[type].find(cbId) != t->registeredCallbacks[type].end()) {
t->registeredCallbacks[type].erase(cbId);
return 0;
} else {
return 0x80010016;
}
}
void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notifyArg)
void __KernelNotifyCallback(SceUID cbId, int notifyArg)
{
u32 error;
@@ -3582,37 +3557,11 @@ void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notify
ERROR_LOG(SCEKERNEL, "__KernelNotifyCallback - invalid callback %08x", cbId);
return;
}
cb->nc.notifyCount++;
cb->nc.notifyArg = notifyArg;
Thread *t = kernelObjects.Get<Thread>(cb->nc.threadId, error);
std::list<SceUID> &readyCallbacks = t->readyCallbacks[type];
auto iter = std::find(readyCallbacks.begin(), readyCallbacks.end(), cbId);
if (iter == readyCallbacks.end())
{
t->readyCallbacks[type].push_back(cbId);
if (cb->nc.notifyCount == 0) {
readyCallbacksCount++;
}
}
// TODO: If cbId == -1, notify the callback ID on all threads that have it.
u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int notifyArg)
{
u32 error;
for (std::vector<SceUID>::iterator iter = threadqueue.begin(); iter != threadqueue.end(); iter++) {
Thread *t = kernelObjects.Get<Thread>(*iter, error);
if (!t)
continue;
for (std::set<SceUID>::iterator citer = t->registeredCallbacks[type].begin(); citer != t->registeredCallbacks[type].end(); citer++) {
if (cbId == -1 || cbId == *citer) {
__KernelNotifyCallback(type, *citer, notifyArg);
}
}
}
// checkCallbacks on other threads?
return 0;
cb->nc.notifyCount++;
cb->nc.notifyArg = notifyArg;
}
void __KernelRegisterWaitTypeFuncs(WaitType type, WaitBeginCallbackFunc beginFunc, WaitEndCallbackFunc endFunc)
+1 -22
View File
@@ -173,27 +173,6 @@ void __KernelWaitCallbacksCurThread(WaitType type, SceUID waitID, u32 waitValue,
void __KernelReSchedule(const char *reason = "no reason");
void __KernelReSchedule(bool doCallbacks, const char *reason);
// Registered callback types
enum RegisteredCallbackType {
THREAD_CALLBACK_UMD = 0,
THREAD_CALLBACK_IO = 1,
THREAD_CALLBACK_MEMORYSTICK = 2,
THREAD_CALLBACK_MEMORYSTICK_FAT = 3,
THREAD_CALLBACK_POWER = 4,
THREAD_CALLBACK_EXIT = 5,
THREAD_CALLBACK_USER_DEFINED = 6,
THREAD_CALLBACK_SIZE = 7,
THREAD_CALLBACK_NUM_TYPES = 8,
};
// These operate on the current thread
u32 __KernelRegisterCallback(RegisteredCallbackType type, SceUID cbId);
u32 __KernelUnregisterCallback(RegisteredCallbackType type, SceUID cbId);
// If cbId == -1, all the callbacks of the type on all the threads get notified.
// If not, only this particular callback gets notified.
u32 __KernelNotifyCallbackType(RegisteredCallbackType type, SceUID cbId, int notifyArg);
SceUID __KernelGetCurThread();
SceUID __KernelGetCurThreadModuleId();
SceUID __KernelSetupRootThread(SceUID moduleId, int args, const char *argp, int prio, int stacksize, int attr); //represents the real PSP elf loader, run before execution
@@ -232,7 +211,7 @@ bool __KernelCurHasReadyCallbacks();
class Thread;
void __KernelSwitchContext(Thread *target, const char *reason);
bool __KernelExecutePendingMipsCalls(Thread *currentThread, bool reschedAfter);
void __KernelNotifyCallback(RegisteredCallbackType type, SceUID cbId, int notifyArg);
void __KernelNotifyCallback(SceUID cbId, int notifyArg);
// Switch to an idle / non-user thread, if not already on one.
// Returns whether a switch occurred.
+1 -4
View File
@@ -154,10 +154,8 @@ int scePowerRegisterCallback(int slot, int cbId) {
}
}
if (retval >= 0) {
__KernelRegisterCallback(THREAD_CALLBACK_POWER, cbId);
int arg = PSP_POWER_CB_AC_POWER | PSP_POWER_CB_BATTERY_EXIST | PSP_POWER_CB_BATTERY_FULL;
__KernelNotifyCallbackType(THREAD_CALLBACK_POWER, cbId, arg);
__KernelNotifyCallback(cbId, arg);
}
return retval;
}
@@ -175,7 +173,6 @@ int scePowerUnregisterCallback(int slotId) {
if (powerCbSlots[slotId] != 0) {
int cbId = powerCbSlots[slotId];
DEBUG_LOG(HLE, "0=scePowerUnregisterCallback(%i) (cbid = %i)", slotId, cbId);
__KernelUnregisterCallback(THREAD_CALLBACK_POWER, cbId);
powerCbSlots[slotId] = 0;
} else {
return PSP_POWER_ERROR_EMPTY_SLOT;
+10 -20
View File
@@ -114,7 +114,8 @@ void __UmdStatChange(u64 userdata, int cyclesLate)
void __KernelUmdActivate()
{
u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READABLE;
__KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg);
if (driveCBId != -1)
__KernelNotifyCallback(driveCBId, notifyArg);
// Don't activate immediately, take time to "spin up."
CoreTiming::RemoveAllEvents(umdStatChangeEvent);
@@ -124,7 +125,8 @@ void __KernelUmdActivate()
void __KernelUmdDeactivate()
{
u32 notifyArg = PSP_UMD_PRESENT | PSP_UMD_READY;
__KernelNotifyCallbackType(THREAD_CALLBACK_UMD, -1, notifyArg);
if (driveCBId != -1)
__KernelNotifyCallback(driveCBId, notifyArg);
CoreTiming::RemoveAllEvents(umdStatChangeEvent);
__UmdStatChange(0, 0);
@@ -148,11 +150,7 @@ void __UmdBeginCallback(SceUID threadID, SceUID prevCallbackId)
else
umdPausedWaits[pauseKey] = 0;
for (auto it = umdWaitingThreads.begin(); it < umdWaitingThreads.end(); ++it)
{
if (*it == threadID)
umdWaitingThreads.erase(it--);
}
HLEKernel::RemoveWaitingThread(umdWaitingThreads, threadID);
DEBUG_LOG(SCEIO, "sceUmdWaitDriveStatCB: Suspending lock wait for callback");
}
@@ -256,17 +254,13 @@ int sceUmdDeactivate(u32 mode, const char *name)
u32 sceUmdRegisterUMDCallBack(u32 cbId)
{
int retVal;
int retVal = 0;
// TODO: If the callback is invalid, return PSP_ERROR_UMD_INVALID_PARAM.
if (cbId == 0)
if (!kernelObjects.IsValid(cbId)) {
retVal = PSP_ERROR_UMD_INVALID_PARAM;
else {
// Remove the old one, we're replacing.
if (driveCBId != -1)
__KernelUnregisterCallback(THREAD_CALLBACK_UMD, driveCBId);
retVal = __KernelRegisterCallback(THREAD_CALLBACK_UMD, cbId);
} else {
// There's only ever one.
driveCBId = cbId;
}
@@ -283,7 +277,6 @@ int sceUmdUnRegisterUMDCallBack(int cbId)
else {
retVal = cbId;
driveCBId = -1;
__KernelUnregisterCallback(THREAD_CALLBACK_UMD, cbId);
}
DEBUG_LOG(SCEIO, "%08x=sceUmdUnRegisterUMDCallBack(id=%08x)", retVal, cbId);
@@ -308,10 +301,7 @@ void __UmdStatTimeout(u64 userdata, int cyclesLate)
if (waitID == 1)
__KernelResumeThreadFromWait(threadID, SCE_KERNEL_ERROR_WAIT_TIMEOUT);
for (size_t i = 0; i < umdWaitingThreads.size(); ++i) {
if (umdWaitingThreads[i] == threadID)
umdWaitingThreads.erase(umdWaitingThreads.begin() + i--);
}
HLEKernel::RemoveWaitingThread(umdWaitingThreads, threadID);
}
void __UmdWaitStat(u32 timeout)