mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-21 02:09:05 +02:00
Kernel: Keep alarm and vtimer queues in step with their pending interrupts
Each due alarm or vtimer queues its id next to a pending interrupt, which pops it when it runs. An alarm cancelled with its interrupt pending was never popped, so every later alarm interrupt found the cancelled one at the front and was dropped: no alarm ran again. Deleting a vtimer erased its id instead, leaving the last pending interrupt with an empty list. Both now pop a timer that's gone when its interrupt comes, as threads/alarm/pending and threads/vtimers/pending show the PSP still runs the rest, in order. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
3ac908345c
commit
d42f34d3de
4 files changed
+19
-9
No files matched your search
@@ -70,12 +70,17 @@ public:
|
||||
bool run(PendingInterrupt& pend) override
|
||||
{
|
||||
u32 error;
|
||||
if (triggeredAlarm.empty()) {
|
||||
return false;
|
||||
}
|
||||
int alarmID = triggeredAlarm.front();
|
||||
|
||||
PSPAlarm *alarm = kernelObjects.Get<PSPAlarm>(alarmID, error);
|
||||
if (error)
|
||||
{
|
||||
// handleResult won't run, so the alarm is popped here, or every later alarm runs this one's entry.
|
||||
WARN_LOG(Log::sceKernel, "Ignoring deleted alarm %08x", alarmID);
|
||||
triggeredAlarm.pop_front();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -139,12 +139,18 @@ public:
|
||||
|
||||
bool run(PendingInterrupt &pend) override {
|
||||
u32 error;
|
||||
if (vtimers.empty()) {
|
||||
return false;
|
||||
}
|
||||
SceUID vtimerID = vtimers.front();
|
||||
|
||||
VTimer *vtimer = kernelObjects.Get<VTimer>(vtimerID, error);
|
||||
|
||||
if (error)
|
||||
if (error) {
|
||||
// Deleted while its interrupt was pending. handleResult won't run, so it's popped here.
|
||||
WARN_LOG(Log::sceKernel, "Ignoring deleted vtimer %08x", vtimerID);
|
||||
vtimers.pop_front();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Reserve some stack space for arguments.
|
||||
u32 argArea = currentMIPS->r[MIPS_REG_SP];
|
||||
@@ -246,12 +252,9 @@ u32 sceKernelDeleteVTimer(SceUID uid) {
|
||||
return hleLogError(Log::sceKernel, error, "bad timer ID");
|
||||
}
|
||||
|
||||
for (std::list<SceUID>::iterator it = vtimers.begin(); it != vtimers.end(); ++it) {
|
||||
if (*it == vt->GetUID()) {
|
||||
vtimers.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Its entry in vtimers stays: each one belongs to a pending interrupt, which pops it when it runs
|
||||
// (or right away, finding the timer gone), so erasing it here would hand that interrupt to the
|
||||
// next timer's entry, or to an empty list if the handler is deleting its own timer.
|
||||
|
||||
return hleLogDebugOrError(Log::sceKernel, kernelObjects.Destroy<VTimer>(uid));
|
||||
}
|
||||
|
||||
+1
-1
Submodule pspautotests updated: 2533d2d44c...aa60f4bfec.
@@ -371,6 +371,7 @@ tests_good = [
|
||||
"sysmem/volatile",
|
||||
"threads/alarm/alarm",
|
||||
"threads/alarm/cancel/cancel",
|
||||
"threads/alarm/pending/pending",
|
||||
"threads/alarm/refer/refer",
|
||||
"threads/alarm/set/set",
|
||||
"threads/callbacks/afterwait",
|
||||
@@ -508,6 +509,7 @@ tests_good = [
|
||||
"threads/vtimers/getbase",
|
||||
"threads/vtimers/gettime",
|
||||
"threads/vtimers/interrupt",
|
||||
"threads/vtimers/pending/pending",
|
||||
"threads/vtimers/refer",
|
||||
"threads/vtimers/sethandler",
|
||||
"threads/vtimers/settime",
|
||||
|
||||
Reference in new issue
Block a user