The tests call _sceUlt*OptParamInitialize and _sceUltReaderWriterLockCreate;
they are declared once in the library's Api.hpp, with the typed UltOptParam
signatures.
sceUltGetUlthreadRuntimeInfo returned success when workerThreads was null and workerCapacity was nonzero, while rejecting the same null/nonzero-capacity combination on ulthreads with ULT_ERROR_NULL. Reject null workerThreads with nonzero capacity before touching info, and add test coverage checking the error result and that info is left untouched.
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]>
Destroy locked the state's mutex through a reference into the map entry and
then erased the entry. When that held the last shared_ptr, the state was
freed before the lock guard unlocked its mutex. Take a shared_ptr copy
before the guard so the state outlives it.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
An ulthread runs on its own guest thread, so it remembers its object for sceUltUlthreadGetSelf, yields that thread, and exits it with the status sceUltUlthreadJoin and sceUltUlthreadTryJoin return. Outside an ulthread the three return ULT_ERROR_STATE.
Readers share the lock while no writer holds it and a writer waits until it is free. Destroying a held or waited-on lock and destroying the waiting-queue pool of a lock a thread waits on return ULT_ERROR_BUSY, and sceUltFinalize wakes waiters with ULT_ERROR_STATE, as for the mutex.
It takes a free mutex or relocks one the caller holds, as sceUltMutexLock does, and returns ULT_ERROR_BUSY instead of waiting when another thread holds it.
Forwards _sceUltWaitingQueueResourcePoolCreate and _sceUltSemaphoreCreate to the existing calls, like the other underscore Ult exports. Declares sceNetShowIfconfig, sceNpWebApi2GetMemoryPoolStats, Json::Value::setNullAccessCallBack, kqueue, kevent and one pad call of unknown name without an implementation.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
sceUltFinalize cleared gUlthreads directly, dropping the last
shared_ptr to an UltUlthreadState while its worker thread still held
the raw pointer passed to scePthreadCreate. Finalize now returns
ULT_ERROR_BUSY when an ulthread is still registered, before any global
state is torn down, following the BUSY convention of the queue,
semaphore and queue data pool destroy paths. Joining the ulthread
remains the caller's responsibility, as sceUltUlthreadJoin already
keeps the state alive across scePthreadJoin and erases it afterwards.
Every library CMakeLists.txt ended with the same block removing -static,
-static-libgcc and -static-libstdc++ from CMAKE_EXE_LINKER_FLAGS on MinGW,
because core/libs/CMakeLists.txt only removed them after adding the library
directories. Remove them before the libc and library directories are added
so each directory inherits the stripped flags, and drop the 52 copies.
Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_017pTZqAyVSZy2FZmaqakPHZ