mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-01 14:58:14 +00:00
Kernel waits: Share waiter ordering and clearing between objects
Priority-ordered waiting lists were sorted with a comparator wrapper per object (msgpipe, fpl, vpl), or searched with a copy of the same function (mutex, mbx). HLEKernel::SortWaitingThreadsByPriority() and FindBestPriorityWaiter() now do both for any waiting list, of thread ids or of structs with a threadID. HLEKernel::ClearWaitingThreads() replaces the identical cancel/delete loops in semaphores, event flags, fpl and vpl. Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
This commit is contained in:
1 parent
cc5ee42dda
commit
80938529a9
7 files changed
+64
-112
No files matched your search
@@ -345,6 +345,54 @@ inline void CleanupWaitingThreads(WaitType waitType, SceUID uid, std::vector<T>
|
||||
waitingThreads.resize(size);
|
||||
}
|
||||
|
||||
// Ends every wait on an object with the given result (for cancel and delete), through the object's
|
||||
// function for releasing one waiter:
|
||||
// bool Unlock(KO *ko, WaitInfoType &waitingThreadInfo, u32 &error, int result, bool &wokeThreads)
|
||||
template <typename KO, class UnlockFunc>
|
||||
inline bool ClearWaitingThreads(KO *ko, int result, UnlockFunc Unlock) {
|
||||
u32 error;
|
||||
bool wokeThreads = false;
|
||||
for (auto &waiting : ko->waitingThreads) {
|
||||
Unlock(ko, waiting, error, result, wokeThreads);
|
||||
}
|
||||
ko->waitingThreads.clear();
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
// A waiting list holds either thread ids or structs with a threadID.
|
||||
inline SceUID WaitingThreadID(const SceUID &threadID) {
|
||||
return threadID;
|
||||
}
|
||||
template <typename T>
|
||||
inline SceUID WaitingThreadID(const T &waitInfo) {
|
||||
return waitInfo.threadID;
|
||||
}
|
||||
|
||||
// For objects created with the priority attribute: best priority first, and among equals the order
|
||||
// they started waiting in.
|
||||
template <typename T>
|
||||
inline void SortWaitingThreadsByPriority(std::vector<T> &waitingThreads) {
|
||||
std::stable_sort(waitingThreads.begin(), waitingThreads.end(), [](const T &a, const T &b) {
|
||||
return __KernelThreadSortPriority(WaitingThreadID(a), WaitingThreadID(b));
|
||||
});
|
||||
}
|
||||
|
||||
// The first waiter with the best priority, without reordering the list.
|
||||
template <typename T>
|
||||
inline typename std::vector<T>::iterator FindBestPriorityWaiter(std::vector<T> &waitingThreads) {
|
||||
_dbg_assert_msg_(!waitingThreads.empty(), "FindBestPriorityWaiter: no threads");
|
||||
auto best = waitingThreads.end();
|
||||
u32 bestPriority = 0xFFFFFFFF;
|
||||
for (auto iter = waitingThreads.begin(); iter != waitingThreads.end(); ++iter) {
|
||||
const u32 priority = __KernelGetThreadPrio(WaitingThreadID(*iter));
|
||||
if (priority < bestPriority) {
|
||||
best = iter;
|
||||
bestPriority = priority;
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void RemoveWaitingThread(std::vector<T> &waitingThreads, const SceUID threadID) {
|
||||
waitingThreads.erase(std::remove(waitingThreads.begin(), waitingThreads.end(), threadID), waitingThreads.end());
|
||||
|
||||
@@ -135,16 +135,6 @@ static bool __KernelUnlockEventFlagForThread(EventFlag *e, EventFlagTh &th, u32
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool __KernelClearEventFlagThreads(EventFlag *e, int reason) {
|
||||
u32 error;
|
||||
bool wokeThreads = false;
|
||||
for (auto &event : e->waitingThreads)
|
||||
__KernelUnlockEventFlagForThread(e, event, error, reason, wokeThreads);
|
||||
e->waitingThreads.clear();
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
void __KernelEventFlagBeginCallback(SceUID threadID, SceUID prevCallbackId) {
|
||||
auto result = HLEKernel::WaitBeginCallback<EventFlag, WAITTYPE_EVENTFLAG, EventFlagTh>(threadID, prevCallbackId);
|
||||
if (result == HLEKernel::WAIT_CB_SUCCESS)
|
||||
@@ -206,7 +196,7 @@ u32 sceKernelCancelEventFlag(SceUID uid, u32 pattern, u32 numWaitThreadsPtr) {
|
||||
|
||||
e->nef.currentPattern = pattern;
|
||||
|
||||
if (__KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_CANCEL))
|
||||
if (HLEKernel::ClearWaitingThreads(e, SCE_KERNEL_ERROR_WAIT_CANCEL, __KernelUnlockEventFlagForThread))
|
||||
hleReSchedule("event flag canceled");
|
||||
|
||||
hleEatCycles(580);
|
||||
@@ -233,7 +223,7 @@ u32 sceKernelDeleteEventFlag(SceUID uid) {
|
||||
u32 error;
|
||||
EventFlag *e = kernelObjects.Get<EventFlag>(uid, error);
|
||||
if (e) {
|
||||
bool wokeThreads = __KernelClearEventFlagThreads(e, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
bool wokeThreads = HLEKernel::ClearWaitingThreads(e, SCE_KERNEL_ERROR_WAIT_DELETE, __KernelUnlockEventFlagForThread);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("event flag deleted");
|
||||
|
||||
|
||||
@@ -249,24 +249,6 @@ void __KernelMbxTimeout(u64 userdata, int cyclesLate)
|
||||
HLEKernel::WaitExecTimeout<Mbx, WAITTYPE_MBX>(threadID);
|
||||
}
|
||||
|
||||
static std::vector<MbxWaitingThread>::iterator __KernelMbxFindPriority(std::vector<MbxWaitingThread> &waiting)
|
||||
{
|
||||
_dbg_assert_msg_(!waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads.");
|
||||
|
||||
std::vector<MbxWaitingThread>::iterator iter, end, best = waiting.end();
|
||||
u32 best_prio = 0xFFFFFFFF;
|
||||
for (iter = waiting.begin(), end = waiting.end(); iter != end; ++iter) {
|
||||
u32 iter_prio = __KernelGetThreadPrio(iter->threadID);
|
||||
if (iter_prio < best_prio) {
|
||||
best = iter;
|
||||
best_prio = iter_prio;
|
||||
}
|
||||
}
|
||||
|
||||
_dbg_assert_msg_(best != waiting.end(), "__KernelMutexFindPriority: Returning invalid best thread.");
|
||||
return best;
|
||||
}
|
||||
|
||||
SceUID sceKernelCreateMbx(const char *name, u32 attr, u32 optAddr)
|
||||
{
|
||||
if (!name)
|
||||
@@ -353,7 +335,7 @@ int sceKernelSendMbx(SceUID id, u32 packetAddr)
|
||||
while (!wokeThreads && !m->waitingThreads.empty())
|
||||
{
|
||||
if ((m->nmb.attr & SCE_KERNEL_MBA_THPRI) != 0)
|
||||
iter = __KernelMbxFindPriority(m->waitingThreads);
|
||||
iter = HLEKernel::FindBestPriorityWaiter(m->waitingThreads);
|
||||
else
|
||||
iter = m->waitingThreads.begin();
|
||||
|
||||
|
||||
@@ -509,22 +509,6 @@ void __KernelFplEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelAllocateFplCB: Resuming mbx wait from callback");
|
||||
}
|
||||
|
||||
static bool __FplThreadSortPriority(FplWaitingThread thread1, FplWaitingThread thread2)
|
||||
{
|
||||
return __KernelThreadSortPriority(thread1.threadID, thread2.threadID);
|
||||
}
|
||||
|
||||
static bool __KernelClearFplThreads(FPL *fpl, int reason)
|
||||
{
|
||||
u32 error;
|
||||
bool wokeThreads = false;
|
||||
for (auto iter = fpl->waitingThreads.begin(), end = fpl->waitingThreads.end(); iter != end; ++iter)
|
||||
__KernelUnlockFplForThread(fpl, *iter, error, reason, wokeThreads);
|
||||
fpl->waitingThreads.clear();
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
static void __KernelSortFplThreads(FPL *fpl)
|
||||
{
|
||||
// Remove any that are no longer waiting.
|
||||
@@ -532,7 +516,7 @@ static void __KernelSortFplThreads(FPL *fpl)
|
||||
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);
|
||||
HLEKernel::SortWaitingThreadsByPriority(fpl->waitingThreads);
|
||||
}
|
||||
|
||||
int sceKernelCreateFpl(const char *name, u32 mpid, u32 attr, u32 blockSize, u32 numBlocks, u32 optPtr) {
|
||||
@@ -616,7 +600,7 @@ int sceKernelDeleteFpl(SceUID uid)
|
||||
return hleLogDebug(Log::sceKernel, error, "invalid fpl");
|
||||
}
|
||||
|
||||
bool wokeThreads = __KernelClearFplThreads(fpl, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
bool wokeThreads = HLEKernel::ClearWaitingThreads(fpl, SCE_KERNEL_ERROR_WAIT_DELETE, __KernelUnlockFplForThread);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("fpl deleted");
|
||||
|
||||
@@ -758,7 +742,7 @@ int sceKernelCancelFpl(SceUID uid, u32 numWaitThreadsPtr) {
|
||||
if (Memory::IsValid4AlignedAddress(numWaitThreadsPtr)) {
|
||||
Memory::WriteUnchecked_U32(fpl->nf.numWaitThreads, numWaitThreadsPtr);
|
||||
}
|
||||
bool wokeThreads = __KernelClearFplThreads(fpl, SCE_KERNEL_ERROR_WAIT_CANCEL);
|
||||
bool wokeThreads = HLEKernel::ClearWaitingThreads(fpl, SCE_KERNEL_ERROR_WAIT_CANCEL, __KernelUnlockFplForThread);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("fpl canceled");
|
||||
return hleLogDebug(Log::sceKernel, 0);
|
||||
@@ -1286,22 +1270,6 @@ void __KernelVplEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelAllocateVplCB: Resuming mbx wait from callback");
|
||||
}
|
||||
|
||||
static bool __VplThreadSortPriority(VplWaitingThread thread1, VplWaitingThread thread2)
|
||||
{
|
||||
return __KernelThreadSortPriority(thread1.threadID, thread2.threadID);
|
||||
}
|
||||
|
||||
static bool __KernelClearVplThreads(VPL *vpl, int reason)
|
||||
{
|
||||
u32 error;
|
||||
bool wokeThreads = false;
|
||||
for (auto iter = vpl->waitingThreads.begin(), end = vpl->waitingThreads.end(); iter != end; ++iter)
|
||||
__KernelUnlockVplForThread(vpl, *iter, error, reason, wokeThreads);
|
||||
vpl->waitingThreads.clear();
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
static void __KernelSortVplThreads(VPL *vpl)
|
||||
{
|
||||
// Remove any that are no longer waiting.
|
||||
@@ -1309,7 +1277,7 @@ static void __KernelSortVplThreads(VPL *vpl)
|
||||
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);
|
||||
HLEKernel::SortWaitingThreadsByPriority(vpl->waitingThreads);
|
||||
}
|
||||
|
||||
SceUID sceKernelCreateVpl(const char *name, int partition, u32 attr, u32 vplSize, u32 optPtr) {
|
||||
@@ -1383,7 +1351,7 @@ int sceKernelDeleteVpl(SceUID uid) {
|
||||
return hleLogError(Log::sceKernel, error);
|
||||
} else {
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelDeleteVpl(%i)", uid);
|
||||
bool wokeThreads = __KernelClearVplThreads(vpl, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
bool wokeThreads = HLEKernel::ClearWaitingThreads(vpl, SCE_KERNEL_ERROR_WAIT_DELETE, __KernelUnlockVplForThread);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("vpl deleted");
|
||||
|
||||
@@ -1588,7 +1556,7 @@ int sceKernelCancelVpl(SceUID uid, u32 numWaitThreadsPtr)
|
||||
if (Memory::IsValid4AlignedAddress(numWaitThreadsPtr))
|
||||
Memory::WriteUnchecked_U32(vpl->nv.numWaitThreads, numWaitThreadsPtr);
|
||||
|
||||
bool wokeThreads = __KernelClearVplThreads(vpl, SCE_KERNEL_ERROR_WAIT_CANCEL);
|
||||
bool wokeThreads = HLEKernel::ClearWaitingThreads(vpl, SCE_KERNEL_ERROR_WAIT_CANCEL, __KernelUnlockVplForThread);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("vpl canceled");
|
||||
|
||||
@@ -1750,7 +1718,7 @@ static void __KernelSortTlsplThreads(TLSPL *tls)
|
||||
HLEKernel::CleanupWaitingThreads(WAITTYPE_TLSPL, uid, tls->waitingThreads);
|
||||
|
||||
if ((tls->ntls.attr & PSP_FPL_ATTR_PRIORITY) != 0)
|
||||
std::stable_sort(tls->waitingThreads.begin(), tls->waitingThreads.end(), __KernelThreadSortPriority);
|
||||
HLEKernel::SortWaitingThreadsByPriority(tls->waitingThreads);
|
||||
}
|
||||
|
||||
int __KernelFreeTls(TLSPL *tls, SceUID threadID)
|
||||
|
||||
@@ -50,11 +50,6 @@ static const u32 MSGPIPE_WAIT_VALUE_RECV = 1;
|
||||
// NativeMsgPipe/MsgPipeWaitingThread/MsgPipe itself now live in sceKernelMsgPipe.h - see the
|
||||
// comment on the class there for why.
|
||||
|
||||
static bool __KernelMsgPipeThreadSortPriority(const MsgPipeWaitingThread &thread1, const MsgPipeWaitingThread &thread2)
|
||||
{
|
||||
return __KernelThreadSortPriority(thread1.threadID, thread2.threadID);
|
||||
}
|
||||
|
||||
bool MsgPipeWaitingThread::IsStillWaiting(SceUID waitID) const
|
||||
{
|
||||
return HLEKernel::VerifyWait(threadID, WAITTYPE_MSGPIPE, waitID);
|
||||
@@ -213,7 +208,7 @@ void MsgPipe::SortThreads(std::vector<MsgPipeWaitingThread> &waitingThreads, boo
|
||||
HLEKernel::CleanupWaitingThreads(WAITTYPE_MSGPIPE, GetUID(), waitingThreads);
|
||||
|
||||
if (usePrio)
|
||||
std::stable_sort(waitingThreads.begin(), waitingThreads.end(), __KernelMsgPipeThreadSortPriority);
|
||||
HLEKernel::SortWaitingThreadsByPriority(waitingThreads);
|
||||
}
|
||||
|
||||
void MsgPipe::SortReceiveThreads()
|
||||
|
||||
@@ -199,26 +199,6 @@ static void __KernelMutexEraseLock(PSPMutex *mutex) {
|
||||
mutex->nm.lockThread = -1;
|
||||
}
|
||||
|
||||
static std::vector<SceUID>::iterator __KernelMutexFindPriority(std::vector<SceUID> &waiting)
|
||||
{
|
||||
_dbg_assert_msg_(!waiting.empty(), "__KernelMutexFindPriority: Trying to find best of no threads.");
|
||||
|
||||
std::vector<SceUID>::iterator iter, end, best = waiting.end();
|
||||
u32 best_prio = 0xFFFFFFFF;
|
||||
for (iter = waiting.begin(), end = waiting.end(); iter != end; ++iter)
|
||||
{
|
||||
u32 iter_prio = __KernelGetThreadPrio(*iter);
|
||||
if (iter_prio < best_prio)
|
||||
{
|
||||
best = iter;
|
||||
best_prio = iter_prio;
|
||||
}
|
||||
}
|
||||
|
||||
_dbg_assert_msg_(best != waiting.end(), "__KernelMutexFindPriority: Returning invalid best thread.");
|
||||
return best;
|
||||
}
|
||||
|
||||
static bool __KernelUnlockMutexForThread(PSPMutex *mutex, SceUID threadID, u32 &error, int result) {
|
||||
if (!HLEKernel::VerifyWait(threadID, WAITTYPE_MUTEX, mutex->GetUID()))
|
||||
return false;
|
||||
@@ -379,7 +359,7 @@ static bool __KernelUnlockMutex(PSPMutex *mutex, u32 &error) {
|
||||
while (!wokeThreads && !mutex->waitingThreads.empty())
|
||||
{
|
||||
if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0)
|
||||
iter = __KernelMutexFindPriority(mutex->waitingThreads);
|
||||
iter = HLEKernel::FindBestPriorityWaiter(mutex->waitingThreads);
|
||||
else
|
||||
iter = mutex->waitingThreads.begin();
|
||||
|
||||
@@ -770,7 +750,7 @@ bool __KernelUnlockLwMutex(T workarea, u32 &error) {
|
||||
while (!wokeThreads && !mutex->waitingThreads.empty())
|
||||
{
|
||||
if ((mutex->nm.attr & PSP_MUTEX_ATTR_PRIORITY) != 0)
|
||||
iter = __KernelMutexFindPriority(mutex->waitingThreads);
|
||||
iter = HLEKernel::FindBestPriorityWaiter(mutex->waitingThreads);
|
||||
else
|
||||
iter = mutex->waitingThreads.begin();
|
||||
|
||||
|
||||
@@ -119,17 +119,6 @@ void __KernelSemaEndCallback(SceUID threadID, SceUID prevCallbackId)
|
||||
|
||||
// Resume all waiting threads (for delete / cancel.)
|
||||
// Returns true if it woke any threads.
|
||||
static bool __KernelClearSemaThreads(PSPSemaphore *s, int reason) {
|
||||
u32 error;
|
||||
bool wokeThreads = false;
|
||||
std::vector<SceUID>::iterator iter, end;
|
||||
for (iter = s->waitingThreads.begin(), end = s->waitingThreads.end(); iter != end; ++iter)
|
||||
__KernelUnlockSemaForThread(s, *iter, error, reason, wokeThreads);
|
||||
s->waitingThreads.clear();
|
||||
|
||||
return wokeThreads;
|
||||
}
|
||||
|
||||
int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
|
||||
{
|
||||
u32 error;
|
||||
@@ -152,7 +141,7 @@ int sceKernelCancelSema(SceUID id, int newCount, u32 numWaitThreadsPtr)
|
||||
else
|
||||
s->ns.currentCount = newCount;
|
||||
|
||||
if (__KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL))
|
||||
if (HLEKernel::ClearWaitingThreads(s, SCE_KERNEL_ERROR_WAIT_CANCEL, __KernelUnlockSemaForThread))
|
||||
hleReSchedule("semaphore canceled");
|
||||
|
||||
return hleNoLog(0);
|
||||
@@ -203,7 +192,7 @@ int sceKernelDeleteSema(SceUID id) {
|
||||
} else {
|
||||
DEBUG_LOG(Log::sceKernel, "sceKernelDeleteSema(%i)", id);
|
||||
|
||||
bool wokeThreads = __KernelClearSemaThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE);
|
||||
bool wokeThreads = HLEKernel::ClearWaitingThreads(s, SCE_KERNEL_ERROR_WAIT_DELETE, __KernelUnlockSemaForThread);
|
||||
if (wokeThreads)
|
||||
hleReSchedule("semaphore deleted");
|
||||
|
||||
@@ -252,7 +241,7 @@ int sceKernelSignalSema(SceUID id, int signal) {
|
||||
s->ns.currentCount += signal;
|
||||
|
||||
if ((s->ns.attr & PSP_SEMA_ATTR_PRIORITY) != 0)
|
||||
std::stable_sort(s->waitingThreads.begin(), s->waitingThreads.end(), __KernelThreadSortPriority);
|
||||
HLEKernel::SortWaitingThreadsByPriority(s->waitingThreads);
|
||||
|
||||
bool wokeThreads = false;
|
||||
retry:
|
||||
|
||||
Reference in new issue
Block a user