Skip to content

feat(http2): complete asynchronous send and read - #11630

Open
edubox wants to merge 20 commits into
boykopovar:mainfrom
edubox:feat/http2-async-completions
Open

edubox wants to merge 20 commits into
boykopovar:mainfrom
edubox:feat/http2-async-completions

Conversation

@edubox

@edubox edubox commented Oct 26, 2026 •

Copy link
Copy Markdown
Contributor

What

sceHttp2SendRequestAsync, sceHttp2ReadDataAsync and sceHttp2WaitAsync threw. This completes them over the existing transport:

  • sceHttp2SendRequestAsync copies the body, runs Send on a worker and queues an Http2AsyncResult whose result is the transport's result, then triggers the kqueue user event (equeue at 0, event id at 8, user data at 16, the layout inferred from PPSA17221).
  • sceHttp2ReadDataAsync does the same for Read and reports the bytes read in result.
  • sceHttp2WaitAsync waits for the oldest completion. A null timeout waits indefinitely; *timeout == 0 throws because whether zero blocks is unknown (PPSA02195 polls with a zero timeout and aborts the request on an immediate timeout, but the 11.00 kernel path is not in the dump), recorded in the debt entry; a nonzero *timeout is a microsecond deadline that returns 0x817b1079 when it expires, which is the 11.00 mapping of the kernel's 0x8002003c. A null result returns 0x817b1225 and a non-null trailing argument or a non-zero reserved field of the result returns 0x817b11fe. Each request owns a stable completion state; deleting a request or its parent retires that state, wakes waiters with the invalid-id error, and drops queued and later completions without triggering a user event. Publication and retirement share the request state lock, so a completion cannot be delivered after deletion returns.
  • event_type is 0 for send and 1 for read, confirmed by the 11.00 completion kinds (+0x1600 pairs mapped at 0x9a4f). *timeout receives the remaining microseconds, following the forwarded kernel pointer; whether a zero timeout blocks is still an open kernel question recorded in the debt entry, an unregistered user event is not detected at submission, and a transport exception is rethrown from sceHttp2WaitAsync.

Evidence

The argument and timeout contract comes from the decrypted firmware 11.00 libSceHttp2.sprx: sceHttp2SendRequestAsync at 0x1940/internal 0x4a60, sceHttp2ReadDataAsync at 0x1b20/0x4e20 and sceHttp2WaitAsync at 0x1c20/0x9a00. The wait forwards the caller's pointer to sceKernelWaitSema(sema, 1, timeout) (0x4790) and remaps the kernel timeout 0x8002003c to 0x817b1079 (0x9a79); the result and trailing-argument checks are at 0x1d21, 0x1cca and 0x1cd3, and the completion kind at +0x1600 selects event_type through the table at 0x271d0. Because the 11.00 submission bodies reject a non-null trailing pointer with 0x817b11fe while PPSA22408 passes one, the trailing pointer stays ignored and the debt entry records the version split.

Tested

Linux (CachyOS), GCC 16.2.1. guest_http2 submits an asynchronous request whose body length does not match the declared content length, then checks the user event payload and that sceHttp2WaitAsync rethrows the worker's exception. guest_http2_transport drives a real loopback HTTP/2 send and read through the asynchronous API, plus the async-failure, wait-versus-delete, two-waiter, parent-teardown, deletion-after-publication, optional-argument and expired-wait cases. The expired-wait case pins 0x817b1079, and the null-timeout case stalls the response and checks that the wait returns only after the completion. The zero-timeout case is not pinned because its console behaviour is unknown. guest_http2, guest_http2_cookies, guest_http2_transport and guest_http2_early_response pass in the Release build.

Title: PPSA02195 polls sceHttp2WaitAsync with *timeout == 0 and aborted the request as soon as it received an immediate timeout; that remains the only observation and the case stays unimplemented until a console measurement settles it. It was run with other local changes on the same tree.

Checklist

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

Reviewed exact head b42c09562c218caa6e999205e43a6c08274b7ced. I found a blocking lifetime race in the async completion queue.

[P1] sceHttp2WaitAsync must not retain a deque reference across the condition-variable wait when deletion can erase it. At Export.cpp:349-350, queue refers directly to the mapped deque and the wait releases g_completionsMutex. sceHttp2DeleteRequest can then erase that entry at lines 163-164. A detached operation may subsequently run CompleteAsync, recreate the map entry, and notify; the waiter wakes and evaluates available against the destroyed deque reference (or accesses it at queue.front()), which is a use-after-free. A finite timeout can also wake it after deletion. Separately, the worker can publish a new completion after deletion, so erasing the existing queue does not actually drop pending completions as the PR description says.

Please make request deletion, in-flight operations, and waiters share a stable per-request completion state (including a defined cancelled/deleted wake result), and ensure no completion can be enqueued after that state is retired. Add a regression that blocks a waiter, deletes the request while an operation is still in flight, then releases/completes the operation and verifies there is no hang, stale completion, or invalid access; run it under ASan/TSan where available.

I have not run this PR's tests locally yet; existing PR checks are policy-only for these changed paths and skip product builds. This request is based on the lock and lifetime interleaving above, not on an unrun test claim.

@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Tested with Palworld (PPSA23126) on Linux (CachyOS, GCC 16.2.1) on a local stack that also carries the HTTP/1.x transport, the Host header translation and the d16 converted-image fix: with this PR the title gets past sceHttp2SendRequestAsync and runs for 150 s (10 presentation windows) without aborting. The send still fails without a system CA trust store, but the completion reaches the kqueue event and sceHttp2WaitAsync, and the title continues to presentation, so the asynchronous error path is exercised. Without this PR the same stack stops at sceHttp2SendRequestAsync not implemented.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

@edubox Thanks for finishing these. A few things before this can merge:

  1. Completion lifetime. sceHttp2WaitAsync keeps a reference into g_completions[req_id] across the condition-variable wait. sceHttp2DeleteRequest, or a second WaitAsync on the same request that drains the queue (it erases the entry when empty), can erase that entry meanwhile, so the first waiter resumes on a destroyed deque. Please give each request a stable completion object (for example a shared_ptr owned by the handle and captured by the worker and the waiter), never hold a reference into the map across a wait, and wake waiters when the request is deleted.
  2. After delete. The detached send/read workers still publish after DeleteRequest (CompleteAsync recreates the queue and emits an event), and DeleteTemplate/Term don't clear these queues. Please drop completions that arrive after the request is gone, and make WaitAsync return ERROR_INVALID_ID for an unknown or deleted request instead of waiting forever.
  3. Error codes. The workers turn every exception into 0x80436063, which isn't sourced (libSceHttp's network error is 0x80431063), and that also hides the transport's "not implemented" throws. Please report only the transport's own return values and carry any exception to the caller (for example store it in the completion and rethrow it from sceHttp2WaitAsync) rather than inventing a code.
  4. Tests. Please remove the two assertions that a valid call throws (an expired WaitAsync timeout, and SendRequestAsync without a kqueue option); the code can keep throwing there, but tests shouldn't pin it. And please add deterministic cases for wait versus delete, two waiters consuming the last result, a worker that completes after deletion, and parent teardown.

@github-actions

github-actions Bot commented Oct 27, 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
PR 15221 core/libs/tests/GuestHttp2Transport.cpp L60
docs/dev/debt/libSceHttp2.md L59-60

Some comparisons could not be completed because a pull request conflicts with the base branch. Review these shared files manually before concluding that there is no overlap.

Pull request Shared files not compared
PR 14212 docs/dev/debt/libSceHttp2.md
PR 15996 core/libs/prx/libSceHttp2/Export.cpp
core/libs/tests/GuestHttp2.cpp
docs/dev/debt/libSceHttp2.md
PR 16292 core/libs/prx/libSceHttp2/Export.cpp
core/libs/tests/GuestHttp2.cpp
docs/dev/debt/libSceHttp2.md

@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Addressed the completion lifetime and error-handling review at 2ca67c36eb.

  • Each request now owns a shared_ptr completion state captured by the worker and the waiters; the global completion map is gone. sceHttp2DeleteRequest, sceHttp2DeleteTemplate and sceHttp2Term retire that state, wake blocked waiters with the invalid-id error, clear pending completions, and later completions are dropped without triggering the kqueue event.
  • sceHttp2WaitAsync looks up the request before waiting and returns 0x817B1100 for an unknown or deleted request; no reference into a map survives a condition-variable wait.
  • Removed the unsourced 0x80436063. Workers store the transport's own return value, and any exception is carried in the completion and rethrown from sceHttp2WaitAsync.
  • Removed the two assertions that pinned throws, and added deterministic cases for wait versus delete, worker completion after deletion, two waiters consuming the last result, parent teardown, and worker exception propagation.

Verification:

  • ctest --test-dir build -R '^guest_http2' -> 4/4 passed (guest_http2, guest_http2_cookies, guest_http2_transport, guest_http2_early_response).
  • ASan build (ANYPS5_ENABLE_ASAN=ON): guest_http2_transport and guest_http2_early_response passed.
  • TSan build (ANYPS5_ENABLE_TSAN=ON): the same two passed with no ThreadSanitizer reports.
  • python3 tools/check_conventions.py --base origin/main -> all checks passed.
  • The new wait/delete regression fails on the previous head under ASan, so it exercises the reported interleaving.

@JJenkx

JJenkx commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Independent Linux follow-up on exact 2ca67c36eb082641d502227da49d08ca193c9c6b: I reproduced an abort in guest_http2: sceHttp2: SSL context or connection unavailable not implemented. That fixture never initializes a real SSL context, but still expects a numeric error from WaitAsync; the new worker correctly carries this exception instead.

A minimal local fixture correction changes that invalid-context case to check exception delivery. It also uses Mode::Reset rather than Mode::Redirect in AsyncFailure: with #11575 composed, redirects are supported, and this fixture instead waits for an event while trying to follow a server that only serves one connection. This tests an actual transport failure without relying on redirects being unavailable. The expired-timeout and missing-kqueue throw assertions remain removed.

Exact #11630 plus this two-line correction (308fc05d9db) passes 4/4 HTTP groups in7.49s. My private HTTP1/callback integration initially reproduced both fixture failures; with these corrections plus three new real async HTTP1 wire scenarios, it passes 7/7 in26.34s (6309c009433). The added scenarios check HTTP/1.0 TLS, HTTP/1.1 TLS and plain TCP: POST upload, send/read event payloads and results, partial body reads, EOF, TLS callbacks and requested wire version. Conventions pass.

Both patches, source pins and negative/positive logs, SHA256 ab55119e29ecc58ef8e12447b87e427cbc24e41452385a24d31a1d895582fed7. async-fixture-correction.patch applies directly to your head (verified); the separate HTTP1 composition tests require the #11575/#11586/#11611 fixtures. No public branch was changed, and the private integration merge should not be published. These are CPU checks; I have not independently rerun ASan/TSan or a title on the new async code.

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

Reviewed current head 2ca67c36eb082641d502227da49d08ca193c9c6b. The completion-lifetime and exception-propagation changes address my earlier request, but the guest_http2 fixture still expects sceHttp2WaitAsync to return a numeric result for a request created by sceHttp2Init(1, 1, ...) without initializing an SSL context. Transport.cpp requires a usable SSL context and throws sceHttp2: SSL context or connection unavailable; the worker now correctly carries that exception to WaitAsync, so this fixture aborts rather than receiving the expected completion. An independent Linux run on this exact head reports the same failure. Please update this case to assert exception delivery, or provide a valid SSL context if a numeric completion is intended.

I built guest_http2_tests locally. ctest -R '^guest_http2$' aborts before reaching the assertion because this Xeon E5-1620 v2 lacks required CPU extensions; this is not a local reproduction of the fixture failure. git diff --check passes. Local conventions report the existing 1200-character debt entry length warning; hosted conventions passed on this head. Product build jobs are skipped by path policy.

@edubox
edubox force-pushed the feat/http2-async-completions branch from 2ca67c3 to 1e42382 Compare October 27, 2026 02:07
@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 1e42382d8b (rebased onto main abed035468).

  • The guest_http2 fixture no longer assumes a numeric WaitAsync result for a request with an uninitialized SSL context. On this host the connection is refused before sceSslCreateConnection, so the worker returns a transport result; on a host where the port accepts, it throws. The fixture now triggers a deterministic worker exception (body length differs from the declared content length), waits for the user event, and asserts that sceHttp2WaitAsync rethrows it.
  • AsyncFailure uses Mode::Reset instead of Mode::Redirect, matching @JJenkx's correction so it no longer depends on redirects being unimplemented (feat(http2): deliver redirect callbacks and follow HTTPS redirects #11575).
  • The earlier lifetime cases (AsyncDelete with and without a blocked waiter, AsyncTwoWaiters, AsyncTeardown) are unchanged.

Validation: guest_http2, guest_http2_cookies, guest_http2_transport and guest_http2_early_response pass 4/4 in Release, ASan (-DANYPS5_ENABLE_ASAN=ON) and TSan (-DANYPS5_ENABLE_TSAN=ON) builds. python3 tools/check_conventions.py --base origin/main reports 0 errors; the pre-existing 1200-character debt-length warning remains.

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

Reviewed exact head 1e42382d8bcf4e1d1612395577bc5f78b5fd21e5. The updated guest_http2 case now uses the transport's declared-length check to exercise exception delivery, and changing AsyncFailure to Mode::Reset removes its dependence on redirect support. Those address the prior fixture findings.

[P1] Serialize event delivery with request retirement. CompleteAsync checks state->retired and enqueues the completion while holding state->mutex, then releases the lock at line 69 and triggers the user event at line 71. sceHttp2DeleteRequest can retire and erase the request in that gap. The worker then triggers an event after deletion even though the debt entry says later completions are dropped without triggering one. Please make retirement and event delivery mutually ordered (and add a regression for deletion after enqueue but before trigger); the existing stalled-worker deletion test only covers completion arriving after retirement.

[P2] Coordinate the overlapping test/debt edits. The current merge-base check against open #11575, #11586, #11611, and #11617 reports content conflicts in GuestHttp2Transport.cpp (and, for the first three, docs/dev/debt/libSceHttp2.md). CONTRIBUTING.md says to agree with overlapping PR authors on order and declare a prerequisite with Depends on when needed. Please coordinate the order and update the checklist/debt text so the combined landing is explicit. The pair with #11616 merges cleanly.

The updated convention and label checks pass, and the report check passed. The product build jobs are skipped by path policy; I have not independently rerun the reported Release/ASan/TSan tests on this head.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Thanks, the request-owned state fixes the lifetime problem, and the zero-length POST in guest_http2 makes JJenkx's case deterministic: it now fails on the body-length mismatch before any connect, so it no longer depends on whether something listens on localhost:443. Three things are left:

  1. Completion after deletion. CompleteAsync (Export.cpp:68-70) releases the lock after pushing the result and before sceKernelTriggerUserEvent. If the worker pauses in that gap, DeleteRequest, DeleteTemplate or Term can retire the request and return, and the event is then triggered for a request that no longer exists. Please serialize publication with retirement, and add a regression that holds the worker in that gap and covers both direct and parent deletion. The existing stalled-transport tests stop earlier, so they don't reach it.
  2. AsyncFailure in guest_http2_transport checks that WaitAsync throws after the server resets the stream (previously after a 302). Both are valid server responses whose console result isn't known, so the test shouldn't pin them to a throw. Please trigger the worker exception with a caller error instead (the body-length mismatch works) and keep the check that the exception reaches WaitAsync.
  3. GuestHttp2.cpp:31 and :52 require attaching a live cookie box to a live template, and GetMemoryPoolStats on a live context with valid output, to throw. Those are valid calls that are not implemented yet (Export.cpp:404-412, 442-443), so please drop those two assertions. Keep the malformed-input, invalid-ID and worker-exception checks. No implementation of those calls is needed in this PR.

@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Pushed 54fe144aac with the remaining code and fixture changes.

  • P1, publication versus retirement. CompleteAsync now keeps the per-request state lock across enqueue, waiter notification and sceKernelTriggerUserEvent; RetireAsync takes the same lock. A deletion cannot return before an in-flight publication finishes, so an event can no longer be triggered after the request is retired. Added a deterministic regression (AsyncDeletePublished) that holds the worker between enqueue and event delivery and covers both direct request deletion and parent template deletion; the hook used to hold it is test-only (GuestSceHttp2Test::SetAsyncPublishHookForTests_nid_no_patch).
  • Async failure fixture. AsyncFailure now triggers the worker exception with a caller body-length mismatch instead of a server reset, and keeps the check that the exception reaches sceHttp2WaitAsync.
  • Valid calls. Dropped the sceHttp2SetCookieBox live-box and sceHttp2GetMemoryPoolStats live-context throw assertions from guest_http2; malformed-input, invalid-ID and worker-exception checks remain.

Local verification on this head: guest_http2, guest_http2_cookies, guest_http2_transport, guest_http2_early_response pass 4/4 in Release, AddressSanitizer and ThreadSanitizer; check_conventions.py --base origin/main reports 0 errors (the existing 1200-character debt warning remains).

