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>
An interrupt with no handler to run, a vblank with none registered for
example, switched the running thread off to idle and left it there until
some later event rescheduled: ~775us of every frame in a game that spins
without a vblank handler. It now reschedules at once. Taking an interrupt
also clears the ll bit directly, which that switch had been doing.
Interrupt handlers can now carry a cost before they run and after the
last queued one returns. Alarms use it: on hardware a thread that keeps
running loses ~70us to an alarm handler, and a thread the handler wakes
runs ~50us after it (pspautotests threads/scheduling/alarmcosts), so
17us in and 40us out. sceKernelSetAlarm's 40us is split evenly around the
deadline, keeping the handler ~1040us after a 1000us alarm.
A handler's return value re-arms its alarm counting from the previous
deadline, so a repeating alarm doesn't drift by those costs, unless
that's already past, as after interrupts were suspended for a while.
The vblank's own cost (~62us of CPU on hardware) isn't charged yet: with
it, a waiter ~90us after the vblank still reads hcount 1 on hardware, but
line 2 here. Hardware evidently raises the interrupt ~40us before the
line count wraps. That's noted where the waiters are released.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On hardware sceKernelSetAlarm takes about 40us, and the handler never runs
sooner than about 215us after the alarm is set, however short it asked
for (pspautotests threads/scheduling/alarmcosts). Also clamps huge
sysclock alarms before converting to cycles; LONG_LONG_MAX used to
overflow and go off at once, which the late-firing events had hidden.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
AlarmIntrHandler::handleResult looked the alarm up again and passed the result
straight to __KernelScheduleAlarm without a null check - run() a few lines above
does check. An alarm handler that cancels its own alarm and then returns a
positive reschedule value dereferenced null.
Also, sceKernelSetSysClockAlarm validated four bytes and then read eight, and
returned a bare -1 instead of an error code.
* Rename LogType to Log
* Explicitly use the Log:: enum when logging. Allows for autocomplete when editing.
* Mac/ARM64 buildfix
* Do the same with the hle result log macros
* Rename the log names to mixed case while at it.
* iOS buildfix
* Qt buildfix attempt, ARM32 buildfix
These are names that can often conflict with system headers in ports.
Let's just simplify by prefixing with PSP.
No actual functional/code changes, just syntax and names.
Couldn't think of a better way to do this, maybe there's some fancy
one I don't know about.
Also finished up a couple left over kernel objects.
Maybe a quarter the way there?
Based on tests, vblank doesn't queue up (makes sense) while
interrupts are disabled.
I'm not 100% sure about the GPU stuff but it seems to only come
from HLE via sceGe, so this should fix those return values.