Skip to content

fix(libkernel): support POLLPRI on Windows sockets - #4525

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
Lorkydey:fix/poll-priority-windows
Oct 13, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
Lorkydey:fix/poll-priority-windows

Conversation

@Lorkydey

@Lorkydey Lorkydey commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

What

Fix the Windows socket stop poll: POLLPRI is not supported by WSAPoll. Ask WSAPoll for POLLRDBAND when the guest requests POLLPRI, and for POLLRDNORM when it requests POLLIN, keeping urgent data separate from ordinary readability. Returned flags are still masked by the guest's requested events. Linux keeps its native mapping.

Carries screamm's 1a20b493 implementation and urgent-data tests with the original author preserved. Rebased onto main 2a2a3dc650b9245fb0fb9b088afb1a6c27637f7d at head 5db1d8d5e933c5096ed87530898c2989becec4d7, after #4391 merged. The resolution retains main's allocated socket descriptors, its descriptor lookup, the pipe-poll tests from #3644, all urgent-data tests and both sets of limitations in docs/dev/debt/libkernel.md. The Windows event mapping itself is unchanged.

The mapping follows WSAPoll's documented flags and FreeBSD 11.4's sopoll_generic. Winsock keeps reporting urgent data until it is read with MSG_OOB, whereas FreeBSD stops once the normal stream passes the urgent mark. The existing debt entry retains that difference and the guest's unsupported MSG_OOB send/receive behavior. This removes a runtime refusal; it adds no newly implemented export to the progress scanner.

Title evidence

Tested

  • Windows 11 Pro 26100, WinLibs MinGW-w64 GCC 15.2.0 r7, Ninja, Release, BUILD_TESTING=ON: full runtime (libs), relinker and the four focused targets build at exact head 5db1d8d5e. Local ANYPS5_ENABLE_SPIRV_TOOLS=OFF.
  • guest_poll, guest_socket_pair, guest_udp and guest_sce_net each pass five consecutive runs, retaining pipe, descriptor and urgent-data coverage.
  • Windows negative control: the combined test with only Udp.cpp replaced by main 2a2a3dc65 fails at poll: POLLPRI is not supported by WSAPoll. Restoring the PR source and rebuilding passes all four tests five times again.
  • Public validation of this exact revision: Linux and Windows full runtime/relinker builds and all four tests repeated five times pass. The Windows job also verifies the main negative control before restoring/retesting the source. Conventions and whitespace pass on both hosts; test registration passes on Linux. The workflow lives on a separate CI branch and explicitly checks out the PR source.
  • Local conventions, test registration and git diff --check pass. These are focused checks, not the full CTest suite. Full upstream jobs require a maintainer dispatch. No new title run on this rebased revision is claimed.

Merge order

#3644 and #4391 are now merged and are included through the main baseline. The earlier proposed ordering with #4391 is therefore superseded. This rebase retains its descriptor allocation/read/write behavior and validates the combined socket tests. #3649 and #4351 remain closed; no socket-fstat implementation from #4351 is carried here.

Remaining open-PR overlaps

After this rebase, pairwise merges against #4903 2cd842efa (socket fstat) and #4933 bc299f299 (polling libSceNet sockets) conflict only in docs/dev/debt/libkernel.md. Their source changes merge textually with this head; this is not a combined runtime validation.

Proposed order: #4525 first, then those branches rebase; that order is not yet agreed with their authors. For #4903, retain its socket-stat limitations and this PR's urgent-data limitations. For #4933, retain its libSceNet socket lookup/ownership and mixed-descriptor support, while removing the obsolete Windows POLLPRI refusal and keeping POLLPRI -> POLLRDBAND, POLLIN -> POLLRDNORM, requested-event masking, pipe tests and urgent-data tests. If either lands first, this PR will need the small debt resolution and focused socket tests again. Neither is a runtime prerequisite for this standalone fix.

Checklist

@Dextroid17 Dextroid17 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.

On Linux this path is not compiled, so a green here cannot stand for the Windows behaviour — and the report side cannot drift from this change. The change sits inside #ifdef _WIN32: guest_poll passes at the head (100% of 1, exit 0) and passes identically with the parent's Udp.cpp in place, which is the expected no-op rather than evidence either way.

What I could check without a Windows host:

  • revents is filled by walking the same table the request side uses — core/libs/prx/libkernel/Socket/src/Udp.cpp:987-989 at 35893ea90:
for (const auto& flag : RequestFlags)
    if ((entry.events & flag.guest) && (native[i].revents & flag.native))
        entry.revents = static_cast<short>(entry.revents | flag.guest);

so re-pointing guest 0x1/0x2 at POLLRDNORM/POLLRDBAND changes what is reported as well, with no second table to keep in step.

  • The Windows constants the mapping rests on, from mingw-w64's winsock2.h: POLLRDNORM 0x0100, POLLRDBAND 0x0200, POLLIN (POLLRDNORM | POLLRDBAND), POLLPRI 0x0400. POLLIN is a union there, so narrowing it to POLLRDNORM is what preserves the guest's distinction; POLLPRI is a distinct flag rather than an alias of POLLRDBAND, so sending the priority request to the priority-data flag is a mapping rather than a redefinition.
  • The refusal this PR removes is the only one on this request path. The file's remaining throws are the unrelated socketpair and sendmsg refusals, plus the equeue WSAPoll failure at Udp.cpp:244 — a different call.

Informational, body only: the windows job in .github/workflows/build.yml is gated to push/workflow_dispatch (a maintainer can dispatch it for a PR number), so an ordinary PR run does not compile this branch, the Windows-only half of the new test included.

Written with AI assistance.

Hermes Agent 🤖 at your service

@xXPBSXx

xXPBSXx commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

Windows test: head 35893ea90 merged onto current main d592d54e1 (clean merge, no conflicts). Windows 10, MinGW GCC (WinLibs), Ninja Release, -j2: full build 0 errors; ctest with the filter guest_poll: guest_poll passed (1 test(s), 0 failed); python tools/check_conventions.py --base upstream/main passed. I did not run the new tests against main without the change.

AI-assisted (Claude Code).

@Dextroid17

Copy link
Copy Markdown
Contributor

This is the half I could not supply, and it is the same head I read (35893ea90). On this host the change is inside #ifdef _WIN32, so my run was a no-op — which is why I said a green here cannot stand for the Windows behaviour. Your run is that evidence, and it is now on the record.

One line is still missing on that side: the red arm. guest_poll passes at the head and passes identically with the parent's Udp.cpp in place, so on Windows too the green alone cannot separate the new mapping from a no-op. Running your filter against the parent's Udp.cpp with this test kept would, and it is cheap while the Windows tree is up.

Written with AI assistance.

@github-actions github-actions Bot added needs rebase Conflicts with main, rebase needed labels Oct 12, 2026
@oneandonlydean oneandonlydean self-assigned this Oct 12, 2026
@Lorkydey
Lorkydey force-pushed the fix/poll-priority-windows branch from 35893ea to 32b2eda Compare October 12, 2026 20:17
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 12, 2026
@github-actions github-actions Bot mentioned this pull request Oct 12, 2026
9 tasks done
@Lorkydey

