Skip to content

feat(libkernel): implement sigaction - #1916

Merged
adriadam10 merged 3 commits into
boykopovar:mainfrom
johnmaia:feat/libkernel-sigaction
Oct 9, 2026
Merged

adriadam10 merged 3 commits into
boykopovar:mainfrom
johnmaia:feat/libkernel-sigaction

Conversation

@johnmaia

@johnmaia johnmaia commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

What

Implements sigaction (libkernel, NID KiJEPEWRyUY). @hikazey reports in #1578 that EVO-PLAYER PPSA99039 v0.11.0 stops here once its earlier imports resolve (#1838, #1634, #1714, #1641, #1857 merged locally). At start-up, projects/evoplayer/main.cpp installs:

  • a crash handler for SIGSEGV, SIGBUS and SIGABRT (SA_SIGINFO | SA_NODEFER);
  • a quit handler for SIGTERM, SIGINT and SIGHUP (flags 0).
int sigaction(int sig, const struct sigaction* act, struct sigaction* oact);
  • Layout: FreeBSD's struct sigaction, which is the handler union at 0, sa_flags at 8, the 128-bit sa_mask at 12, and 32 bytes in all. static_asserts pin it.
  • Recording: the handler, flags and mask of every signal from 1 to 128 are recorded and returned through oact.
    • As FreeBSD's kern_sigaction does, other signal numbers return EINVAL, and so does any handler but SIG_DFL on SIGKILL or SIGSTOP.
    • signal now shares this table and records SA_RESTART, as FreeBSD's libc signal does, so mixing the two calls reports consistent results.
  • Delivery: handlers without SA_SIGINFO on the six signals signal already delivers (SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTERM) run exactly as signal handlers do. SIG_IGN and SIG_DFL are applied to the host signal as before.
  • Recorded only: SA_SIGINFO handlers and the other signals (SIGBUS, SIGHUP, ...) are recorded but never called. Calling them needs FreeBSD's siginfo_t and ucontext_t; feat(libkernel): deliver sceKernelRaiseException on Linux #1431 builds the context for sceKernelRaiseException. For a signal like that, raise throws instead of terminating the process. sa_mask and the flags are not applied to delivery. All of this is in TechnicalDebt.

Overlap: none on exports. #1431 changes signal masks and exception delivery in other files (Exception.cpp, Thread.cpp), not Signals.cpp.

Tested

  • guest_signals, extended:
    • oact after signal(SIGTERM, SIG_DFL) reports SA_RESTART.
    • A plain SIGTERM handler with a mask in words 0 and 3 is delivered by raise, and round-trips through oact.
    • signal returns the handler sigaction set, and the reverse.
    • SA_SIGINFO handlers on 10, 1, 64 and 128 round-trip.
    • raise(SIGABRT) with an SA_SIGINFO handler throws.
    • Signals 0 and 129, and handlers on 9 and 17, return -1 with errno 22, while SIG_DFL on 9 and 17 succeeds.
    • Null act and oact are accepted.
  • Linux (Ubuntu 24.04.5, GCC 13.3, RX 7600): full ctest passes, 497/497.
  • Windows 11 (WinLibs GCC 15.2.0 r7): the signal and exception tests pass, 5/5.
  • No title was run here; EVO-PLAYER is a prebuilt release, and I don't run those on these machines.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed in TechnicalDebt
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • AI-assisted: yes

🤖 Generated with Claude Code

https://claude.ai/code/session_01DwFnKjMxmwGDWiuYYf1v4D

@github-actions

github-actions Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Progress report (c9d4261 → ab658fc)

➖ System libraries: 85.63% (+0.0%, +1 implemented functions)

✅ 1 implemented
Library Name
libkernel sigaction_nid_postfix

@rmz-24

rmz-24 commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Ran this on a title, since the PR says no title was run.

