Skip to content

feat(libkernel): select on pipes on Windows - #5013

Merged
oneandonlydean merged 1 commit into
boykopovar:mainfrom
p3n1cillin:claude/select-pipes
Oct 14, 2026
Merged

oneandonlydean merged 1 commit into
boykopovar:mainfrom
p3n1cillin:claude/select-pipes

Conversation

@p3n1cillin

Copy link
Copy Markdown

What

On Windows, select threw for any descriptor that is neither a guest socket nor a libSceNet socket. RetroArch (PPSA99169) in RetroArch mode stops there:

terminate called after throwing an instance of 'std::runtime_error'
  what():  select on descriptor 4 (not a libSceNet socket) not implemented

gdb shows the throw on the MHD-worker thread, GNU libmicrohttpd's server worker behind RetroArch's web UI. The descriptor is the read end of a pipe from the guest's pipe() (gdb on pipe_nid_postfix returned 4 and 5): libmicrohttpd's inter-thread wake-up channel, selected next to its listening socket. #3644 already taught poll to handle such a pipe; select had no Windows counterpart for its host group.

select's host group now has a Windows poller too. It uses the same PipeReadiness test as poll (Udp.cpp, exposed as GuestSockets::PipeReady): readable with data or when the write end is closed, writable with at least PIPE_BUF (512) bytes of quota. It checks the pipes every millisecond until the slice ends, and reports EBADF for a closed descriptor as Linux's HostPoll does. A descriptor that is neither a socket nor a pipe still throws, now saying so. Linux is unchanged. The select entries in docs/dev/debt/libkernel.md are updated.

Tested

  • guest_select, which was registered only off Windows, now runs on Windows and passes. It covers an idle pipe timing out, a readable read end, a writable write end, both at once, a pipe next to a guest socket with both ready, and EBADF after closing. Without the change it fails on Windows (it throws on the first pipe). All 124 libkernel tests pass on Windows 11 (MinGW GCC 15.2.0); the Linux path is unchanged and was not rebuilt locally.
  • RetroArch PPSA99169 v1.0.0-beta.1 on Windows (started through the picker with feat: convert a title's other executables and start them with sceSystemServiceLoadExec #4786): before, it stops as above about 3 s after start. After, it runs its XMB menu for the whole 100 s run: retroarch.log shows the Vulkan swapchain, [Autoconf] PS5 Controller configured in port 1, and the playlists loaded, with about 11 submissions per second.
  • python tools/check_conventions.py --base origin/main, tools/check_test_registration.py and tools/pr_overlap.py pass.

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none (reaching RetroArch mode needs feat: convert a title's other executables and start them with sceSystemServiceLoadExec #4786)
  • Unblocks: RetroArch (PPSA99169) in RetroArch mode
  • AI-assisted: yes

🤖 Generated with Claude Code

@p3n1cillin

Copy link
Copy Markdown
Author

Follow-up Linux validation of this change on current main 4bb2c7f3947440d513b1dbd12143ec55b250495a: cleanly cherry-picked PR head 76a168fccca9ceae399be9f4077db19fccce420a into an isolated local branch, alongside the independent libc tzname change from #5009. Exact integration head: 2e3b9eb35c775e1d429f6c42144a701a632859ae.

Ubuntu 26.04.1 / WSL2, GCC 15.2.0, Ninja Release, bundled dependencies, BUILD_TESTING=ON. Built the real libc and libkernel libraries and all their Linux-registered test targets. All 187 scoped tests passed (66 libc, 121 libkernel), no skips or failures, 3.73 s. guest_select passed in 0.30 s, including idle/readable/writable pipes, simultaneous pipe/socket readiness and closed-descriptor EBADF. Conventions and whitespace checks passed on the integration branch.

This was a scoped library build and native Linux test run, not a full Linux application build or a Linux RetroArch run. No further game run was performed. AI-assisted validation with Codex; Claude's original implementation remains unchanged.

@p3n1cillin p3n1cillin mentioned this pull request Oct 13, 2026
10 tasks done

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

Reusing PipeReadiness from poll keeps the two consistent. One timing detail: the new Windows HostPoll loop waits with std::this_thread::sleep_for(std::chrono::milliseconds(1)). On Windows that sleep follows the coarse system tick and usually takes about 15.6 ms, as measured in #1471, which is why #4980 (poll) and #4754 (select timeouts) move these waits to PreciseSleepUs.

For libmicrohttpd's wake-up pipe, that means each wake-up of the MHD-worker thread can be delayed by up to ~15 ms. A select with a short timeout also overshoots it by the same amount. PreciseSleepUs(1000) (high-resolution waitable timer, no spinning) gives the 1 ms slice the description intends at the same CPU cost.

@oneandonlydean oneandonlydean self-assigned this Oct 14, 2026
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
select now checks pipe descriptors on Windows with the readiness test poll
already uses, so a pipe next to a libSceNet socket no longer throws.
RetroArch (PPSA99169) selects on libmicrohttpd's wake-up pipe beside its
listening socket. guest_select now runs on Windows too.

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

Copy link
Copy Markdown
Author

Rebased onto main 78f1aea70 (head f288daf6f). main now has precise select timeouts and the new guest_select_wait test. I kept both: the two includes in Socket.cpp, and in CMake guest_select_wait stays as it is while guest_select is registered on Windows too, as before. main's HostPoll still only polls host descriptors on Unix, so the Windows pipe path is still needed. On Windows (MinGW GCC 15, Release), guest_select and guest_select_wait pass, the libkernel suite passes (one guest_memory failure under -j8 passes 3/3 alone and is unrelated), and the conventions check passes.

@github-actions github-actions Bot removed the needs rebase Conflicts with main, rebase needed label Oct 14, 2026
@oneandonlydean
oneandonlydean merged commit 1a40d3d into boykopovar:main Oct 14, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants