Skip to content

refactor: from guest threads to EE scheduler - #184

Draft
ran-j wants to merge 1 commit into
mainfrom
feature/remove-runtime-guest-threads
Draft

refactor: from guest threads to EE scheduler#184
ran-j wants to merge 1 commit into
mainfrom
feature/remove-runtime-guest-threads

Conversation

@ran-j

@ran-j ran-j commented Jul 26, 2026

Copy link
Copy Markdown
Owner

No description provided.

@smmathews

smmathews commented Jul 26, 2026

Copy link
Copy Markdown
Contributor

Spent some time comparing this head-on with my #137, since they're really two takes on the same thing. Both kill the per-guest-thread host threads and put everything on one executor, we just picked different suspension mechanisms (I park fibers, you unwind with EeDispatcherTransfer and re-dispatch by PC). They can't merge together, so I benchmarked and probed both to figure out which one deserves to live. Short version: I think yours does. Reasoning below so you can check my work.

Why I prefer this over #137:

  • Portability. You need C++ exceptions, which every target already builds with. I need a working fiber backend per platform: ucontext is gone on Bionic and deprecated on macOS, and my Android fallback ends up running each fiber as a real OS thread with a pair of semaphores, which quietly resurrects the exact N-thread model we're both trying to delete, on the most constrained target.
  • Memory. A blocked thread here is ~32 bytes of continuation; mine reserves a 1 MiB stack plus a guard page per guest thread.
  • Savestates, eventually. Your blocked thread is plain serializable data ({context, wait reason, completion}); a parked fiber stack is opaque machine state. If this project ever wants savestates, your model is much closer.
  • Fibers do win raw switch cost (I measured ~196 ns/handoff vs ~420 ns for throw+redispatch, and throw cost grows with unwind depth while swapcontext is flat), but at PS2 switch rates that's sub-millisecond per wall-second, so it doesn't move the needle.

The one thing I had to check first: fibers can block in the middle of an HLE helper and keep the live C++ frame; your model structurally can't (the throw destroys the frame). I wrote a small probe test against this branch to see how much that matters, and it turns out your answer is already in here: waitExternal's completion carries host state by value across the block, and the only in-tree helper that actually blocks mid-computation with live state (the MPEG picture pacing) is already written in that shape. So it's an authoring pattern future HLE code has to follow, not a missing capability. Happy to PR the probe test into this branch if you want it; it documents the resume semantics as tests (helper body runs twice, tail never runs, completion carries the value).

What I'd like to bring over from #137 before I close it:

  1. The test suite (~6k lines of scheduler/EE-semantics tests). Most of it drives the shared handleSyscall/registerFunction surface, so it retargets onto EeScheduler mostly mechanically. I'm happy to do that port.
  2. The bug list feat: N=1 cooperative fiber scheduler replacing per-thread host threads #137 paid for, as regression tests: the RotateThreadReadyQueue lone-runnable-thread short-circuit (you've already got the caller-rotation right here, this is the remaining edge), suspend-gated wakeups, thread-id-reuse ABA on wakeup, the alarm-cancel-vs-fire race, and WaitSema-with-count-available not yielding.
  3. A written exception-safety contract for HLE authors. The discipline your model needs is global and the compiler won't enforce it (any catch(...) swallowing the transfer, or a raw lock held across a blocking syscall, silently breaks a wait). Worth a short doc section so it survives contributors.
  4. One heads-up for the PR body: the resume-PC publication means pre-refactor: from guest threads to EE scheduler #184 generated output needs regenerating. Worth calling out for anyone carrying big generated dirs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants