sceUltGetQueueInfo reported every blocked queue thread as a waiting popper because both directions incremented one counter. Track the two wait classes in separate fields and fill both query outputs, copy one waiter record per blocked thread, and cover full-queue and empty-queue waits with a new queue-waiters test. sceUltGetUlthreadRuntimeInfo now throws when a caller asks for worker thread handles, since this runtime starts no worker threads, and the debt entry records the remaining limitations.
The console's libSceUlt exports these calls only under their
underscore names: _sceUltSemaphoreOptParamInitialize,
_sceUltQueueOptParamInitialize,
_sceUltQueueDataResourcePoolOptParamInitialize,
_sceUltWaitingQueueResourcePoolOptParamInitialize,
_sceUltUlthreadOptParamInitialize,
_sceUltReaderWriterLockOptParamInitialize and
_sceUltReaderWriterLockCreate are in the PS5 3.20 export list
(DNNDHH/PS5-3.20_Libs libSceUlt.c) and in the PS4 SDK stub list
(aerosoul94/dynlib dynlib.xml), and their names without the underscore
are in neither. Each now forwards to the export without the underscore,
passing the trailing build version, as _sceUltMutexOptParamInitialize
and _sceUltMutexCreate already do. The argument lists match the PS Vita
libult in RPCS3; that they hold on PS5 stays recorded as unmeasured in
the debt entry for the underscore forwarders.
The opt-params test also runs the six underscore initializers: a null
pointer returns ULT_ERROR_NULL, the 128-byte structure is cleared and
the bytes after it are left alone. The new rwlock-underscored test
checks that _sceUltReaderWriterLockCreate returns ULT_ERROR_NULL for a
null lock, ULT_ERROR_INVALID for an unknown pool without writing the
lock and ULT_ERROR_STATE for a second create, that it clears the
256-byte lock, and that the lock it creates on a waiting-queue pool
works with the read, write and destroy calls.
Co-Authored-By: Claude Opus 5.5 <[email protected]>