host_performance_session_tests uses no guest library, so the guest unwind helper leaves the C++ runtime unlinked on MinGW and the link fails with an undefined __gxx_personality_v0. The host test helper links the runtime statically, as the other host-only tests do.
On Windows, sceKernelRaiseException threw for a thread created suspended
and not resumed yet. FreeBSD libthr starts such a thread with signals
blocked and restores its mask on resume, so the signal stays pending and
is delivered on that thread once it runs.
The raise is now recorded in the thread's pendingException with a
compare-exchange, and the thread exchanges it for -1 when it leaves the
creation wait and delivers it to itself before its start routine. Both
sides use one atomic, so a raise racing a resume is either taken by the
thread or, after it started, delivered as for a running thread. Raises
while pending are merged, as for a standard signal.
guest_pthread_create_suspended now runs the deferred-delivery case on
every host, with a second raise while the thread is suspended.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Read APS5_GAME_MODE once at load, the same point where the Windows build
raises the scheduler tick, so an invalid value stops the title at start
with an error that names the variable and an unset one changes nothing.
Run the process session in a test executable linked with libc and leave
through LibcExit and LibcExitWithoutHandlers: the backend is released once
in both. Check that a refused request is never released, that off never
reaches the backend, that a second session is refused, that an unset
APS5_GAME_MODE is accepted and that APS5_GAME_MODE=bogus is rejected with
an error naming the variable.
Add CreateHostBackend (the GameMode client on Linux, the activity backend
on macOS, a backend that reports itself unavailable elsewhere),
StartProcessSession, which owns the one session of the process and
releases it from the libc shutdown callbacks that every exit path runs,
and StartFromEnvironment, which reads APS5_GAME_MODE and does nothing at
all when it is unset, empty or off. Build the files into libkernel; the
session is not started yet.
Build four fixture libraries that export objc_getClass, sel_registerName,
objc_msgSend and the autorelease pool functions (complete, without
NSProcessInfo, returning no activity, without pool functions) and drive
the backend through them on any POSIX host. Check the exact message
sequence (begin with the user-initiated and latency-critical options,
retain, end, release), balanced pools on every path, a held activity ended
by the destructor, and unavailable and refused results.
macOS throttles timers and background work of a process unless it holds an
NSProcessInfo activity (Apple, Foundation, NSProcessInfo
beginActivityWithOptions:reason:, with NSActivityUserInitiated and
NSActivityLatencyCritical, which asks for the highest timer and I/O
precision available). The tree has no Objective-C sources, so call the
runtime from C++: load libobjc and Foundation with dlopen, look up
objc_getClass, sel_registerName, objc_msgSend and the autorelease pool
functions, begin one activity, retain its token, and end and release it on
End. Both library paths are injectable, and any missing piece is reported
as unavailable. Nothing uses the backend yet.
Build three tiny shared libraries that export the real_gamemode_* symbols
(complete, without real_gamemode_request_end, without
real_gamemode_error_string) and drive the client through them, so no
daemon is needed. Check a missing library, a fall back to the second
library name, request and release once each, a refusal with the library's
reason, a failing release, a missing symbol and a session over the client.
Linux hosts running Feral's gamemoded switch the CPU governor and scheduler
for a registered game. The client the project ships is a header that loads
libgamemode.so.0 (then libgamemode.so) with dlopen and binds the library's
real_gamemode_request_start, real_gamemode_request_end and
real_gamemode_error_string symbols (FeralInteractive/gamemode at
a74b8106a2236d1f2696aa44c93bc4c8ef13b42e, lib/gamemode_client.h).
Do the same here with the library name list injectable: a missing library
or symbol is reported as unavailable, a failing request as refused, nothing
is linked, and the request is ended only when it was made. Nothing uses the
backend yet.
Accept off, on and auto, treat an unset or empty value as off so the
default stays as it is today, and reject anything else with an error that
names the variable and the accepted values.
Check that off never reaches the backend, that start and stop reach it
once each and cannot restart a stopped session, that an unavailable
backend is silent in auto and logged once in on, that a refusal is logged
once in both modes, that throwing backends are contained, and that
concurrent starts reach the backend once.
A title that runs for hours would like the host to treat it as a game
(Feral GameMode on Linux, a latency-critical activity on macOS), but no
code owns that request. Add IBackend, the interface a host mechanism
implements, and Session, the state machine that requests once, releases
once, contains every backend failure and logs it once. Nothing uses it
yet.
The patched libkernel does not hand its plain C++ functions to the other patched libraries: every cross-library call in the tree goes through an extern C helper with a _nid suffix. The host CPU probe had none, so a library that wants the CPU model or the missing feature list cannot reach it. These helpers return plain structs, as the application metadata helpers do.
On Windows, mmap sent a shared memory descriptor straight to the shared
file mapper, skipping the checks and the private path that a regular
file descriptor takes. A private mapping of a named or anonymous object
then failed with EOPNOTSUPP, and a writable shared mapping of a
read-only descriptor failed with EIO instead of EACCES. Shared memory
objects are files on Windows, so they now take the same access checks
and the same private copy as a regular file; only the directory, device
and file-type refusals stay limited to other descriptors.
guest_named_shm_windows_mapping covers shared mappings through two
descriptors, pread and pwrite against them, an offset mapping, a private
mapping, read-only mappings and the mappings after shm_unlink.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
PS5_PayloadSDK measured in a title (firmware 12.09) that
pthread_getaffinity_np answers sets of 8 and 16 bytes and returns ERANGE
for 32 bytes or more, so FreeBSD's 32-byte cpuset_t is refused. The call
accepted exactly 32 bytes and refused every other size. Sizes under 8
keep ERANGE; 17 to 31 bytes, between the measured sizes, throw.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Return the main program's handle, the first one sceKernelGetModuleList
lists and one sceKernelGetModuleInfo accepts. reSOT (PPSA99023) imports
it from libkernel and passes the handle to sceKernelGetModuleInfo to find
its own code segment; before this its eboot failed to load on the
unresolved import.
The PS5 3.20 export lists have it in libkernel as well as libkernel_sys,
and on Windows a libkernel import never reaches libkernel_sys, so the
throwing libkernel_sys stub moves to libkernel as pselect did.
Co-Authored-By: Claude Opus 5.5 <[email protected]>