This reverts commit 780b33aea3, restoring the 13824 MiB direct memory pool.
With the pool at 12288 MiB, Astro Bot (PPSA21564) can no longer load its
level: DirectMemoryAllocator asserts "Can't allocate direct memory" for a
64 MB VideoPlayerTexture with 12228 of 12288 MB in use, then the process
faults about 26 s in (2 of 2 runs, RTX 4090, Linux, main cccdaa2734).
The same tree with only this merge reverted runs the full 150 s with no
direct memory assert (2 of 2 runs).
scePthreadMutexattrSetkind called NotImplemented_nid_no_patch for a kind
outside 1 to 4. Firmware 13.42's libkernel, run in an emulator, makes it
call pthread_mutexattr_setkind_np, which stores any kind as a signed
16-bit value and returns 0, and turns a null attribute's -1 with errno 22
into 0x8001FFFF. It now forwards to pthread_mutexattr_setkind_np and
converts the result with sceKernelError, so a null attribute or object
still returns 0x8001FFFF and now also sets errno 22.
An out-of-range kind is refused by scePthreadMutexInit with 0x80020016,
leaving the mutex untouched, as measured for the same module.
scePthreadMutexattrGetkind is unchanged; kind 0 now reaches it and
returns 0.
sceKernelTruncate and truncate checked for a symbolic link loop only
after the native truncate failed, but on Windows std::filesystem::status
already reports a self-referencing link as missing, so the call returned
ENOENT before reaching that check. The loop check now runs before the
not-found result too.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
SuspendThread fails with STATUS_THREAD_IS_TERMINATING for a thread that
has begun to exit while its handle is not signaled yet. TryDeliver took
only the signaled handle as an exit, so the raise deliverer, which keeps
sweeping a target in host code until delivery or exit, threw "cannot
suspend the target thread" and aborted the process when that target
exited in between. The suspension now reads the NTSTATUS from
NtSuspendThread and treats a terminating target as exited; other
failures still throw.
guest_raise_exiting_thread raises at 32 threads per round that block in
a host wait and exit after it, for 100 rounds.
The test throws std::bad_alloc from a replaced operator new, so on MinGW it needs the same libc link, unwind section rename and DLL path as the other throwing guest tests (the Windows link failed on __gxx_personality_v0).
JsonObject held std::pair<std::string, JsonValue> while JsonValue was
still incomplete. Clang with libstdc++ instantiates the pair and the
vector destructor at the end of JsonValue and stops with "incomplete
type used in type trait expression". A named JsonMember struct defined
after JsonValue keeps the vector element a plain class.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Unbacked pages of a PRT range are anonymous zero pages, so a failed allocation puts those back with _zeroPrt instead of leaving the range reserved and unreadable.
_ammAllocatePrt took pool pages one at a time and mapped and recorded them run by run, so a failure on run k lost the pool pages of runs k to n. It now maps the unbacked part through AmmPool::MapScattered and returns the range to the reservation if that throws, and the unused _takePoolPages is gone.
Fail each allocation of a map from a fragmented pool, a map whose host call fails after each run, and a page insertion, and check that the pool and the page records are unchanged after every failure and that a map of one page more than the pool holds is still refused.
Move the pool bookkeeping into AmmPool.hpp. A map from a fragmented pool now plans its pages without changing the pool, stages the page and reference records in their own maps, maps the runs, and only then splits the pool and moves the records in with no allocation, so a failed map leaves the pool and the records as they were. Adding a page inserts its reference record first and undoes it if the page record throws.
_ammMap took one contiguous run of the direct memory given to the mapper and
threw (an uncaught runtime_error -> abort) when the pool was fragmented:
PPSA03671 aborted ~4 min into a slot-4 load on an 11 MB map ("AMM: no free run
of 11010048 bytes"). The PS5 maps the mapper's pages through page tables, so a
fragmented pool still serves the map: when no run fits, the map now takes
pages from several runs (first fit) and maps each contiguous group. Run hww8:
the 11 MB map and several 10-33 MB maps went through, no abort.
pthread_setspecific returns an errno value, unlike the Sce function it wraps,
and neither POSIX export had a test. Check the FreeBSD 11.4 results of
_pthread_setspecific and _pthread_getspecific (lib/libthr/thread/thr_spec.c
lines 165-194 and 196-222): a key outside the valid range or a deleted key
makes setspecific return EINVAL (22), getspecific returns NULL for such a key
and for a key never set, a stored value is read back, NULL can be stored, a
new key with a reused number starts empty, and another thread has its own
value.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>