When the native open failed with an error other than ENOENT, OpenNative
probed whether the path is a directory with std::filesystem::is_directory.
With the MinGW runtime that probe can set errno to ENOENT, and OpenNative
then reported the probe's ENOENT instead of the open error. On Windows 11
22621 a symbolic link loop failed with ELOOP from the native open and
sceKernelOpen returned 0x80020002, so guest_filesystem aborted at the
ELOOP check added by #8640.
Keep the open error and restore it when the path is not a directory.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
pthread_kill(thread, 0) returned 0 for every handle other than the caller's before it asked whether the thread was still alive. FreeBSD's _pthread_kill looks the thread up with _thr_find_thread before it checks for signal 0, so the call answers ESRCH for a thread that has ended or was never a thread. The liveness check now runs before the signal 0 shortcut; the calling thread still answers 0.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
sceKernelGetProcessTimeCounter counted nanoseconds and
sceKernelGetProcessTimeCounterFrequency returned 1 GHz, while
sceKernelGetTscFrequency reports the host TSC rate. On the console the
process time counter runs at the TSC frequency, so a title may scale
the counter by sceKernelGetTscFrequency. PPSA34501 does, and its clock
ran 3.4 times slow on a 3.4 GHz host: it paced its 60 Hz frames to
17.6 fps and its game time and audio drifted apart.
The counter now ticks at sceKernelGetTscFrequency, over the same
monotonic clock and APS5_TIME_SCALE, and its frequency is that rate.
With the stem cut at the last extension, the decoy guest_module_fixture.sprx.elf.GUEST.PRX
and the dangling link guest_module_fixture.zprx.elf.GUEST.PRX had the stems
guest_module_fixture.sprx and guest_module_fixture.zprx, so they no longer
matched the request and the shortest-name rule was not exercised. They are now
guest_module_fixture.sprx.GUEST.PRX and guest_module_fixture.zprx.GUEST.PRX,
which have the request's stem and are longer than the real module copy.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Since #8512 a raise redirects a target running host code once 50 ms have
passed since the raise began. A target inside a system call that is not a
wait, such as the NtWriteFile of an fwrite that holds its stream lock, can
stay there longer; the redirect then ran the handler with the lock held.
SONIC SUPERSTARS froze at frame 67 again on main this way, with its GC
raise delivered at ntdll!ZwWriteFile+20.
A target stopped right after a syscall instruction in ntdll now restarts
the 50 ms host-code window, so the raise keeps sampling until the call
returns and the target leaves host code, bounded by the 1 s retry limit.
guest_raise_in_system_call holds a writer in NtWriteFile on a slowly
drained pipe; it times out on main and passes with this change.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Animal Well (PPSA22520) imports _Thrd_detach (L7f7zYwBvZA) from libc.prx and nothing exports it, so the Windows loader stops at startup. Register libkernel's pthread_detach with libc like pthread_create and pthread_join, and return _Thrd_error (4) when it fails.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GtXavMkgCTCdmRpweviHcQ
Culprit: none in 892a4f1328..b85d972f42; race in the Windows vnode watch (50b06110b guarded only the loop). Run 39473930499, guest_kqueue: a watched file deleted before registration is snapshotted under $Extend\$Deleted, WatchParent got ERROR_ACCESS_DENIED and threw.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
A title asks for a module by its console name and the relinker names the
converted module after the ELF it was built from: Unity IL2CPP titles load
Media/Modules/<name>.prx and Media/Plugins/<name>.prx while the dump holds
<name>.elf.guest.prx, so sceKernelLoadStartModule failed with 0x80020002
and the title stopped 3 s after start. After the exact and the
case-insensitive <name>.guest.prx lookups miss, take the sibling whose stem
matches the request and ends with .guest.prx, shortest name first.
The Windows sceKernelGetdirentries stored 0 in *basep on every read, so a
guest looping on the cookie saw it stall (FreeBSD stores the directory
offset the read started at, kern_getdirentries: *basep = loff). Report the
index of the first entry of the read, the same unit lseek takes on these
descriptors, and run guest_directory_entries on Windows, where it was never
built.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>