On Windows, pipe_nid_postfix configured the anonymous pipe with a 4096-byte buffer. When guest executables redirect standard error to a pipe via dup2 and host logging writes to standard error, the pipe buffer fills during startup before or between guest reader drains, blocking writer threads in ZwWriteFile and deadlocking the title. Increase the Windows pipe buffer capacity to 65536 bytes to match FreeBSD BIG_PIPE_SIZE used by the PS5 kernel, and cover multi-page single-shot pipe writes in guest posix scalar IO tests.
The C runtime allows 512 stdio streams by default, so after about 509
guest fopen/fdopen streams every further stream failed with EMFILE,
including the std::ifstream APR opens for each read, while getrlimit
reports 8192 open files. Raise the limit to 8192 when libkernel loads,
as the Linux build raises RLIMIT_NOFILE.
guest_dynamic_loader and guest_dynamic_loader_fixed_base run the same
GuestDynamicLoader.cpp in the same working directory, and both copy the
module fixture to anyps5-relinked-module-for-test.prx.guest.prx and
anyps5-host-loaded-module-for-test.prx before loading it. Under ctest
--parallel one test rewrote or removed a file the other had mapped:
Bus error, or failed at GuestDynamicLoader.cpp:92. Give both one
RESOURCE_LOCK.
PPSA34015 (EA SPORTS FC 27) stopped with "Joining guest thread: Access is
denied": scePthreadJoin waited on a thread that another call released
under it, and then waited on its closed handle. As FreeBSD 11.4's
thr_join.c and thr_detach.c do with the joiner field, scePthreadDetach
now returns EINVAL while a thread waits to join the target, a second
concurrent scePthreadJoin returns EOPNOTSUPP, a cancelled join backs out,
and a completed join leaves the thread detached.
Copy bounded host reads into the destination in user mode so demand-committed pages can be handled by the process. Preserve short-read validation, zero-fill at EOF and HostWrite protection checks. Add synthetic read and Windows page-fault regressions. AI-assisted: yes.
Open.cpp passed host errno values 1 to 34 through and turned every
other one into EIO. On Linux, ENAMETOOLONG (36) and ELOOP (40) are above
that range, so sceKernelOpen and sceKernelUnlink returned EIO for a name
longer than 255 bytes or a symbolic link loop, where FreeBSD returns
ENAMETOOLONG (63) and ELOOP (62). sceKernelStat returned ENOENT for
both. sceKernelMkdir already reported them through the mapping in
Stdio.cpp.
Values above 34 now go through FilesystemError, the std::errc mapping
that path resolution already uses. sceKernelStat returns ENAMETOOLONG
and ELOOP when the status query fails with them. The POSIX open, unlink
and stat wrappers set the same errno values.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A shared mapping is a view of a file section created on the descriptor's
handle, read-write when the descriptor is, otherwise read-only. A private
mapping is a copy of the file read at mmap, as POSIX allows. Anonymous
shm_open objects and JIT shared memory descriptors are temporary files on
Windows, so mmap now maps them too (it failed with EOPNOTSUPP before).
mprotect of a mapped view above the view's protection fails with EACCES
before any bookkeeping changes. The cases Windows cannot represent are
listed in the libkernel debt.
Dusklight (PPSA99305) uses SQLite in WAL mode, which maps its -shm file.
On Windows main f0634088b every start logged "Failed to start
transaction: disk I/O error" for its Dawn and pipeline caches (3 of 3
runs); with this change the caches initialise and their WAL files fill
(4 of 4 runs). The title reaches its menu either way.
A shared mapping may end inside the 16 KiB page that holds the end of
the file, as POSIX mmap allows: the view ends with the file's last 4 KiB
host page, which Windows zero-fills past the end, the rest of the guest
page is private zero pages, and the file never grows. A mapping that
reaches a whole page past the end still fails with EOPNOTSUPP.
PS5LM Plus (PPSA99581) loads its model with llama.cpp, which maps the
whole GGUF file shared and read-only. With a 491,400,032-byte model,
Windows main 5de7a46e0 and this change without the last page logged
"llama_model_load: error loading model: mmap failed: Operation not
supported" (3 of 3 runs); now the model loads and the completion of
"The capital of France is" starts with " Paris" (3 of 3 runs).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Locking, trylocking, unlocking a destroyed mutex and signalling, broadcasting,
waiting on or destroying a destroyed condition variable threw a C++ exception
into the guest. FreeBSD 11.4 libthr returns EINVAL for all of them (thr_mutex.c
check_and_init_mutex and mutex_unlock_common compare against THR_MUTEX_DESTROYED,
thr_cond.c CHECK_AND_INIT_COND and _pthread_cond_destroy against
THR_COND_DESTROYED). The condition wait path already reported EINVAL for a
destroyed mutex.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>