Copy link
Copy Markdown
Contributor Author

@DariusHQ @pushkarreddyy @milescoviello

Coordinating the overlap with #3644: #4525 carries the Windows socket POLLPRI mapping and urgent-data tests. The overlap flagged here is in GuestPoll.cpp and the shared poll debt entry; the pipe-readiness behavior belongs to the pipe-poll PR.

I propose landing the selected pipe-poll fix and #4351 before #4525. As Marc noted on #3649, #3644 and #3649 still need a maintainer choice, and #3649 also needs coordination with #4391. My current Depends on lists #3649 and #4351; I can update the pipe dependency if #3644 is selected instead.

After the agreed prerequisites land, I will rebase #4525, keep both the pipe and urgent-data tests (including their imports, declarations and calls), combine the debt descriptions, and preserve the Windows POLLIN -> POLLRDNORM / POLLPRI -> POLLRDBAND mapping. I will rerun the focused Windows/Linux tests after integration. This comment does not claim a combined validation with the current pipe-poll heads.

For this PR alone, the requested Windows negative control is now recorded in CI: replacing Udp.cpp with the parent makes the new test fail at the old POLLPRI refusal; restoring the patch makes all four focused tests pass three times.

Does that ordering work for you, subject to the maintainer's pipe-poll choice?

AI-assisted: yes (Codex).

@Dextroid17

Copy link
Copy Markdown
Contributor

Thanks for pointing at the Windows negative control. One thing to line up before it counts for this head:

  • The linked run (Lorkydey/AnyPS5 run 38302727370) reports head ede071e5784089def9b23f9c721d598ee7a4c64b.
  • This PR's head is now 32b2eda2ca (single commit, "fix(libkernel): accept POLLPRI on guest sockets under WSAPoll"), updated 2026-10-12T22:17:56Z.

Could you confirm that the parent Udp.cpp swap (guest_poll fails at the old POLLPRI refusal, passes with the patch) was run on 32b2eda2ca? If the commit changed after that run, the red arm needs a re-run on the current head. I have no Windows host here, so I cannot reproduce it myself.

AI-assisted: yes (Claude Code).

@Lorkydey

Copy link
Copy Markdown
Contributor Author

@Dextroid17 Yes, the Windows negative control was run on the current PR head, 32b2eda2ca394a43d46d60f09ea08a469ba7bd4c.

ede071e578 is the commit containing the separate validation workflow. The Windows job explicitly checks out the PR commit at line 18, and its checkout log confirms 32b2eda2ca394a43d46d60f09ea08a469ba7bd4c.

In that checkout, the negative-control step replaces only Udp.cpp with HEAD^ while retaining the new test. In the Windows job, guest_poll fails at poll: POLLPRI is not supported by WSAPoll; after restoring and rebuilding the PR source, all four focused tests pass three times.

The PR head still matches that tested commit. Thanks for checking the provenance!

AI-assisted: yes (Codex).

@Dextroid17

Copy link
Copy Markdown
Contributor

@Lorkydey Thanks, you're right, and I checked the run log rather than taking the link on trust.

  • The checkout step in run 38302727370 (job 114989316200) reads HEAD is now at 32b2eda fix(libkernel): accept POLLPRI on guest sockets under WSAPoll, which is the current PR head.
  • The red arm is in the same job. With the parent Udp.cpp and the new test kept, guest_poll exits 0xc0000409 with poll: POLLPRI is not supported by WSAPoll. After the patch is restored, ctest -R "^(guest_poll|guest_socket_pair|guest_udp|guest_sce_net)$" --repeat until-fail:3 runs, so the green arm is recorded too.

That closes the provenance question, and the negative control is now on the record for this head. I still have no Windows host, so this is evidence from your CI log, not a run of mine.

AI-assisted: yes (Claude Code).

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 13, 2026
@babyhuey

Copy link
Copy Markdown
Contributor

Title check on Windows 11 (WinLibs GCC 15.2, RTX 3080) now that #3644 is merged. On main d1fd937, three titles that used to stop at poll: descriptor N is not a socket stop at poll: POLLPRI is not supported by WSAPoll instead. This PR conflicts with main now, so I merged it locally (fork test/verify-pollpri, 0343f29). Udp.cpp merges clean; I kept main's GuestPoll.cpp for the merge and unioned the debt line, so this PR's new tests weren't part of these runs.

With it the POLLPRI throw is gone in all three:

  • Nuvio Max'd (PPSA99288, --trap-sdk-syscall-stubs): renders for the full 60 s, [SX] 59.9 fps, worst frame 20.0-21.3 ms, no throw. This is the first time it renders on Windows.
  • ProsperoAI (PPSA99004, --trap-sdk-syscall-stubs): renders and sits in its UI for 60 s, about 500 submissions per 10 s window, no throw. Its update check fails quietly.
  • ProsperoTV (PPSA99003): gets into its HUI (swapchain, fonts, [HUI] pad open), then stops at a separate Windows-only throw, fcntl: record locks are not implemented on Windows, command=12, fd=4 (F_SETLK on a file).

The RequestFlags change maps guest POLLIN to POLLRDNORM and POLLPRI to POLLRDBAND on Windows. Results are still masked by entry.events, so the shared POLLRDNORM bit doesn't report anything the guest didn't ask for.

@Lorkydey

Copy link
Copy Markdown
Contributor Author

@MarcZX100 A coordination note for #4391: #4525 is now rebased onto main c13dc7e6b at bf51a206c, retaining both the merged #3644 pipe tests and screamm's urgent-data tests. The Windows POLLIN -> POLLRDNORM and POLLPRI -> POLLRDBAND mapping remains independent of the socket descriptor allocation scheme.

Would #4525 before #4391 work for your next rebase? The combined GuestPoll.cpp should retain both groups of tests and the native socket includes/linkage, and the debt entry needs both the allocation/pipe semantics and the urgent-mark limitation. #4391 already conflicts with main, so I am not treating a pairwise merge conflict as a runtime dependency or claiming a combined build. The standalone rebased #4525 passes the four focused Windows tests three times, including the main-with-new-tests negative control.

AI-assisted: yes (Codex).

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 13, 2026
@Lorkydey

Copy link
Copy Markdown
Contributor Author

@babyhuey Thanks for the title retests! Rebased onto main c13dc7e6b at bf51a206c, retaining both #3644's pipe tests and this PR's urgent-data tests, plus both debt descriptions. #3649 and #4351 are closed, so I removed those obsolete dependencies; no socket-fstat code from #4351 is included.

@Dextroid17 The negative control has also been rerun for this new head. Windows and Linux build libs, relinker and the focused targets; guest_poll, guest_socket_pair, guest_udp and guest_sce_net each pass three times. On Windows, replacing only Udp.cpp with parent main while keeping the combined test fails at the old POLLPRI refusal; restoring it makes the tests pass again. Linux is the non-regression check.