P2 remains unresolved. Against the current heads (#11575 d847910c69, #11586 a40e7c1e81, #11611 b5eebed6ca, #11617 cac330cff3), git merge-tree --write-tree still reports content conflicts in core/libs/tests/GuestHttp2Transport.cpp and, for the first three, docs/dev/debt/libSceHttp2.md. I did not change Depends on: none or rebase this branch onto another author's branch, because choosing and declaring the landing order requires agreement with those authors and I cannot verify that agreement here. #11616 still merges cleanly.

@milescoviello

milescoviello commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

A title that reaches this path over HTTP/2: MXGP 26 (PPSA30839 01.003.000). Linux, RTX 4070 Ti (NVIDIA 615.71.09), GCC 15.2, Release libs, warm shader cache, 600 s run limit. Its first network calls stop on three HTTP/2 gaps in a row: sceHttp2GetMemoryPoolStats (#11616), sceHttp2SetResolveRetry (#11617, stacked on #11616), and sceHttp2SetRedirectCallback (#11575). With those three it reaches this PR's functions.

For the stack, the only conflicts with this PR were the Mode enum and main() call list in GuestHttp2Transport.cpp (#11575 adds RedirectOnce, #11617 adds Retries) and the debt file's last entry (#11575 adds the redirect entry). Keeping both sides of each was enough. Next I'll add #11611 to the same stack and post where MXGP stops then.

AI-assisted: yes (Claude Code)

@milescoviello

Copy link
Copy Markdown
Contributor

Follow-up to the MXGP run above: with #11611 in place of #11575 (main abed035 + #11617 + #11611 + this PR), the asynchronous HTTP/1.x request reaches the host lookup. MXGP then exits at 7 s with sceHttp2: DNS failed; console error mapping is unknown, which my no-network sandbox makes expected (details on #11611). So with this PR, the title's asynchronous send gets through submission and into the transport. The guest_http2 and guest_http2_transport tests also pass on the first stack (main + #11617 + #11575 + this PR) on Linux.

AI-assisted: yes (Claude Code)

@edubox
edubox force-pushed the feat/http2-async-completions branch from 54fe144 to 20b7a97 Compare October 27, 2026 04:05
@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto main b986c11a34 (clean; main does not touch the files in this PR) and force-pushed 20b7a972a8. The rebase also replaces the superseded cancelled conventions run; hosted conventions, labels, eligibility and report are green on the new head.

Local verification on 20b7a972a8:

  • ctest --test-dir build -R '^guest_http2' -> 4/4 passed in Release.
  • The same 4/4 pass in the AddressSanitizer and ThreadSanitizer builds.
  • python3 tools/check_conventions.py --base origin/main -> 0 errors; the 1200-character debt-length warning on the new async entry remains.
  • git diff --check is clean.

P2 is still unresolved because I cannot verify an agreement with the overlapping authors: git merge-tree still reports content conflicts with #11575, #11586, #11611 and #11617 in GuestHttp2Transport.cpp and the debt file. I did not change Depends on: none, touch their branches, or invent a landing order. #11616 still merges cleanly. The code and fixture items are ready for re-review.

AI-assisted: yes

@milescoviello

milescoviello commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

@edubox For #11617 (mine, stacked on #11616): either order is fine with me. The conflicts between it and this PR are small. In GuestHttp2Transport.cpp, this PR adds its Async* calls to main()'s list at the spot where #11617 adds Retries(ssl); the Mode enum conflict is with #11575's RedirectOnce, not with #11617. In libSceHttp2.md, both edit the debt entries. Keeping both sides resolves each one; I did exactly that for the MXGP stacks above, and the tests passed there. If this PR lands first, I'll rebase #11617 onto it the same day, and if #11617 lands first, the rebase on your side is those few lines. So I'm not holding this PR for #11617.

AI-assisted: yes (Claude Code)

@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Re-checked head 20b7a972a8 against the latest requests.

Completion lifetime / event ordering (P1). CompleteAsync now holds the per-request state lock from the retired check through sceKernelTriggerUserEvent, so RetireAsync (direct request deletion, parent deletion, or sceHttp2Term) cannot retire the state until event delivery finishes. AsyncDeletePublished holds the worker between enqueue and trigger and covers both direct and parent deletion; AsyncDelete covers completion after retirement, and parent teardown is covered by AsyncTeardown.

Fixture assertions. AsyncFailure now triggers the worker exception with the caller's body-length mismatch instead of a server reset, and sceHttp2WaitAsync still has to rethrow it. The live-cookie-box and live-context GetMemoryPoolStats throw assertions are gone; malformed-input, invalid-ID and worker-exception checks remain.

Overlap (P2). The checklist now records the textual overlap and the stacks: #11575 -> #11586 -> #11611 and #11616 -> #11617, keeping both sides for GuestHttp2Transport.cpp and libSceHttp2.md. The #11617 author already confirmed either order with this PR is fine. There is no implementation dependency.

Verification on 20b7a972a8 (Linux x86-64, GCC 16.2.1, same machine):

  • Release: guest_http2, guest_http2_cookies, guest_http2_transport, guest_http2_early_response pass 4/4 in 7.9 s.
  • AddressSanitizer: 4/4 in 8.0 s.
  • ThreadSanitizer: 4/4 in 8.5 s.
  • python3 tools/check_conventions.py --base origin/main: only the pre-existing 1200-character libSceHttp2.md debt-length warning; no errors. git diff --check clean.

Product jobs remain skipped by path policy, so this is the focused local evidence, not a title run.

@edubox
edubox force-pushed the feat/http2-async-completions branch from 20b7a97 to eba7e4a Compare October 27, 2026 06:06
@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current main (ad29cabe9e); head is now eba7e4a686. No files touched by this PR changed on main, so the rebase was clean.

Local verification on eba7e4a686 (Linux x86-64, GCC 16.2.1, same machine):

  • Release: guest_http2, guest_http2_cookies, guest_http2_transport, guest_http2_early_response pass 4/4 in 7.7 s.
  • AddressSanitizer: 4/4 in 7.9 s.
  • ThreadSanitizer: 4/4 in 8.6 s.
  • python3 tools/check_conventions.py --base origin/main: 0 errors (the pre-existing 1200-character libSceHttp2.md debt-length warning remains); git diff --check clean.

The previous head's review items stand as fixed: CompleteAsync holds the per-request lock through event delivery, AsyncDeletePublished covers direct and parent deletion, AsyncFailure uses the caller body-length mismatch, and the checklist records the overlap/order text. P2's #11617 order confirmation is in the thread.

@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Rebased automatically onto current main (f1adec7eb1); head is now 34848861aa. Focused tests pass; check_conventions.py --base origin/main and git diff --check are clean.

@edubox
edubox force-pushed the feat/http2-async-completions branch 2 times, most recently from 3484886 to 9d7aaab Compare October 27, 2026 08:01
@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Rebased automatically onto current main (12686b52de); head is now 9d7aaabd7f. Focused tests pass; check_conventions.py --base origin/main and git diff --check are clean.

@milescoviello

Copy link
Copy Markdown
Contributor

@edubox here's a second title that reaches this code, Crimson Desert (PPSA25286 01.000.568). It uses an asynchronous form this PR still refuses.

On main 13926067ac, the title stops 1 s after launch with sceHttp2SendRequestAsync not implemented. That was 1 run on plain main, plus 2 with an unrelated recompiler-only change (#11798) on top. Setup: Linux, RTX 4070 Ti (NVIDIA 615.71.09), GCC 15.2, release libs, cold shader cache, no network in my sandbox. On 10-21, main 6f9de57386 ran it for 600 s, so a later HTTP/2 change lets the request reach the asynchronous send.

On this PR's head 9d7aaabd7f (release libs, same setup), the title still stops at 1 s with the same message: 2 runs on the head alone and 2 with #11798 on top. The title's calls, read from its relinked eboot.bin:

Call Arguments
sceHttp2SendRequestAsync (0x3043c2f) kqueue_option NULL, option NULL
sceHttp2ReadDataAsync (0x304591a) 0x2000-byte buffer, kqueue_option NULL, option NULL
sceHttp2WaitAsync (0x304594a) non-null result, timeout pointer, option NULL

So it uses the asynchronous calls without a kqueue and waits for each one with sceHttp2WaitAsync. SendRequestAsync and ReadDataAsync here go to NotImplemented_nid_no_patch when kqueue_option is null, so the first one stops it.

Everything else this title imports from libSceHttp2 is the template/request setup: CreateTemplate, CreateRequestWithURL, SetTimeOut, SetSendTimeOut, AddRequestHeader, SetRequestContentLength. After that come GetStatusCode, GetAllResponseHeaders, GetResponseContentLength, AbortRequest and DeleteRequest.

If the kqueue-less form is in scope for this PR, I can rerun Crimson Desert on a new head; otherwise it can be a follow-up. In my sandbox I'd expect it to stop next at the DNS lookup, like MXGP.

AI-assisted: yes (Claude Code)

@edubox

edubox commented Oct 27, 2026

Copy link
Copy Markdown
Contributor Author

Rebased automatically onto current main (5bc84038c4); head is now 2f1307654d. Focused tests pass; check_conventions.py --base origin/main and git diff --check are clean.

@edubox
edubox force-pushed the feat/http2-async-completions branch from 3519324 to f364585 Compare November 4, 2026 09:37
@edubox

edubox commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Rebased onto current origin/main (b11c7bf84f) and pushed f364585f10, so the merge conflict is resolved.

Resolutions:

  • GuestHttp2Transport.cpp: Mode takes main's HTTP/1.x modes plus this PR's StallResponse; Server keeps main's location/redirectStatus and HTTP/1.x ALPN selection and adds this PR's bindHost parameter, so the async cases can bind localhost; Failure keeps main's signature, with the numeric-host case still covered by main's Handshake.
  • docs/dev/debt/libSceHttp2.md: keeps main's transport, gzip, redirect and SSL entries and this PR's asynchronous/sceHttp2WaitAsync entries.

On this head: guest_http2_tests, guest_http2_cookie_tests and guest_http2_transport_tests pass; python3 tools/check_conventions.py --base origin/main reports all checks passed; git diff --check origin/main...HEAD is clean.

@oneandonlydean

Copy link
Copy Markdown
Collaborator

Hi edubox, thanks for the rebase onto main. One thing from putting core/libs/tests/GuestHttp2Transport.cpp at f364585f10 next to the earlier head 3519324da2: the Server constructor still takes (mode, location, redirectStatus, bindHost) (:95), but the calls that used to pass the bind host now pass "localhost" as the second argument, which is the redirect location:

  • :971 Server server(mode, mode == Mode::Normal && !disableCa ? "localhost" : "127.0.0.1");
  • :1112, :1151, :1203 Server server(Mode::Normal, "localhost");
  • :1233 Server server(Mode::StallResponse, "localhost");

At 3519324da2 these were Server server(..., "/another", 302, "localhost"). As written, the listener binds 127.0.0.1 (the default) while the client connects to localhost, so on Windows the client tries ::1 first and waits for it to be refused, which is the delay the bind change was meant to remove. Linux still passes because localhost resolves to 127.0.0.1 first there.

Please pass the host in the fourth slot again ("/another", 302, "localhost"), or give the constructor a bindHost-first overload, and re-run guest_http2*.

@edubox

edubox commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Fixed the async fixtures' listener binding: the five calls that need localhost now pass it in the fourth bindHost slot again ((mode, "/another", 302, "localhost")), including the conditional one in Success, so the listener no longer falls back to 127.0.0.1 while the client tries ::1 first.

Tested at 60b06e53ea: all 10 guest_http2* tests pass (guest_http2_transport 11.6 s), and python3 tools/check_conventions.py --base origin/main passes.

AI-assisted: yes.

@milescoviello

Copy link
Copy Markdown
Contributor

@edubox a Windows run of the new head 60b06e53ea (the listener bindHost fix), on the Windows 11 VM where I saw the Async failure: NVIDIA GeForce GT 1030, driver 582.78, WinLibs GCC 15.2.0.

Tree guest_http2 guest_http2_transport
base main b11c7bf84f (the head's merge-base) 3 of 3 pass 3 of 3 pass
head 60b06e53ea 3 of 3 pass 3 of 3 pass, about 4.1 s each

AI-assisted: yes (Claude Code)

@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ AMD GPU test: passed

PR head 60b06e5 merged onto main b11c7bf · tested 2026-11-04 20:17 UTC · 16 min

GPU AMD Radeon RX 6300 (RADV NAVI24), driver Mesa 25.2.8-0ubuntu0.24.04.4, Vulkan 1.4.318
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-42-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 1,123 passed · 5 failed (0 new, 4 also fail on main, 1 unstable on main) · 7 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 1,135 of 3,894 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (548 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.4 s, ⚠️ public_headers 56.7 s, ⚠️ agc_driver_image_sample_unnormalized 50.1 s, ⚠️ agc_driver_lazy_resolved_abi 42.7 s, ⚠️ agc_driver_sample_multisample_target 36.5 s
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 8 of the last 10 main runs
Failing on main too (4, not counted against this PR)
agc_driver_image_table
agc_driver_native_depth_bda_clear
agc_driver_native_multisample_depth
agc_driver_submit_progress
Validation IDs already present on main (8 IDs in 469 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (469 tests): agc_driver_address_draw_space_reuse, agc_driver_address_passes, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, agc_driver_bda_span_reads, and 461 more
VUID-vkCmdCopyImage-srcImage-01548 (4 tests): agc_driver_depth_clear_hle, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-vkCmdCopyImage-srcImage-01551 (4 tests): agc_driver_depth_clear_hle, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (1 test): agc_driver_srgb8_color_target
VUID-VkSamplerCreateInfo-addressModeU-01079 (1 test): agc_driver_image_gather_volume
VUID-VkSamplerCreateInfo-addressModeU-parameter (1 test): agc_driver_image_gather_volume
VUID-VkSamplerCreateInfo-addressModeV-parameter (1 test): agc_driver_image_gather_volume
VUID-VkSamplerCreateInfo-addressModeW-parameter (1 test): agc_driver_image_gather_volume
Skipped (7)
agc_driver_copied_writer_label_order: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_float16_unused_nan_payloads: skipped, the device has no native f16 conversions with RTE rounding and kept f16 denormals
agc_driver_gcn_display_present: skipped, no display: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
agc_driver_linear_target_direct_write_completion: skipped, the device does not keep host imports write-watched, so no completion stamp over the target is tracked
agc_driver_ngg_vertex_wave_reduction: skipped, s3 describes a 32-lane wave only on 32-lane subgroups, and the device has 64 lanes
agc_driver_scattered_runs: skipped, host imports are unavailable: /dev/udmabuf is not accessible
agc_driver_sparse_dma_buf_import: skipped, host imports are unavailable: /dev/udmabuf is not accessible
Reproduce
git fetch origin 60b06e53ea9a5744f0965fd732c460ff6ea26d65 b11c7bf84f5d2f636ff60166cc3371bd071e24d5
git checkout b11c7bf84f5d2f636ff60166cc3371bd071e24d5 && git merge --no-ff 60b06e53ea9a5744f0965fd732c460ff6ea26d65
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 12 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 16 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@edubox

edubox commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

The hosted windows job fails while compiling core/libs/prx/libSceAgcDriver/Graphics/src/DepthSurface.cpp on the base commit b11c7bf, before it reaches this change: cannot convert 'VkMemoryAllocateInfo' to 'const VkImageCreateInfo&' at line 1623. Current main contains the fix for that sampled-depth-shadow allocation, so a new run against current main should get past it. No change in this PR is needed for it, and I cannot rerun the hosted job without admin rights.

AI-assisted: yes.

@edubox

edubox commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

The Server constructor calls now pass the bind host in the fourth slot again (for example Server(Mode::Normal, "/another", 302, "localhost") at the async and stall scenarios), so the listener and the client use the same first address on Windows. That fix is in 60b06e53ea.

I merged current main (48c8ef11fc) into the branch (4b14055f66) because the last windows failure was a base-tree compile error in DepthSurface.cpp (the old OwnedImage::Allocate overload against the current header), not this change; current main carries the fix.

Checks on the merged head:

  • ctest -R '^guest_http2': 10/10 passed, including guest_http2 and guest_http2_transport.
  • python3 tools/check_conventions.py --base origin/main: all checks passed.

The push retriggers windows against a base that compiles.

Apply review request from 2026-11-05: resolve the GuestHttp2Transport Mode enum and libSceHttp2 debt-doc conflicts.
@TechLevelZero

Copy link
Copy Markdown
Contributor

✅ AMD GPU test: passed

PR head ce840ea merged onto main e772fb2 · tested 2026-11-05 16:46 UTC · 16 min

GPU AMD Radeon RX 6300 (RADV NAVI24), driver Mesa 25.2.8-0ubuntu0.24.04.4, Vulkan 1.4.318
Host Ubuntu 26.04.1 LTS, kernel 7.0.0-42-generic, container ubuntu:24.04
Logs build and test logs for this run
Build ✅ passed (Release, -DANYPS5_ENABLE_SPIRV_TOOLS=ON)
Tests ✅ 1,322 passed · 5 failed (0 new, 4 also fail on main, 1 unstable on main) · 7 skipped (ANYPS5_REQUIRE_VULKAN=1)
Test setup CPU-only tests without a GPU; GPU tests (and any CPU-only test that failed or skipped without one) once on the GPU with VK_LAYER_KHRONOS_validation and ANYPS5_NO_SHADER_CACHE=1; main ran the same way
Test selection 1,334 of 4,074 tests run: the ones this change can reach, chosen by tools/select_tests.py from main's build graph
Vulkan validation ✅ no new validation IDs vs main (638 tests run on the GPU)
Slow tests (>30 s, GPU tests timed with validation layers) ⚠️ agc_driver_pipeline_journal 120.2 s, ⚠️ public_headers 58.2 s, ⚠️ agc_driver_image_sample_unnormalized 52.9 s, ⚠️ agc_driver_lazy_resolved_abi 41.8 s, ⚠️ agc_driver_indexed_copy 30.8 s
Unstable on main (1, these also failed in recent main runs on this machine; not counted against this PR)
agc_driver_pipeline_journal: failed in 9 of the last 10 main runs
Failing on main too (4, not counted against this PR)
agc_driver_image_table
agc_driver_native_depth_bda_clear
agc_driver_native_multisample_depth
agc_driver_submit_progress
Validation IDs already present on main (4 IDs in 550 tests)
VUID-VkDeviceCreateInfo-pNext-pNext (550 tests): agc_driver_address_draw_space_reuse, agc_driver_address_passes, agc_driver_address_passes_draw_transitions, agc_driver_alias_copy_label, agc_driver_alpha_to_coverage, agc_driver_array_layer_target, agc_driver_bc_block_copy, agc_driver_bda_anchor_reads, and 542 more
VUID-vkCmdCopyImage-srcImage-01548 (4 tests): agc_driver_depth_clear_hle, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-vkCmdCopyImage-srcImage-01551 (4 tests): agc_driver_depth_clear_hle, agc_driver_depth_storage_dispatch, agc_driver_depth_surface_from_storage, agc_driver_dispatch_move_depth
VUID-VkPipelineColorBlendStateCreateInfo-pAttachments-00605 (1 test): agc_driver_prepared_exports
Skipped (7)
agc_driver_copied_writer_label_order: skipped, the device reports a minStorageBufferOffsetAlignment of 4, so the dispatch binds its record at +0x1004 in place and nothing is written back; the test needs an alignment above 4
agc_driver_float16_unused_nan_payloads: skipped, the device has no native f16 conversions with RTE rounding and kept f16 denormals
agc_driver_gcn_display_present: skipped, no display: Vulkan support is either not configured in SDL or not available in current SDL video driver (offscreen) or platform
agc_driver_linear_target_direct_write_completion: skipped, the device does not keep host imports write-watched, so no completion stamp over the target is tracked
agc_driver_ngg_vertex_wave_reduction: skipped, s3 describes a 32-lane wave only on 32-lane subgroups, and the device has 64 lanes
agc_driver_recorded_draw_staging: skipped, the device does not keep host imports write-watched, so the target is never resident
agc_driver_vertex_elected_atomic_max: skipped, the device runs vertex programs in subgroups, so they keep their cross-lane reductions
Reproduce
git fetch origin ce840eaa1e9306611b53cbc28787abfdb8867dce e772fb25cc72ee5faf77847f06bbc69533016e82
git checkout e772fb25cc72ee5faf77847f06bbc69533016e82 && git merge --no-ff ce840eaa1e9306611b53cbc28787abfdb8867dce
git submodule update --init --recursive
cmake -S . -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_TESTING=ON -DANYPS5_ENABLE_SPIRV_TOOLS=ON
cmake --build build && cmake --build build --target libs
VK_DRIVER_FILES=/nonexistent/icd.json ctest --test-dir build -E '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 12 --output-on-failure
ANYPS5_REQUIRE_VULKAN=1 ANYPS5_NO_SHADER_CACHE=1 VK_INSTANCE_LAYERS=VK_LAYER_KHRONOS_validation \
  ctest --test-dir build -R '^(agc|shader|recompiler|videoout|video_out|guest_video_out|vulkan)|gpu' --timeout 120 --parallel 16 --output-on-failure
# failures are then re-run alone: --timeout 360 --parallel 2; new validation IDs: the test alone, twice, --parallel 1

Automated build and test on a contributor's AMD machine; it does not replace upstream CI. A new comment is posted for each new push. Full logs.

@JJenkx

JJenkx commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Independent Linux qualification of this PR head 3a4ca44163f23c3c28a40d7f977e033a6cdf047c on main 151a2cb6e274f594a09c8a2ca42f44af2e5c40d8; clean private merge 12ebdb6490ff1268e02d7fa9e858f771c679186a (nothing pushed to this branch). The former prerequisite #11611 is merged.

Built the actual HTTP2 module and selected fixtures, then ran 13/13 HTTP2 cases on main and13/13 with this PR, zero skips. The production NID-patched HTTP2 module was frozen into the same full-main SDK/relinker bank; that module is the only changed native library.

Actual title check: PPSA16064, Minecraft DungeonsII01.000.000, fresh private saves/caches in each arm, no controller input:

Arm Native result Reached
main abort134 at33.0s sceHttp2SendRequestAsync not implemented
main + this PR abort134 at33.0s sceHttp2WaitAsync not implemented

The latter refusal is the exact provider's timeout && *timeout == 0 branch. Both reviewed25s captures show the illustrated loading screen; nearby XComposite/X11 comparisons were recorded. This confirms the title gets past the async submission refusal, not that its network transaction succeeds or gameplay is unblocked. No FPS/audio/input or console-semantic claim.

Linux7.2.11, GCC16.2.1 Release, Ryzen9 7950X, RX6650XT/RADV26.2.6. Each complete title harness ran through the shared FIFO, with frozen banks/decoded inputs unchanged. Original assets were bound read-only; converted-module outputs used private writable overlays. All mounts released and udmabuf64MiB restored, no harness errors. An initial staging-only readonly-output-identity failure is retained and excluded from native results.

Commands, full build/test/JUnit logs, native reports/logs, module hashes and reviewed captures, SHA-256 70e1deaa8e2753ba1e6e576e5b666ad6b60c0550dfc9445b19503f137af60c09; downloaded and verified. No game binaries, savedata or memory captures included. AI-assisted: yes.

@JJenkx

JJenkx commented Nov 5, 2026

Copy link
Copy Markdown
Contributor

Follow-up ready PR #16231 targets the already-completed zero-timeout case, depending on this PR. A private PPSA16064 diagnostic found request6 with completed=1 and retired=0 at the unconditional refusal. The fix checks readiness under the existing mutex and still refuses an empty zero wait; it adds no pending-wait timeout policy.

The new real loopback send/read regression fails this parent and passes with the change; all14 focused cases pass. The title clears that wait and next stops on unsupported authentication at41.6s. Its25s readbacks are black, so no visual/gameplay unblock is claimed. Source/commands/logs/captures and the exact parent/source pins are in the follow-up description. The final commit fe20311 is the new change; your commits/authorship are retained. AI-assisted: yes.

@edubox

edubox commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Thanks. Confirming the split: #16231 carries the zero-timeout follow-up and this PR stays at 3a4ca44163. Verified on this head: ctest -R '^guest_http2' passes 13/13, python3 tools/check_conventions.py --base origin/main passes, and git diff --check origin/main...HEAD is clean. AI-assisted: yes.

…letions

# Conflicts:
#	core/libs/tests/GuestHttp2Transport.cpp
#	docs/dev/debt/libSceHttp2.md
@edubox

edubox commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

Merged main e3a14a86e4 into the branch (19e010da4b). Two conflicts, both resolved by keeping both sides:

  • GuestHttp2Transport.cpp: the Mode enum keeps main's Trailers and this branch's StallResponse.
  • docs/dev/debt/libSceHttp2.md: keeps main's trailing-header entry, drops main's stale "async submission and sceHttp2WaitAsync throw" entry, and keeps this branch's async and wait entries.

Focused guest_http2* tests pass (14/14 locally, including guest_http2_transport), and python3 tools/check_conventions.py --base origin/main is clean. The bindHost fourth-argument fix is already in this head.

@xXPBSXx

xXPBSXx commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

What

An independent title measurement for this PR on Windows: PPSA23126 on main against main with this PR merged in. On main the title aborts in sceHttp2SendRequestAsync; with the PR it does not abort there in two of three runs, and the third run ended earlier for another reason.

Tested

Windows 10 (10.0.19045), MinGW GCC 15.2, NVIDIA GeForce RTX 4080 SUPER, libraries and relinker built fresh from the tree under test. One title, runs set up for 600 s.

  • Arm main 7ad9749ed03: two runs, 2026-11-05 from 15:34 UTC to 15:38 UTC and from 16:20 UTC to 16:24 UTC. Both stop with std::runtime_error sceHttp2SendRequestAsync not implemented followed by FATAL: abort() (SIGABRT), after 44 s and after 55 s (line 40 and line 42 of the runs' error logs).
  • Arm main 7ad9749ed03 merged with this PR's head ce840eaa1e9306611b53cbc28787abfdb8867dce (the merge is clean): three runs on 2026-11-06. The PR's head has moved since then (now 19e010da4b9b4f788b16f2a038d6a4ed21de15c2); the PR's own diff to Export.cpp, Http2.hpp and the debt file is the same on both heads, while the two test files GuestHttp2.cpp and GuestHttp2Transport.cpp differ, which a title run does not use.
    • 15:42 UTC to 15:49 UTC: the game ends after 34 s with AGC graphics: vkQueueSubmit recorder: Vulkan result -4, after [device-fault] write invalid at 0x0 (lines 38 to 46). That is before the 44 s at which main aborts, so this run says nothing about the HTTP/2 path. An earlier run of this title on main (2026-10-26) ended after about ten seconds with a device fault at address 0x0 and vkQueueSubmit clear: Vulkan result -4 (lines 31 to 36 of its error log), a similar message.
    • 15:49 UTC to 16:04 UTC and 16:07 UTC to 16:20 UTC: both ran until the run script stopped them (set up for 600 s; it counted 573 s and 581 s) with no FATAL and no abort, past the 44 s and 55 s at which main stops.
  • The merged runs print no HTTP line in the log, so the send call itself is not visible; the observation is the missing abort at the point where main aborts. In the first full run 14% of the sampled frames were blank and the picture changed in 4 sampled cycles; in the second full run all sampled frames were blank. I did not judge the picture.
  • Not measured: whether the title's request is answered correctly, what it does after the send, and whether any later stop follows. This is Windows, not a console, and a different stack from the Linux run reported above in this thread.

AI-assisted (Claude Code).

…letions

# Conflicts:
#	core/libs/prx/libSceHttp2/Export.cpp
@edubox

edubox commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

Merged current main (bbc1388e355) into the branch to clear the merge conflict; head is now f11bebcc4b5.

The only conflict was Http2Handle in core/libs/prx/libSceHttp2/Export.cpp: kept both main's webSocket field and the per-request async state. No other conflict.

Focused tests: ctest --test-dir build -R '^guest_http2' -j2 -> 14/14 passed. python3 tools/check_conventions.py --base origin/main and git diff --check origin/main...HEAD are clean. The two approvals are retained on the new head.

This branch has not been deployed

No deployments
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.