Skip to main content
Print

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

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 continuation
Source-owned callback-aware-wait diagram.

Callback 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.

Primary sources

Table of Contents