Skip to main content
Print

ThreadMan Synchronization Primitives: Wait Objects, Cancellation, and Lifetime

Type: REFERENCE   Status: MAINTAINED   Scope: ThreadMan object identity, waits, timeouts, callbacks, cancellation, deletion, and scheduler-visible consequences.   Last reviewed: 2026-08-11

ThreadMan synchronization is a family of guest-visible transactions, not a set of host locks. A compatibility runtime must preserve which guest object was addressed, which condition was requested, why the caller stopped waiting, and which output bytes were committed. This page is a semantic model and source map; it does not claim that every firmware or object type has been measured.

What the public API establishes

The maintained PSPSDK header exposes semaphores, mutexes, lightweight mutexes, event flags, message pipes, callbacks, and thread-status values in one exact public source: user/pspthreadman.h. Its event-flag constants distinguish AND versus OR matching and whether a matched pattern is cleared. The same header documents callback-aware wait variants and typed ThreadMan IDs. Those declarations are the contract surface, not proof of every scheduler ordering detail.

A SceUID is an integer guest identity. It must not be treated as a host pointer or as an untyped array index. The companion PSPSDK type definitions show the same UID convention for file descriptors, which is why a runtime needs type-aware lookup and stale-handle rejection.

Model the wait transaction

call -> validate UID/type and guest spans<br>     -> evaluate condition<br>       -> poll success: consume/clear, write outputs, return<br>       -> wait: READY -> WAITING with deadline and reason<br>                    | signal/unlock/set | timeout | cancellation | deletion | callback interruption/resume<br>     -> commit one PSP result and wake/reschedule
Source-owned wait model. The text-equivalent flow is explicit about the point at which guest memory is written.

The wait record should retain the waiter thread, object/type, requested count or bit pattern, wait mode, deadline, callback-aware flag, and a completion reason. “Waiting=false” is not enough: it loses the distinction between a satisfied condition, timeout, cancellation, deletion, and an API-specific failure. Validate the complete readable/writable guest span before mutating a semaphore count, event-flag clear mask, timeout remainder, or result pointer.

Object-specific conditions

LwMutex: the PSP lightweight mutex API uses a SceLwMutexWorkarea and has its own creation, lock, unlock, recursion, waiter-order, and deletion contract; do not silently map it to an ordinary host mutex.

  • Semaphores: preserve current and maximum counts and the requested signal amount. Waking every waiter to race on a host primitive can change PSP-visible order.
  • Mutexes and lightweight mutexes: retain owner, recursion/count rules, waiter ordering, and the work-area contract for lightweight mutexes. Owner termination is a separate experiment from ordinary unlock.
  • Event flags: store the waiter’s requested bits and AND/OR/clear mode. Multiple waiters can observe and mutate one flag word in an order-sensitive way.
  • Callbacks: callback-aware waits can run guest callback code and then resume the original wait. They are not ordinary waits followed by a host callback after return.

Deletion, cancellation, and timeout are observable

Deleting an object can wake blocked threads, invalidate later refer/status calls, affect UID reuse, and change callback behavior. Cancellation and deletion can have different error meanings. A timeout argument may be null/infinite, immediate, or a guest pointer updated with remaining time; the pointer write is part of the ABI. Keep the cause until the API chooses its named result.

The runtime scheduler in Nakagawa’s current sched.c and HLE boundary in hle.c are implementation-specific anchors for this model. They are cited at file/revision level; the page does not imply that current runtime coverage equals the full PSP contract.

Evidence boundary

The existing callbacks and callback-aware waits and ThreadMan scheduler model pages provide public context. The bounded hardware result in WaitThreadEnd signed-negative intermediate status is one measured path, not a universal rule for every wait object. Private fixtures, captures, paths, and hashes are deliberately not reproduced here.

Recommended probe matrix

Use source-owned probes with deterministic semaphore/event-flag handshakes: poll versus wait, signal-before-wait versus signal-during-wait, timeout zero versus finite, callback-aware versus ordinary, cancellation versus deletion, and one waiter versus multiple waiters. Record PSP model, firmware/CFW, controls, repeat count, raw return, output bytes, and final object state separately. Leave any unreplicated axis OPEN.

Sources

Table of Contents