Callbacks and Callback-Aware Waits
Type: REFERENCE Status: MAINTAINED Scope: PSP callback objects, notification, nested execution, and CB waits
PSP callbacks are owned, notified, and executed in a context associated with a guest thread. A callback-aware wait is therefore a contract about notification, wake conditions, nested execution, state preservation, and return handling—not a periodic host timer that invokes every registered function.
How We Know
- PRIOR ART: PSPSDK callback structure and callback/wait declarations.
- IMPLEMENTATION FACT: Nakagawa callback argument/context helper and callback wake path.
- Open behavioral gaps are tracked in Open Research Questions, not filled with generic host behavior.
notify callback
|
v
owned callback becomes pending
|
+--> callback-aware wait wakes/checks
|
'--> nested callback dispatch on owning guest context
|
v
return value / remaining notification / wait continuationCallback object and ownership
A callback record has at least a guest identity, owner-thread association, entry function, common argument, notification state, and lifecycle. Public declarations expose the shape of this object; exact notify-count and deletion semantics remain API-specific.
- Do not run a callback on an arbitrary host worker without preserving the owning guest context.
- Do not conflate callback ownership with the object that caused notification.
- Do not leave a callback entry callable after its owner/module is deleted without an explicit guest rule.
Notification and CheckCallback
Notification makes a callback pending; it is not identical to executing it. sceKernelCheckCallback is a distinct public operation, while callback-aware wait variants have their own wake/check interaction. The safe model keeps pending state, count/argument, owner, and execution separate.
Nested execution and state preservation
IMPLEMENTATION FACT: the current runtime packs callback arguments into the live guest register file, dispatches the callback as a nested guest call, observes its return, and restores the interrupted context. The helper intentionally leaves callee-saved registers, HI/LO, FPU/VFPU state, stack, and GP responsibility to the guest calling convention and callback prologue/epilogue.
This is a production-helper implementation fact, not a claim that every callback edge is hardware-verified. The nesting model should be tested with callbacks that mutate registers, call HLE, yield, and return non-zero.
Callback-aware waits
CB waits need an explicit state machine:
- callback pending before the wait;
- callback arrives while the thread is waiting;
- the waited object satisfies at the same time;
- timeout expires while callback work is pending;
- callback or waited object is deleted/cancelled;
- nested callback returns and the wait resumes.
“Invoke every callback each VBLANK” is not a generic PSP callback model. VBLANK may drive one notification source, but callback execution is governed by ownership, pending state, and the API path that checks or waits.
Do Not Infer
- A defined callback NID is not proof that a CB path executed.
- A callback table is not proof of ownership or deletion semantics.
- Manual fixture setup is not production-dispatch evidence.
- One callback result does not establish all ThreadMan wait variants.
Open questions
Prioritize callback arrival races, nested callbacks during HLE, non-zero callback returns, deletion with pending notifications, module unload, callback-aware I/O/VBLANK waits, and cross-model/firmware results. Keep platform fact, implementation note, and hardware evidence separate.