Windows 11, WinLibs GCC 15.2.0 r7, Release, --windows relink. EVO-PLAYER PPSA99039 v0.11.0 (release zip, SHA256 checked against the release's SHA256SUMS.txt). Base is main f145139 with #1838, #1634, #1714, #1641 and #1857 merged locally, the same set as in #1578.

  • Without this PR: FAIL: unresolved ELF import KiJEPEWRyUY from libkernel.prx (sigaction).
  • With this PR: start-up gets past it and stops at FAIL: unresolved ELF import DRGXpDDh8Ng from libkernel.prx (lstat).

guest_signals passes on the same build.

AI-assisted: yes

@johnmaia

johnmaia commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Checked with EVO-PLAYER v0.11.0 built from source (sainsaji/EVO-PLAYER-PS5 9715f6e: PS5 Payload SDK v0.42, pacbrew recipes and EVO's own FFmpeg 7.1.1, all from source), relinked on Linux (Ubuntu 24.04.5, RX 7600). The base was main f1451396 plus this PR, #1838, #1634, #1714, #1641, #1857 and #1529. EVO gets past KiJEPEWRyUY and stops later, while bringing up its resident decoders and before it opens a video output:

EVO boot: INFO  EVO boot: main() entry
EVO boot: INFO  EVO boot: Application::initialize entry
EVO boot: INFO  EVO vdec native: RESIDENT AVC decoder up  1920x1088 ...
EVO boot: INFO  EVO vdec native: HEVC config codec_type=974921 profile=1 max_level=123 max=1920x1088 dpb=auto depth=4
EVO boot: INFO  EVO vdec native: HEVC 1920x1088 [CreateDecoder]
terminate called after throwing an instance of 'std::runtime_error'
  what():  Videodec2: unsupported codec

As a control, preloading an abort-on-call stub for KiJEPEWRyUY over this PR's export stops it at sigaction after main() entry, so the call is made at start-up and this PR is what gets it through.

On Linux the title has 21 further unresolved imports (atoll, lstat, socketpair, tcgetattr, madvise, mkstemp, ...) that Windows only resolves on first call. I covered those with abort-on-call stubs for this run; none was called before the Videodec2 stop.

@johnmaia johnmaia mentioned this pull request Oct 9, 2026
9 tasks done

@klosixgaming-arch klosixgaming-arch left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Excellent, careful implementation. The POSIX contract is handled correctly: signal range validated (EINVAL outside 1–128), SIGKILL/SIGSTOP reject a non-default handler, and the disposition (handler + flags + mask) is recorded and reported back for all 128 signals even when only a subset are natively deliverable. The boundary is exactly right — SA_SIGINFO handlers and non-signal()-delivered signals are recorded but raise of them throws (rather than a silent no-op or wrong teardown), and the limitation is spelled out in TechnicalDebt instead of being hidden. The signal() path is refactored onto the same Install()/disposition store so signal and sigaction can't drift apart, and the struct layout is pinned with static_assert. The test matrix (query, set, raise, SIGKILL/SIGSTOP, SA_SIGINFO throw, error codes, signal↔sigaction interop) is thorough.

One robustness note: handlers[] is sized 32 while dispositions[] is sized 129, and Install indexes handlers[guest] directly. That's safe today only because NativeSignal returns 0 for every guest signal at/above that bound; a future NativeSignal case added past index 31 would be an out-of-bounds write. An assert(native && guest < (int)(sizeof handlers / sizeof handlers[0])) (or sizing handlers to MaxSignal+1) would make the invariant explicit.

Written with AI assistance.

@johnmaia

johnmaia commented Oct 9, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @klosixgaming-arch. handlers is now sized MaxSignal + 1, like dispositions (0c35d91c), so the bound no longer depends on which signals NativeSignal maps. guest_signals passes on Linux. And thanks @rmz-24 for the Windows run with the release build.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 9, 2026
@johnmaia
johnmaia force-pushed the feat/libkernel-sigaction branch from 0c35d91 to 83eedd9 Compare October 9, 2026 08:35
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 9, 2026
@johnmaia
johnmaia force-pushed the feat/libkernel-sigaction branch from 83eedd9 to b935947 Compare October 9, 2026 09:55
@adriadam10

Copy link
Copy Markdown
Collaborator

Checked on a build of the PR merged onto current main: full ctest 527/527, guest_signals passes, and without the change the test doesn't link, so it exercises it. Layout and EINVAL cases match FreeBSD's kern_sigaction. Confirmed on EVO-PLAYER by @rmz-24 (Windows) and the author (Linux).

Added one commit: the TechnicalDebt line said raise of any recorded-only signal throws, but for signals without a native mapping (SIGBUS, SIGHUP, ...) it still returns EINVAL as on main; only SA_SIGINFO handlers on the six delivered signals throw. Worth fixing the same sentence in the PR description. The red relinker (windows) job is hardware_oracle, which this PR doesn't touch. Merging.

@adriadam10
adriadam10 force-pushed the feat/libkernel-sigaction branch from b935947 to b11bf2d Compare October 9, 2026 21:53
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 9, 2026
johnmaia and others added 3 commits October 9, 2026 23:42
EVO-PLAYER (PPSA99039) v0.11.0 stops at sigaction once its earlier
imports resolve: it installs a crash handler for SIGSEGV, SIGBUS and
SIGABRT and a quit handler for SIGTERM, SIGINT and SIGHUP at start-up.

sigaction records the handler, flags and mask of signals 1 to 128 and
reports them back, with FreeBSD's EINVAL cases. signal shares the table
and records SA_RESTART, as FreeBSD's libc does. Plain handlers on the
signals signal already delivers run as signal handlers do; SA_SIGINFO
handlers and other signals are recorded only, and raise of such a
signal throws.

Assisted by Claude Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwFnKjMxmwGDWiuYYf1v4D
… dispositions

Assisted by Claude Code.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DwFnKjMxmwGDWiuYYf1v4D
@johnmaia
johnmaia force-pushed the feat/libkernel-sigaction branch from b11bf2d to ab658fc Compare October 9, 2026 22:49
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 9, 2026
@github-actions

github-actions Bot commented Oct 9, 2026 •

Copy link
Copy Markdown

Other open pull requests touch the same code. Merging one will break the other, or both implement the same thing. If this one builds on them, list them in Depends on.

Pull request Conflicting files (lines on main) Same exports Same new files
#1619 docs/dev/TechnicalDebt.md L387
#1652 core/libs/tests/GuestSignals.cpp L48
#1926 docs/dev/TechnicalDebt.md L387
#2500 docs/dev/TechnicalDebt.md L387

@adriadam10

Copy link
Copy Markdown
Collaborator

Checked on a build of the PR merged onto current main: full ctest 553/553, guest_signals passes, and without the change the test doesn't link. Layout and EINVAL cases match FreeBSD's kern_sigaction; confirmed on EVO-PLAYER by @rmz-24 (Windows) and the author (Linux). Merging once CI is green on this head.

@adriadam10
adriadam10 merged commit c5424ab into boykopovar:main Oct 9, 2026
8 checks passed
SleglJan pushed a commit to SleglJan/AnyPS5 that referenced this pull request Oct 10, 2026
…tion

feat(libkernel): implement sigaction
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants