Skip to content

Add per-PTY dispatch-source I/O path as alternative to TaskNotifier select loop#587

Draft
chall37 wants to merge 1 commit into
gnachman:masterfrom
chall37:feat/per-pty-dispatch-sources-pr
Draft

Add per-PTY dispatch-source I/O path as alternative to TaskNotifier select loop#587
chall37 wants to merge 1 commit into
gnachman:masterfrom
chall37:feat/per-pty-dispatch-sources-pr

Conversation

@chall37
Copy link
Copy Markdown
Contributor

@chall37 chall37 commented Feb 20, 2026

Summary

  • Adds PTYTaskIOHandler: one serial dispatch queue per PTY with dispatch sources for read/write/process events, as
    an alternative to the shared TaskNotifier select() loop.
  • Gates this path behind UsePerPTYDispatchSources (advanced setting, default off, restart required).
  • Introduces routing helpers PTYTask.registerTaskWithNotifier: / deregisterTaskFromNotifier: so job managers are
    agnostic to the active I/O path.
  • Adds backpressure-aware read control in per-PTY mode:
    • TokenExecutor now exposes a BackpressureLevel derived from available token-buffer slots.
    • PTY reads are suppressed under heavy pressure and resumed via a release callback wired from
      PTYSession.taskDidRegister:.
  • Ensures suspended-read EOF delivery remains reliable by monitoring child exit and resuming reads to drain final
    data / broken-pipe.
  • Keeps legacy behavior safe by restricting backpressure-gated read suppression to per-PTY mode (legacy TaskNotifier
    path continues unchanged in this area).

Relationship To Fairness Scheduler

This PR was split out of #580 to stand alone per discussion. A few choices reflect that extraction:

  • BackpressureLevel granularitynone/light/moderate/heavy/blocked is introduced even though this PR
    currently gates only on >= heavy. The extra levels are intended to support future scheduler policy/budget
    decisions.
  • Backpressure gating is per-PTY onlywantsRead applies backpressure gating only when an ioHandler exists.
    Legacy TaskNotifier mode has no pressure-release wakeup, so gating there can stall reads. Future scheduler wiring
    can unify this behavior across both paths.

@chall37 chall37 marked this pull request as draft February 20, 2026 21:15
…loop

Replace the shared TaskNotifier select() loop with per-PTY serial
dispatch queues, each owning DispatchSource read/write/process sources.
Gated behind the UsePerPTYDispatchSources advanced setting (default off).

Key design:
- PTYTaskIOHandler owns the ioQueue and all dispatch sources for one PTY
- DISPATCH_SOURCE_TYPE_PROC monitors child exit to force-resume the read
  source for EOF delivery even when suspended for backpressure/pause
- Backpressure integration: TokenExecutor tracks available slots via an
  atomic counter; when heavy backpressure is detected, wantsRead returns
  false and the read source suspends. A backpressureReleaseHandler wired
  in PTYSession re-evaluates read state when pressure drops
- Backpressure-gated reads are restricted to per-PTY mode to avoid
  stalling the legacy TaskNotifier path which has no wake-up mechanism
- Registration routing via PTYTask class methods so job managers do not
  need to know which I/O path is active
- Coprocess sources are serialized on ioQueue to prevent data races
  with event handlers

Includes comprehensive test coverage: lifecycle, state predicates,
EOF detection, read/write round-trips, coprocess management, and
concurrency regression tests.
@chall37 chall37 force-pushed the feat/per-pty-dispatch-sources-pr branch from d7f0a27 to 3360501 Compare February 20, 2026 21:37
@gnachman
Copy link
Copy Markdown
Owner

Thanks for taking the time to put this together! I'm trying to review it but I don't think I can do a good job on a PR of this size. This is critical infrastructure so it's better to be slow and methodical. Probably it would make the most sense to chat about it instead of trying to discuss it asynchronously in a PR. LMK what's a good time when you have an hour or so and we can talk through what's going on here and what would be the best way to proceed. I'm pretty slammed until Tuesday, so any time after that should be fine.

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