RaiseOn suspends the target, reads its context and, while it is in host
code, resumes it and samples again after SwitchToThread. On a 16-core
Ryzen 9 5950X (Windows 11 22H2) that resampled the writer of
guest_raise_in_host_code about every 10 us before it could run: in the
raise that hung, 4,989 samples over 50 ms all found it in ucrtbase, so
the 50 ms host-code limit ran out and the handler was redirected into
fwrite, where it deadlocked on the stream lock (the test timed out at
30 s on every run). In a passing raise the samples sat at one RIP for
14,695 of 14,703 samples and the raise took 145 ms.
Spin for 20 us before each new host-code sample, so the target gets to
leave host code. With that, guest_raise_in_host_code passes 5 of 5 runs,
no raise is redirected in host code, and the longest raise is 0.46 to
0.53 ms. Other samples keep SwitchToThread.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
#9272 keeps liveStacks and protectedStackPages alive through static
destruction so that a late mprotect from an atexit handler can still
look up guest thread stacks. The mutex guarding them is still a static
std::mutex. libstdc++'s std::mutex has a trivial destructor, so it keeps
working on Linux, but libc++ destroys the pthread mutex, and a later lock
throws "mutex lock failed: Invalid argument": on macOS the exit probe of
guest_memory_lifetime fails at its mapping protection stage. The lock is
now allocated and never destroyed, like the maps.
The same change is part of #7201 and #8658.
Co-Authored-By: marion909 <[email protected]>
Co-Authored-By: iamthehimansh <[email protected]>
Co-Authored-By: Claude Opus 5.5 <[email protected]>
FreeBSD keeps every character device on devfs, whose devfs_statfs reports
512-byte blocks, 2 blocks and nothing free. Windows threw for any console,
NUL or the guest random device, and Linux described the host's /dev mount.
A kqueue now returns EINVAL, as getvnode does.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
The EINVAL for a descriptor without a vnode now applies only to a pipe or socket. A character device is a vnode on FreeBSD, so getvnode succeeds and change_dir fails with ENOTDIR; File::IsCharacterDevice keeps that answer for the host character devices (a tty, NUL or /dev/null) and the guest random device. guest_kernel_sys pins it with /dev/random.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
On Windows, dlopen passed a module that was never relinked to LoadLibraryExW, which raised the
modal Bad Image hard-error dialog and blocked the calling thread until someone answered it. The
load now runs with SEM_FAILCRITICALERRORS set for that thread only, so it fails at once with the
same result as before. Every failed load is reported once per file on stderr with a [module]
prefix; a file that exists with no relinked .guest.prx names the relinker's --module-dir option.
sosend_generic fails a send on a socket that can send no more with EPIPE
before it looks at so_error. Winsock reports the same send as WSAECONNABORTED
or WSAECONNRESET, which reached the guest as ECONNABORTED or ECONNRESET.
A stream send now maps both to EPIPE. The send-after-close checks of
guest_tcp, guest_socket_read_write and guest_socket_pair run on Windows too.
Co-Authored-By: Claude Sonnet 5.5 <[email protected]>