Both jobs explicitly check out bf51a206c6c80c0646605fbcfd44a588c46c9f3d; the separate workflow commit is 6ad548f0a. The description now links your title evidence separately from these focused tests. I have not rerun the titles on this rebased head or run the full CTest suite.

AI-assisted: yes (Codex).

@Dextroid17

Copy link
Copy Markdown
Contributor

Thanks for rerunning. I confirmed the PR head is bf51a206c, the commit you named. Run 38341096951's head is the workflow commit 6ad548f0a, so I'm treating its Windows and Linux passes as your CI evidence, not a run of mine. I have no Windows host, so I can't verify the Windows result myself.

@babyhuey

Copy link
Copy Markdown
Contributor

Native Windows check of the exact head bf51a20 (Windows 11, RTX 3080, WinLibs GCC 15.2, Release), as there was no Windows host on the earlier review:

  • guest_poll, guest_socket_pair, guest_udp and guest_sce_net each pass 5/5 (--repeat until-fail:5). No warnings in Udp.cpp or GuestPoll.cpp.
  • Udp.cpp is unchanged from the head I ran yesterday; what's new is the extra tests in GuestPoll.cpp and ws2_32 for guest_poll_tests.

The same three titles on this head alone (#4480 is merged now, so ProsperoTV needs nothing else), each running the full 60 s with no throw:

  • ProsperoTV (PPSA99003): renders its menu, [TV] frames=600 mean=23.36ms ... draws=2 shapes=407.
  • ProsperoAI (PPSA99004, --trap-sdk-syscall-stubs): renders and sits in its UI, about 590 submissions per 10 s window.
  • Nuvio Max'd (PPSA99288, --trap-sdk-syscall-stubs): [SX] 59.9 fps, worst frame 21.6 ms.

On main c13dc7e all three stop at poll: POLLPRI is not supported by WSAPoll.

@babyhuey

babyhuey commented Oct 13, 2026 •

Copy link
Copy Markdown
Contributor

More titles for this: ProsperoEden (PPSA99008, discussion #4852), PSXS5 (PPSA97510), SwanStationPS5 (PPSA98510) and ProsperoRadio (PPSA99001). On main (Windows 11, catalog releases; ProsperoEden with --trap-sdk-syscall-stubs) each exits with 0xC0000409 on poll: POLLPRI is not supported by WSAPoll, shortly after start-up.

With bf51a20 merged onto main (clean merge), the throw is gone and each runs the full 60 s:

  • ProsperoEden (on 7e181fc) draws its launcher at 60 fps. It then stops only for user content (prod.keys, firmware, games).
  • On ea2bbef, PSXS5 and ProsperoRadio render at 59.9 fps and SwanStationPS5 at 119.8 fps, with no throws.

@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 13, 2026
@LeandroLP23

Copy link
Copy Markdown
Contributor

This unblocks four catalog titles on Windows. Windows 11 (26300), Radeon 860M, WinLibs GCC 15.2.0, Release. Head bf51a206c merged onto main 88107b7de. Each title is relinked with --windows --trap-sdk-syscall-stubs and run for 60 s.

Title main main + this PR
PSXS5 (PPSA97510) poll: POLLPRI is not supported by WSAPoll, exit after 9 s runs 60 s, 32 FPS
SwanStationPS5 (PPSA98510) same stop, after 8 s runs 60 s, 29 FPS
ProsperoEden (PPSA99008) same stop, after 8 s runs 60 s, 57 FPS
Nuvio Max'd (PPSA99288) same stop the UI runs 60 s at 43 FPS

Nuvio Max'd then hits abort() when the run is closed. Its log shows nothing failing before that, and the close comes after the point this PR changes, so I'm noting it, not counting it against the PR.

AI-assisted: yes (Claude Code)

@MarcZX10

Copy link
Copy Markdown
Contributor

Thanks for the coordination note. #4391 merged on October 13, so the proposed #4525-before-#4391 ordering is now moot; there is no remaining sequencing conflict from that PR. I see #4525 currently reports a conflict with main, so please keep the merged socket-descriptor changes and both groups of GuestPoll tests when updating it.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Needs a rebase: #4391 is merged and this now conflicts with it in core/libs/prx/libkernel/Socket/src/Udp.cpp and docs/dev/debt/libkernel.md. It gets a full build once it is clean.

Three catalog titles stop on Windows when they poll a guest socket for
POLLPRI|POLLOUT to see whether a non-blocking connect has completed:

- PPSA97510 PSXS5 (socket 0x10000002, thread gamedb, 13 s):
  what():  poll: POLLPRI is not supported by WSAPoll
- PPSA98510 SwanStation (sockets 0x10000003/0x10000002, threads gamedb
  and update): what():  poll: POLLPRI is not supported by WSAPoll
- PPSA99003 ProsperoTV ({0x10000001, POLLPRI|POLLOUT} at 5.3 s):
  what():  poll: POLLPRI is not supported by WSAPoll

FreeBSD's sopoll_generic (sys/kern/uipc_socket.c, freebsd-src 8c639945)
reports POLLPRI and POLLRDBAND alike, only while out-of-band data is
pending (so_oobmark or SBS_RCVATMARK). WSAPoll rejects POLLPRI in events
with WSAEINVAL but reports pending urgent data as POLLRDBAND, so on
Windows the guest POLLPRI is now asked of WSAPoll as POLLRDBAND and
POLLIN as POLLRDNORM (Winsock's POLLIN includes POLLRDBAND, which would
report urgent data as readable). Measured on this host: WSAPoll reports
POLLRDBAND after a peer's send(MSG_OOB), waits for it, and clears it once
the byte is read with MSG_OOB. Linux keeps polling POLLPRI on the host.

select needs no change: libkernel's select passes exceptfds as Urgent to
the libSceNet poller, which already asks WSAPoll for POLLRDBAND, and it
does not take libkernel guest sockets on either host.

The guest send and recv refuse MSG_OOB, so urgent data only comes from a
peer outside the guest's sockets; guest_poll now sends it from a host
socket and checks that a connected pair and a non-blocking connect
report POLLOUT and not POLLPRI. TechnicalDebt records where Winsock's
answer differs from FreeBSD's once the stream passes the mark.

Depends on boykopovar#3649 (poll on file descriptors), whose two commits this
branch carries, since the titles reach this stop only with it.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@Lorkydey
Lorkydey force-pushed the fix/poll-priority-windows branch from bf51a20 to 5db1d8d Compare October 13, 2026 09:24
@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 13, 2026
@screamm

screamm commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Windows validation with title evidence (Windows 11 Pro 26220, WinLibs MinGW-w64 GCC 15.2.0 r7, Ninja, Release, BUILD_TESTING=ON, full build including libs; base main d379bfd0 with #5025 applied for the title runs (without it current main cannot load libkernel_sys.prx on Windows, #4877)): the earlier head bf51a206 merged onto d379bfd0 (two trivial conflicts: main already looks up the socket earlier in Udp.cpp, so the duplicate Find block and main's POLLPRI throw go; the debt sentence applied to main's poll bullet). Code matches my fix/libkernel-poll-pollpri-sockets commit (NativePollIn/NativePollPriority, throw removed); the debt text is shorter. guest_poll 3/3; suite 685/688 with conventions_function_bodies and guest_sce_net passing serially and patched_libraries being main's #4877 failure; conventions and git diff --check pass. The rebased head 5db1d8d5 has the same code, merges cleanly onto 075169f7 and passes conventions, but I did not rebuild it.

Titles (before, main + #5025: all four end with what(): poll: POLLPRI is not supported by WSAPoll at 3 to 5.5 s): with this PR all four run the whole minute with no stop line: PSXS5 FPS: 25.53 (1400), SwanStation FPS: 34.75 (1714), ProsperoTV FPS: 23.63 (686), ProsperoRadio FPS: 21.35 (736) (frame rates lowered by other builds on the host; ProsperoTV/Radio staged with app0/eboot.bin, see #5040).

@oneandonlydean
oneandonlydean merged commit 1841444 into boykopovar:main Oct 13, 2026
11 checks passed
MarcZX10 pushed a commit to MarcZX10/AnyPS5 that referenced this pull request Oct 13, 2026
Titles that bundle OpenSSL load the console's CA file from the sandbox
directory and fail every HTTPS request without it. ProsperoRadio
(PPSA99001, libcurl 8.18.0 + OpenSSL 3.5.2) on main + boykopovar#4796 + boykopovar#4525:

  [ProsperoRadio][http] https://all.api.radio-browser.info/json/servers: Problem with the SSL CA cert (path? access rights?) (error adding trust anchors from file: /gkbHtXc3Wq/common/cert/CA_LIST.cer)

SwanStation (PPSA98510) stops on the same file (boykopovar#5001).

The guest path resolver now accepts exact-path providers, and libkernel
registers one for /<sceKernelGetFsSandboxRandomWord()>/common/cert/CA_LIST.cer.
On first use it writes a PEM bundle once per process to
cert_cache/CA_LIST.cer in the run directory, read-only: on Windows the
current user's ROOT and CA system stores, elsewhere SSL_CERT_FILE or the
first distro bundle that exists. Without a certificate the path keeps
resolving under the guest root and does not exist, as before. Every other
path under the sandbox word is unchanged. The console file's format and
the rest of its common/cert directory are unverified and recorded in
docs/dev/debt/libkernel.md.

With this change, boykopovar#4796, boykopovar#4525 and boykopovar#5025 on Windows 11, 60 s each:

  [ProsperoRadio][http] 11846160 bytes in 1458 ms: 1161 passes, 803 waits (679 woken) for 1428 ms
  [ProsperoRadio][catalog] page offset=0 bytes=11846160 objects=10000 accepted=9549 total=9549
  ...
  [ProsperoRadio][catalog] page offset=60000 bytes=1712035 objects=1494 accepted=1436 total=59371

  [SwanStationPS5] update: latest 1.2.5, this 1.1.3, available
  [SwanStationPS5] gamedb: index written

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
santhoshkumar-dev pushed a commit to santhoshkumar-dev/AnyPS5 that referenced this pull request Oct 14, 2026
Titles that bundle OpenSSL load the console's CA file from the sandbox
directory and fail every HTTPS request without it. ProsperoRadio
(PPSA99001, libcurl 8.18.0 + OpenSSL 3.5.2) on main + boykopovar#4796 + boykopovar#4525:

  [ProsperoRadio][http] https://all.api.radio-browser.info/json/servers: Problem with the SSL CA cert (path? access rights?) (error adding trust anchors from file: /gkbHtXc3Wq/common/cert/CA_LIST.cer)

SwanStation (PPSA98510) stops on the same file (boykopovar#5001).

The guest path resolver now accepts exact-path providers, and libkernel
registers one for /<sceKernelGetFsSandboxRandomWord()>/common/cert/CA_LIST.cer.
On first use it writes a PEM bundle once per process to
cert_cache/CA_LIST.cer in the run directory, read-only: on Windows the
current user's ROOT and CA system stores, elsewhere SSL_CERT_FILE or the
first distro bundle that exists. Without a certificate the path keeps
resolving under the guest root and does not exist, as before. Every other
path under the sandbox word is unchanged. The console file's format and
the rest of its common/cert directory are unverified and recorded in
docs/dev/debt/libkernel.md.

With this change, boykopovar#4796, boykopovar#4525 and boykopovar#5025 on Windows 11, 60 s each:

  [ProsperoRadio][http] 11846160 bytes in 1458 ms: 1161 passes, 803 waits (679 woken) for 1428 ms
  [ProsperoRadio][catalog] page offset=0 bytes=11846160 objects=10000 accepted=9549 total=9549
  ...
  [ProsperoRadio][catalog] page offset=60000 bytes=1712035 objects=1494 accepted=1436 total=59371

  [SwanStationPS5] update: latest 1.2.5, this 1.1.3, available
  [SwanStationPS5] gamedb: index written

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
santhoshkumar-dev pushed a commit to santhoshkumar-dev/AnyPS5 that referenced this pull request Oct 14, 2026
Titles that bundle OpenSSL load the console's CA file from the sandbox
directory and fail every HTTPS request without it. ProsperoRadio
(PPSA99001, libcurl 8.18.0 + OpenSSL 3.5.2) on main + boykopovar#4796 + boykopovar#4525:

  [ProsperoRadio][http] https://all.api.radio-browser.info/json/servers: Problem with the SSL CA cert (path? access rights?) (error adding trust anchors from file: /gkbHtXc3Wq/common/cert/CA_LIST.cer)

SwanStation (PPSA98510) stops on the same file (boykopovar#5001).

The guest path resolver now accepts exact-path providers, and libkernel
registers one for /<sceKernelGetFsSandboxRandomWord()>/common/cert/CA_LIST.cer.
On first use it writes a PEM bundle once per process to
cert_cache/CA_LIST.cer in the run directory, read-only: on Windows the
current user's ROOT and CA system stores, elsewhere SSL_CERT_FILE or the
first distro bundle that exists. Without a certificate the path keeps
resolving under the guest root and does not exist, as before. Every other
path under the sandbox word is unchanged. The console file's format and
the rest of its common/cert directory are unverified and recorded in
docs/dev/debt/libkernel.md.

With this change, boykopovar#4796, boykopovar#4525 and boykopovar#5025 on Windows 11, 60 s each:

  [ProsperoRadio][http] 11846160 bytes in 1458 ms: 1161 passes, 803 waits (679 woken) for 1428 ms
  [ProsperoRadio][catalog] page offset=0 bytes=11846160 objects=10000 accepted=9549 total=9549
  ...
  [ProsperoRadio][catalog] page offset=60000 bytes=1712035 objects=1494 accepted=1436 total=59371

  [SwanStationPS5] update: latest 1.2.5, this 1.1.3, available
  [SwanStationPS5] gamedb: index written

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
santhoshkumar-dev pushed a commit to santhoshkumar-dev/AnyPS5 that referenced this pull request Oct 15, 2026
Titles that bundle OpenSSL load the console's CA file from the sandbox
directory and fail every HTTPS request without it. ProsperoRadio
(PPSA99001, libcurl 8.18.0 + OpenSSL 3.5.2) on main + boykopovar#4796 + boykopovar#4525:

  [ProsperoRadio][http] https://all.api.radio-browser.info/json/servers: Problem with the SSL CA cert (path? access rights?) (error adding trust anchors from file: /gkbHtXc3Wq/common/cert/CA_LIST.cer)

SwanStation (PPSA98510) stops on the same file (boykopovar#5001).

The guest path resolver now accepts exact-path providers, and libkernel
registers one for /<sceKernelGetFsSandboxRandomWord()>/common/cert/CA_LIST.cer.
On first use it writes a PEM bundle once per process to
cert_cache/CA_LIST.cer in the run directory, read-only: on Windows the
current user's ROOT and CA system stores, elsewhere SSL_CERT_FILE or the
first distro bundle that exists. Without a certificate the path keeps
resolving under the guest root and does not exist, as before. Every other
path under the sandbox word is unchanged. The console file's format and
the rest of its common/cert directory are unverified and recorded in
docs/dev/debt/libkernel.md.

With this change, boykopovar#4796, boykopovar#4525 and boykopovar#5025 on Windows 11, 60 s each:

  [ProsperoRadio][http] 11846160 bytes in 1458 ms: 1161 passes, 803 waits (679 woken) for 1428 ms
  [ProsperoRadio][catalog] page offset=0 bytes=11846160 objects=10000 accepted=9549 total=9549
  ...
  [ProsperoRadio][catalog] page offset=60000 bytes=1712035 objects=1494 accepted=1436 total=59371

  [SwanStationPS5] update: latest 1.2.5, this 1.1.3, available
  [SwanStationPS5] gamedb: index written

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
santhoshkumar-dev pushed a commit to santhoshkumar-dev/AnyPS5 that referenced this pull request Oct 17, 2026
Titles that bundle OpenSSL load the console's CA file from the sandbox
directory and fail every HTTPS request without it. ProsperoRadio
(PPSA99001, libcurl 8.18.0 + OpenSSL 3.5.2) on main + boykopovar#4796 + boykopovar#4525:

  [ProsperoRadio][http] https://all.api.radio-browser.info/json/servers: Problem with the SSL CA cert (path? access rights?) (error adding trust anchors from file: /gkbHtXc3Wq/common/cert/CA_LIST.cer)

SwanStation (PPSA98510) stops on the same file (boykopovar#5001).

The guest path resolver now accepts exact-path providers, and libkernel
registers one for /<sceKernelGetFsSandboxRandomWord()>/common/cert/CA_LIST.cer.
On first use it writes a PEM bundle once per process to
cert_cache/CA_LIST.cer in the run directory, read-only: on Windows the
current user's ROOT and CA system stores, elsewhere SSL_CERT_FILE or the
first distro bundle that exists. Without a certificate the path keeps
resolving under the guest root and does not exist, as before. Every other
path under the sandbox word is unchanged. The console file's format and
the rest of its common/cert directory are unverified and recorded in
docs/dev/debt/libkernel.md.

With this change, boykopovar#4796, boykopovar#4525 and boykopovar#5025 on Windows 11, 60 s each:

  [ProsperoRadio][http] 11846160 bytes in 1458 ms: 1161 passes, 803 waits (679 woken) for 1428 ms
  [ProsperoRadio][catalog] page offset=0 bytes=11846160 objects=10000 accepted=9549 total=9549
  ...
  [ProsperoRadio][catalog] page offset=60000 bytes=1712035 objects=1494 accepted=1436 total=59371

  [SwanStationPS5] update: latest 1.2.5, this 1.1.3, available
  [SwanStationPS5] gamedb: index written

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
RINNECODER added a commit to RINNECODER/AnyPS5 that referenced this pull request Oct 17, 2026
…hroughput (#530)

* fix(libSceNet): read SO_RCVTIMEO and SO_SNDTIMEO as a timeval in sceNetSetsockopt

sceNetSetsockopt took the BSD timeout options, SO_SNDTIMEO (0x1005) and
SO_RCVTIMEO (0x1006), like Sony's 0x1105 and 0x1106: as an int of
microseconds read from the first four bytes. A caller passing a struct
timeval got tv_sec taken as microseconds, so {0, 100000} meant to wait
100 ms became 0 and disabled the timeout, and the receive blocked until
data came.

On the console 0x1006 takes a timeval, as FreeBSD 11.4's sosetopt does.
ProsperoLight (PPSA99002) gives it {0, 100000} through sceNetSetsockopt,
and its log from a console (firmware 12.20) shows Moonlight's receive
timing out every 100 ms before the first packet ("Received first video
packet after 400 ms"). Sony moved only these two timeval options to
0x1105 and 0x1106, as ints. On AnyPS5 the receive never times out, so
ProsperoLight's receive threads never wake when the PC stops sending and
LiStopConnection never returns: the stream screen freezes when a session
ends from the PC side. Steam Remote Play (PPSA99350) sets {0, 10000} the
same way and stays on "THE PC DID NOT ANSWER" when the PC doesn't reply.

0x1005 and 0x1006 now go through the timeval path that setsockopt() on a
libSceNet socket already uses (EINVAL for a value shorter than a timeval,
EDOM for a negative or out-of-range one). sceNetGetsockopt gives them
back as a timeval cut to the caller's length, as FreeBSD's sooptcopyout
does. 0x1105 and 0x1106 keep taking an int of microseconds.

* docs(debt): sync debt documentation structure with upstream

* fix(libSceNet): let a datagram receive on an unbound socket wait on Windows

sceNetRecv, sceNetRecvfrom and sceNetRecvmsg called Winsock's receive
straight away. Winsock fails a receive on a socket with no local address
with WSAEINVAL, so on Windows the call returned EINVAL at once. On the
console the receive waits: FreeBSD 11.4's soreceive_dgram sleeps on the
receive buffer whether or not the socket has an address, returns
EWOULDBLOCK for a non-blocking socket, and a send from another thread
binds the socket so the reply can arrive.

Steam Remote Play (PPSA99350) relies on that. Its stream library opens
its discovery socket, starts receiving on a worker thread, and binds the
socket only when another thread sends the discovery broadcast. On
Windows the worker got EINVAL, took it as fatal and closed the socket
before the broadcast went out, so the title never found a PC running
Steam.

On Windows a receive on a datagram socket with no local address now
waits until a bind, connect or send gives it one, checking every 10 ms.
A non-blocking socket fails with EAGAIN at once, and the receive timeout
ends the wait with EAGAIN. An abort or close ends the wait, and the host
receive then fails as before. Once the socket has an address it is noted
as bound, so later receives skip the check, and a later sceNetBind fails
with EINVAL as it does on the console.

* fix(shader): flush v_cvt_pknorm_*_f16 denormal inputs by FLOAT_MODE

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

* refactor(libSceNet): wait for a local address after sceNetRecvmsg's socket type check

* feat(libSceAppContent): implement sceAppContentGetAddcontDownloadProgress

The signature (uint32_t service label, const NpUnifiedEntitlementLabel*,
progress*) follows SharpProspero Interop/AppContent/AppContent.cs.
dlc_emu dlc_content.cpp (fcf69b16) answers PARAMETER for a null label or
progress and NOT_FOUND for a label that is not installed additional
content. No additional content is ever installed here, as
sceAppContentAddcontMount, sceAppContentAddcontEnqueueDownload and
sceAppContentAddcontDelete already model, so every other call answers
NOT_FOUND and the progress, whose 16-byte layout SharpProspero gives,
is never written.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* perf(shader): intersect dominator sets as bitsets

Structurizing recomputes dominators after every CFG rewrite, and each block started from a vector of every block id. The same fixed point now runs on bitsets and still writes the sorted id lists.

Co-authored-by: Cursor <cursoragent@cursor.com>

* test(relinker): run the file writer's replacement test on a copy of itself

The running-executable replacement test copied /bin/sleep under the
names "running" and "leftover" and started the copy. On Ubuntu 26.04
/bin/sleep is the uutils multi-call coreutils binary, which picks the
utility from the file name of the path it was started through, not
from argv[0], so the copy printed "coreutils: unknown program
'running'" and exited, and file_writer_binary and file_writer_text
failed without ever replacing a running executable. The test now
copies its own executable and starts it with a "wait" argument that
sleeps, so it no longer depends on how a system binary reads its name.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(ajm): honor Opus gapless resets

* fix(ajm): preserve live decoder handles across ID wrap

* feat(libSceNpPartner001): answer sceNpHasEAAccessSubscription without an EA Access server

Co-authored-by: Cursor <cursoragent@cursor.com>

* perf(libSceSysmodule): cache the unwind region of loaded images on Windows

sceSysmoduleGetModuleInfoForUnwind called VirtualQuery and GetMappedFileNameA on every call. VirtualQuery on a large image section costs time proportional to the section (2 us for 16 KiB, 51 us for 8 MiB, 167 us for 32 MiB), and a title that unwinds exceptions while loading calls it for every frame of every throw.

The region and file name of an address inside an image of the Windows loader's module list are kept per region and used while the loader still reports the same image (base, time stamp and size). Other addresses are queried every time.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* feat(opus): decode at 8, 12, 16 and 24 kHz

Accept every creation rate listed by the public decoder research in
libSceOpusDec and libSceOpusCeltDec, resampling FFmpeg's 48 kHz output.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(libc): raise logic_error::_Doraise and _Xruntime_error

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(relinker): preserve weak imports in Linux guest modules

* fix(libSceNetCtl): answer the DHCP host name, PPPoE name and proxy server as empty strings

Since boykopovar#5056, sceNetCtlGetInfo throws for every info code it does not
model. Ghost of Yotei (PPSA26344) asks for code 12, the DHCP host name,
during boot and now aborts one second in.

The configuration boykopovar#5056 reports (wired, DHCP, HTTP proxy off) sets no
DHCP host name, no PPPoE user name and no proxy server, so codes 12, 13
and 20 now return 0 with an empty string. The Wi-Fi codes (5-10) and
the proxy port (21) still throw. GuestNetCtl checks the three empty
answers and keeps the throw check for the rest; the libSceNetCtl debt
line says the same.

* feat(libSceAmpr): implement __cxa_call_unexpected

__cxa_call_unexpected takes the in-flight exception's unwind header and
never returns, as in libcxxabi. No std::set_unexpected is exported and
the exception header's unexpected handler is never set, so the handler
is always the default one, which calls std::terminate. It therefore
forwards to libc's __cxa_call_terminate, which begins the catch and runs
the current terminate handler; a null header terminates in libc's
__cxa_begin_catch. libcxxabi's std::terminate would instead run the
terminate handler saved in the exception header at throw time; the two
differ only if std::set_terminate was called in between, which the debt
entry records.

The test shares the forked-child helper of the std::_Pad test, which now
takes the terminate handler to install.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(relinker): guard TLS instruction byte access at EOF

* feat(libSceLoginService): let PPSA34015 load without a missing module

FC 27 stops on Windows with Failed to load module / error 126 because this PRX is absent. Export Initialize and Terminate as no-ops and keep RequestDevices throwing until the buffer layout is known.

Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(libSceSysmodule): report the region of the queried page from a cached unwind region

VirtualQuery describes the pages from the queried address to the end of the run of equal pages, so the reported seg0 begins at the queried page. The cached entry returned the first lookup's page for every later address in the run. It now returns the queried page and the bytes up to the end of the cached run, which is what VirtualQuery returns.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(libSceSysmodule): look up an earlier page of a cached unwind region after a later one

The backward lookup added with the region fix compared the address with a page it could not reach and never ran. The test now queries an ntdll address three pages in, then the first page, then the pages between, and compares each with VirtualQuery. The lookups after the first fail on the cache before the region fix.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* docs(input): list the default keyboard and mouse bindings

INPUT_MAPPING.md names the actions and says that omitted actions keep their built-in bindings, but not what those bindings are. The table is read from InputMapping in core/libs/prx/libScePad/include/InputMapping.hpp.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* test(libc): keep intentional aborts away from the system crash handler

guest_host_standard_error and exception_runtime fork children that end in
SIGABRT on purpose. When kernel.core_pattern pipes cores to a handler, as
Ubuntu's apport and systemd-coredump do, the kernel starts it for every
dumpable crash even with RLIMIT_CORE at 0. apport takes about 1.1 s per
crash here, so guest_host_standard_error spent 2.3 s waiting and timed out
at its 10 s limit under parallel ctest load. Marking those children
non-dumpable on Linux skips the handler: 2.29 s to 0.01 s and
1.17 s to 0.01 s, with the same SIGABRT and message checks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(libkernel): support EVFILT_READ on the read end of a pipe

kevent threw for any descriptor that is not a guest socket. The read end
of a pipe now gets the descriptor knote, following FreeBSD 11's
filt_piperead: data is the number of buffered bytes and EV_EOF is set
once the write end is closed. GuestSockets::Ready falls back to the new
PipeReadState for a descriptor that is not a socket, and WaitAny waits on
the pipe with ppoll on Linux or in 1 ms WSAPoll slices on Windows, only
when the queue holds a pipe. On Windows the equeue waker now starts
Winsock itself, since a queue can wait on a pipe before any socket exists.

* feat(libkernel): add sceCoredumpConfigDumpMode as a throwing stub

PPSA16833 imports it from libkernel, and its executable does not load
while no library exports the NID. The signature is unknown, so it throws
if called, like sceCoredumpWriteUserString.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* refactor(libkernel): share the Windows pipe query between poll and kevent

PipeReadiness and PipeReadState both opened the pipe handle and asked
NtQueryInformationFile for its access mask and local information. Both
now go through QueryPipe, which keeps each caller's error prefix.

* docs(build): describe the [gputime] line and its command classes

* fix(libkernel): fail connect on a listening socket with EOPNOTSUPP

FreeBSD's soconnectat refuses a socket with SO_ACCEPTCONN set with EOPNOTSUPP (45). The host answers EINVAL on Windows and EISCONN on Linux, so connect() on a listening stream socket returned the host's error. Answer EOPNOTSUPP for a listening stream socket before the address is read.

* test(agc): wait for preparation workers before linking

* fix(libkernel): reject invalid ftruncate descriptors safely

* fix(ngs2): stop stale rendering after waveform callbacks

* fix(libkernel): use precise waits for select and poll on pipes on Windows

On Windows, select over pipes polls readiness in HostPoll and sleeps
std::this_thread::sleep_for(1 ms) between rounds, and poll with pipes
but no native sockets sleeps sleep_for(slice). winpthreads ends these
sleeps on 15.6 ms timer ticks (boykopovar#1471), so a guest select or poll with a
short timeout on an idle pipe waits about 15 ms per call instead of its
timeout, and a longer wait checks the pipes only every 15.6 ms.

Both paths now sleep with PreciseSleepUntil. Each sleep requests at
most 1 ms and ends no later than the deadline; the old HostPoll sleep
could pass its deadline by a whole tick. poll on pipes also stops
spinning through the last partial millisecond before its deadline,
where the remaining time truncated to 0 ms and no sleep was made.
Infinite timeouts still sleep 1 ms per round.

The pipes are now checked about every 1.5 ms instead of every 15.6 ms:
a pipe that becomes ready is noticed sooner, and a thread blocked on an
idle pipe wakes about ten times as often. A 1 ms poll on an idle pipe
returns after about 1.5 ms instead of spinning for 1 ms.

guest_poll times 20 polls with a 2 ms timeout on an empty pipe read end
and guest_select times 20 selects with a 1 ms timeout on it; each set
must take less than 200 ms. A 1 ms poll does not reach the old sleep,
because the remaining time truncates to 0 ms and the old loop spins
until the deadline, so the poll check uses 2 ms. On Windows Server 2025
both sets took 312 ms before this change and about 50 ms and 30 ms
after it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(shader): allow 32 sampler pairs per shader

A pixel shader of MXGP 26 (PPSA30839) uses 17 samplers, over the limit
of 16 sampler pairs. The sampler heap now holds 64 descriptors, ShaderData
grows by 32 sampler metadata records and the runtime ABI version moves
to 13.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* test(agc): honor the GPU selector in recorder fixtures

* perf(agc): draw an indirect rect list from its records on the GPU

ClassifyIndirectDraw sent every indirect rect-list draw to the CPU path
(non-vertex path), which reads the records on the CPU. When the GPU writes
those records earlier in the frame, the read waits for every batch up to
the producer: in Kena (PPSA01802) each such DRAW_INDIRECT waited about
15 ms, about once per frame.

A rect list on the vertex path is drawn by its generated tessellation
stages from three-vertex patches, with no draw-dependent constants, so the
records can be consumed on the GPU like any vertex-path draw. The
classifier now keeps a rect list without mesh or tessellation stages on
the GPU path, and Graphics::Draw accepts it. APS5_NO_RECT_INDIRECT=1
restores the CPU path.

agc_driver_rect_list_indirect submits a direct rect-list draw and the
same rectangle from a DRAW_INDIRECT record and requires the same bytes,
and a record without vertices to draw nothing; it passes on either path.
agc_driver_draw_offset_indices requires an auto indirect rect-list record
whose packet names no offset registers to be classified to the GPU.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(libSceNet): return 0 from an unbound datagram receive after shutdown or for zero bytes

On Windows a receive on a datagram socket with no local address waits
for one. A sceNetShutdown of the receive side now ends that wait, and
later receives return 0 at once; a zero-length receive returns 0 without
waiting. FreeBSD's soreceive_dgram returns 0 in both cases. Before, a
thread blocked in such a receive kept waiting after the socket was shut
down.

* test(libSceNet): receive on an unbound datagram socket that another thread binds or connects

The test covered a send that names the waiting socket. A bind and a
datagram connect from another thread name it too: each case now waits in
sceNetRecv on the unbound socket, binds or connects it, and checks that a
peer's datagram to the new address reaches the waiting receive.

* perf(libSceNet): end the wait for a local address when a bind, connect or send gives one

A receive on an unbound datagram socket checked the host socket every
10 ms, so it went on waiting up to 10 ms after another thread's bind,
connect or send had named the socket. sceNetBind now wakes the waiting
receives. On Windows a datagram connect or a send marks the socket bound
and wakes them once the host socket has its local address; a raw socket
that a send leaves without one stays unmarked and keeps waiting.

* fix(libSceNet): keep one receive timeout across the wait for a local address

When the address came during the wait, the host receive that followed
waited its whole SO_RCVTIMEO again, so a receive could take up to twice
the timeout. FreeBSD's soreceive_dgram sleeps once per timeout. Now the
receive waits for a datagram with WSAPoll only for what is left of the
timeout, and fails with EAGAIN when it runs out, as before. Nothing
changes when the socket already had an address or has no timeout.

* test(tools): add tool convention tests from upstream

* fix(tools): recognize markdown fences with CRLF endings

* fix(tools): keep duplicate export paths unquoted

* fix(tools): hide labels that do not fit treemap slivers

* docs(usage): state that the shader cache directory has no size limit

The Shader cache section says only that subdirectories of other versions are removed after 14 days. housekeeping() in ShaderDiskCache.cpp removes nothing from the current version, and no size or entry limit applies there.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>

* fix(tools): read workflow job keys at the indentation the file uses

The ci-gate check read a job's needs and if only two spaces deeper
than the job name. In a workflow indented by four spaces those keys
were never found, so a job gated with needs: eligibility and an if on
its outputs was reported as ungated. Read the keys at the indentation
of the job's first child instead.

* test(agc): wait for the second-store image itself to be pending

* test(agc): wait for pending result on the tested surface

* test(agc): cover pending surface identity in the shared wait

* docs(usage): describe the texture cache budgets and APS5_TEXTURE_CACHE_MIB

* test(agc): shut libc down before agc_shader_helpers returns

On Windows, agc_shader_helpers returned from main with the driver's
threads still running. ExitProcess ends them first, then the DLLs'
static destructors run and wait on what those threads left locked:
the async log's queue mutex in Driver::stop, DeviceUseGate's condition
variable in ~Driver, and condition variables in libkernel's statics.
The test hung after printing its result in about one ctest run of
three on a Radeon 860M (boykopovar#6791).

Like the other driver tests, it now runs LibcRunShutdown_nid_postfix
before returning, which stops the driver while its threads are alive.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(libkernel): validate the address before refusing connect on a listening socket

FreeBSD reads and checks the address (getsockaddr) before soconnect refuses a listening socket with EOPNOTSUPP, so a null or short address on a listener fails with the address error. Move the listener check after the address is read and keep it ahead of the family check.

* test(agc): require the GPU route for the indirect rect-list draws

agc_driver_rect_list_indirect compared the indirect draws' output with
the direct draws only, so it also passed when the records were read on
the CPU. Its records lived in a static array that is not guest memory,
so every indirect draw fell back to the CPU path as not imported.

The records now sit in a registered 64 KiB guest allocation, the test
turns on APS5_PROFILE_DRAW and reads the indirect-draw counters through
the new Graphics::IndirectDrawCounts, and it requires all four indirect
draws on the GPU path. It fails with APS5_NO_RECT_INDIRECT=1 and with
the IndirectDraw.cpp and Draw.cpp changes reverted (4 non-vertex path).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(libc): print the text that registers point at in Windows crash reports

Unreal titles end in their own libc fatal path with the UTF-16
LowLevelFatalError message in a register, and the crash report shows
only the first 64 bytes of it as hex words, so the message is lost
(boykopovar#4238: Demon Slayer PPSA03490, Stray PPSA02100).

For every general register that points at readable memory starting
with at least four printable ASCII characters, as UTF-16LE or as single
bytes, the report now prints the text up to a NUL, the first other
character, 512 characters or the end of readable memory (each page is
checked with VirtualQuery before it is read).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* feat(libSceVdecsw): block on SyncDecodeInput/Output like TrySync

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(libSceNpManager): export two unknown NIDs so PPSA34015 can load

Co-authored-by: Cursor <cursoragent@cursor.com>

* feat(libkernel): serve the console CA list from the host trust store

Titles that bundle OpenSSL load the console's CA file from the sandbox
directory and fail every HTTPS request without it. ProsperoRadio
(PPSA99001, libcurl 8.18.0 + OpenSSL 3.5.2) on main + boykopovar#4796 + boykopovar#4525:

  [ProsperoRadio][http] https://all.api.radio-browser.info/json/servers: Problem with the SSL CA cert (path? access rights?) (error adding trust anchors from file: /gkbHtXc3Wq/common/cert/CA_LIST.cer)

SwanStation (PPSA98510) stops on the same file (boykopovar#5001).

The guest path resolver now accepts exact-path providers, and libkernel
registers one for /<sceKernelGetFsSandboxRandomWord()>/common/cert/CA_LIST.cer.
On first use it writes a PEM bundle once per process to
cert_cache/CA_LIST.cer in the run directory, read-only: on Windows the
current user's ROOT and CA system stores, elsewhere SSL_CERT_FILE or the
first distro bundle that exists. Without a certificate the path keeps
resolving under the guest root and does not exist, as before. Every other
path under the sandbox word is unchanged. The console file's format and
the rest of its common/cert directory are unverified and recorded in
docs/dev/debt/libkernel.md.

With this change, boykopovar#4796, boykopovar#4525 and boykopovar#5025 on Windows 11, 60 s each:

  [ProsperoRadio][http] 11846160 bytes in 1458 ms: 1161 passes, 803 waits (679 woken) for 1428 ms
  [ProsperoRadio][catalog] page offset=0 bytes=11846160 objects=10000 accepted=9549 total=9549
  ...
  [ProsperoRadio][catalog] page offset=60000 bytes=1712035 objects=1494 accepted=1436 total=59371

  [SwanStationPS5] update: latest 1.2.5, this 1.1.3, available
  [SwanStationPS5] gamedb: index written

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* fix(libkernel): filter sandbox TLS roots and preserve path overrides

* test(agc): map GPU memory on fibers with and without a host stack

Since boykopovar#6003 a fiber with a context of 64 KiB or more runs on the
context itself, so the 64 KiB fiber of agc_driver_gpu_map_on_fiber
imports its mapping on a host thread on Windows too, and the test's
Windows-only expectation of no thread failed. The test now also maps
on a 16 KiB fiber, which keeps a host stack and imports on it on
Windows, and expects one import thread for the 64 KiB fiber on every
platform.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* fix(recompiler): hold 32 samplers in the runtime sampler heap

A pixel shader of PPSA16833 binds more than 16 samplers outside the
sampler tables. Each takes two heap entries, one per descriptor variant,
so the 32-entry heap refused it with "shader sampler pairs exceed runtime
heap capacity" and the title aborted when a new game started.

The heap now holds 64 entries (32 samplers). Its metadata array is part
of ShaderData, which grows from 14528 to 16064 bytes, still within the
16 KiB uniform buffer every Vulkan device supports; the runtime ABI
version moves to 13 so shaders cached with the old layout are rebuilt.
The overflow message names the sampler count.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* perf(metal): optimize Civ 7 128-bit detile vectors and elide non-indexed draw snapshots

* fix(tools): sync nid_names and exempt missing debt doc-links for macOS fork

---------

Co-authored-by: Yunus Shaikh <75296019+EagleBearerYS@users.noreply.github.com>
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: KernelPanicNT <76663133+KernelPanicNT@users.noreply.github.com>
Co-authored-by: wh1trope <noxerkrul@gmail.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Niko <nikobilger2000@gmail.com>
Co-authored-by: Ondra97 <47064087+Ondra97@users.noreply.github.com>
Co-authored-by: notaxeltv <notaxeltv@gmail.com>
Co-authored-by: JAB-dev <68183649+JAB-dev@users.noreply.github.com>
Co-authored-by: snipeTR <31975916+snipeTR@users.noreply.github.com>
Co-authored-by: Zinebyte <197974009+Zinebyte@users.noreply.github.com>
Co-authored-by: Celegans12 <53881228+Celegans12@users.noreply.github.com>
Co-authored-by: MarcZX100 <marczxrr@gmail.com>
Co-authored-by: xXPBSXx <20614131+xXPBSXx@users.noreply.github.com>
Co-authored-by: Hashaam Zafar <hashaam1217@gmail.com>
Co-authored-by: Felipe Arce <felipearce.2004@gmail.com>
Co-authored-by: Tamalero <11452991+Tamalero@users.noreply.github.com>
Co-authored-by: Josip Parlov <josipparlov@protonmail.com>
Co-authored-by: Hussein Kadhim <husseinkad.dev@gmail.com>
Co-authored-by: MarcZX100 <MarcZX100@users.noreply.github.com>
Co-authored-by: fdfawef324 <omarelfernani07@gmail.com>
Co-authored-by: Nahid Delic <nahe.delic84@gmail.com>
Co-authored-by: Romans Pokrovskis <motivated.it@gmail.com>
Co-authored-by: alfalfa-star <kosher-chive-take@duck.com>
Co-authored-by: Ishmam Ahmed <89687266+IshmamDC217@users.noreply.github.com>
Co-authored-by: LeandroLP23 <leandroplacidi@gmail.com>
Co-authored-by: screamm <davidrydgren@gmail.com>
Co-authored-by: Santhosh Kumar <santhosh-pc@outlook.com>
Co-authored-by: thuanquang <60096168+thuanquang@users.noreply.github.com>
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.

8 participants