The deferred-dependency start state in InitializeDeferredModule (the
resolving vector and the started-results map) were thread_local objects with
destructors. On Windows a thread_local destructor in a module runs after
emulated TLS has freed the object, and prx_thread_local_destructors fails on
main for it. Hold both in HostThreadLocal like the other prx modules; the
trivial depth counter stays thread_local. Behaviour is unchanged.
The test declared sceKernelInstallExceptionHandler, sceKernelRemoveExceptionHandler
and longjmp_nid_postfix itself, the last with a void* buffer. Include the API
headers instead and keep the jump buffer as std::uint64_t, as the canonical
longjmp_nid_postfix(std::uint64_t*, int) takes it.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
dladdr1 searches the object's symbol table, which made every host fault
chained past an installed handler about 8 us slower on Linux. glibc 2.35
and later answer the same question with _dl_find_object, which is also
async-signal-safe; older glibc keeps dladdr1.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A handler installed for SIGILL, SIGFPE, SIGBUS or SIGSEGV now receives
the faults raised in title code instead of the process ending, with
mc_trapno, mc_addr and mc_err filled as FreeBSD 11's amd64 trap() does.
On Windows the crash reporter's vectored handler offers unclaimed faults
to libkernel, which redirects the thread to a stub that runs the handler
outside the exception dispatcher; on Linux chained host signal handlers
classify faults by REG_TRAPNO.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
Resolves docs/dev/debt/libkernel.md: main's sigaction entry (SIGPIPE outside Windows) and this branch's signal entry, which points to libSceLibcInternal for siginterrupt.
Co-Authored-By: Claude Opus 5.5 <[email protected]>
A module started as a dependency or by the sweep kept its start result, so a later
load of it by the title returned that result instead of 0 (guest_deferred_module_*
failed in the Windows job with 'module start result').
A swept module whose start throws is skipped with a log line, whatever it throws, and
the load that triggered the sweep, and later loads, still succeed.
Concurrent first loads now wait for the one sweep; a failed sweep is retried by the
next first load. The sweep no longer skips the module that triggered it, so a swept
module that depends on it starts after it, and the trigger keeps its start result.
A deferred module that only another deferred module names (PSNCommon, needed by
PSNCore) started after the plugins that use it (SPFXUnityPlugin) and crashed
Soul Hackers 2 on Windows. The first title load of any deferred module now starts
every deferred module some module depends on, in dependency order, with that
load's start arguments, and logs the sweep. Boot is unchanged.
On Windows a module the executable needs or imports from stays deferred, but its
dependencies were deferred too and started only when the title loads it, so a title
that calls it first ran them uninitialised (Soul Hackers 2, #15370 rerun). They start
at startup again, as on main. The loader prints one line per deferred start.