Skip to content

Migrate relay IO to MultiHandleWait infrastructure#40730

Draft
benhillis wants to merge 1 commit into
masterfrom
benhill/migrate-relays-to-new-io
Draft

Migrate relay IO to MultiHandleWait infrastructure#40730
benhillis wants to merge 1 commit into
masterfrom
benhill/migrate-relays-to-new-io

Conversation

@benhillis

Copy link
Copy Markdown
Member

Summary

Migrates the old hand-rolled overlapped IO relay loops to the newer MultiHandleWait/RelayHandle/ReadHandle system, reducing code by ~284 lines while consolidating all IO patterns into a single infrastructure.

PR Checklist

  • Builds cleanly
  • Formatted with FormatSource.ps1
  • Tested with test.bat

Detailed Description

What changed

  • InterruptableRelay, BidirectionalRelay, ScopedMultiRelay::Run, ScopedRelay::Run - rewritten to use MultiHandleWait directly instead of manual ReadFile/WriteFile + WaitForMultipleObjects + CancelIoEx scope guards
  • Dmesg read loop & GuestTelemetryLogger read loop - replaced manual InterruptableRead loops with ReadHandle + MultiHandleWait + EventHandle for exit signals
  • InterruptableRead/Write/Wait - moved canonical implementations to wsl::windows::common::io namespace in HandleIO.h/cpp; removed redundant relay:: forwarding wrappers; updated all callers to use io:: directly
  • CreateThread - collapsed 4 overloads into a single variadic template
  • ReadHandle/RelayHandle - added configurable BufferSize parameter
  • Dead code removed - CancelPendingIo, InitializeFileOffset, manual overlapped loops

Design decisions

  • HandleWrapper(HANDLE) is non-owning - used where the same handle is managed elsewhere
  • IgnoreErrors flag on read handles ensures pipe disconnects don't throw
  • CancelOnCompleted | NeedNotComplete on exit events ensures clean cancellation without requiring the event to fire
  • Null output handle in InterruptableRelay uses a drain-only ReadHandle (no-op callback) instead of RelayHandle to avoid writing to invalid handle

Validation Steps

  • Full build passes (all projects including wsltests.dll)
  • FormatSource.ps1 clean

Copilot AI review requested due to automatic review settings June 6, 2026 06:19

Copilot AI 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.

Pull request overview

This PR migrates multiple service/common IO relay paths from bespoke overlapped IO loops to the shared wsl::windows::common::io infrastructure (MultiHandleWait + ReadHandle/RelayHandle/EventHandle). This consolidates relay behavior across the codebase and removes duplicated cancellation/wait logic.

Changes:

  • Replaces manual relay/read loops in several components with MultiHandleWait + handle abstractions (relay, dmesg, guest telemetry logger).
  • Moves the standalone cancellable InterruptableRead/Write/Wait implementations into wsl::windows::common::io and updates call sites accordingly.
  • Simplifies relay thread creation by collapsing multiple CreateThread overloads into a single templated helper, and adds configurable buffer sizing for ReadHandle/RelayHandle.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/windows/service/exe/LxssUserSession.cpp Updates callers to use wsl::windows::common::io::InterruptableRead/Wait directly.
src/windows/service/exe/GuestTelemetryLogger.cpp Replaces the manual overlapped read loop with MultiHandleWait + ReadHandle and exit EventHandles.
src/windows/common/relay.hpp Collapses multiple CreateThread overloads into a single template wrapper around InterruptableRelay.
src/windows/common/relay.cpp Rewrites relay helpers (InterruptableRelay, BidirectionalRelay, ScopedRelay::Run, ScopedMultiRelay::Run) to use MultiHandleWait + RelayHandle/ReadHandle.
src/windows/common/HandleIO.h Adds buffer size configuration to ReadHandle and propagates it through RelayHandle; declares standalone interruptable IO helpers in io namespace.
src/windows/common/HandleIO.cpp Implements standalone io::InterruptableRead/Write/Wait and updates ReadHandle to allocate its buffer based on the new size parameter.
src/windows/common/Dmesg.cpp Replaces the manual interruptable read loop with MultiHandleWait + ReadHandle and uses io::InterruptableWrite for output/com1 writes.

Comment thread src/windows/common/HandleIO.cpp Outdated
Comment on lines +212 to +213
ReadHandle::ReadHandle(HandleWrapper&& MovedHandle, std::function<void(const gsl::span<char>& Buffer)>&& OnRead, size_t BufferSize) :
Handle(std::move(MovedHandle)), OnRead(OnRead), Buffer(BufferSize), Offset(InitializeFileOffset(Handle.Get()))
- Rewrite InterruptableRelay, BidirectionalRelay, ScopedMultiRelay::Run,
  and ScopedRelay::Run to use MultiHandleWait directly
- Rewrite Dmesg read loop and GuestTelemetryLogger read loop to use
  ReadHandle + MultiHandleWait + EventHandle for exit signals
- Move InterruptableRead/Write/Wait canonical implementations to
  wsl::windows::common::io namespace in HandleIO.h/cpp; remove redundant
  relay:: forwarding wrappers and update all callers to use io:: directly
- Collapse 4 CreateThread overloads into a single variadic template
- Add configurable BufferSize parameter to ReadHandle/RelayHandle
- Remove dead code (CancelPendingIo, InitializeFileOffset, manual
  overlapped loops)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@benhillis benhillis force-pushed the benhill/migrate-relays-to-new-io branch from 2b9a867 to 8f442d2 Compare June 6, 2026 07:01
@benhillis benhillis requested a review from Copilot June 8, 2026 16:15

Copilot AI 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.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 6 comments.

}
ioWait.AddHandle(
std::make_unique<io::RelayHandle<io::ReadHandle>>(io::HandleWrapper{InputHandle}, io::HandleWrapper{OutputHandle}, BufferSize),
io::MultiHandleWait::IgnoreErrors | io::MultiHandleWait::CancelOnCompleted);
ioWait.AddHandle(
std::make_unique<io::ReadHandle>(
io::HandleWrapper{InputHandle}, [](const gsl::span<char>&) {}, BufferSize),
io::MultiHandleWait::IgnoreErrors | io::MultiHandleWait::CancelOnCompleted);
io::MultiHandleWait ioWait;
ioWait.AddHandle(
std::make_unique<io::RelayHandle<io::ReadHandle>>(io::HandleWrapper{Input}, io::HandleWrapper{Output}, BufferSize),
io::MultiHandleWait::IgnoreErrors | io::MultiHandleWait::CancelOnCompleted);
}
},
BufferSize),
io::MultiHandleWait::IgnoreErrors);
ProcessInput(std::string_view{buffer.data(), static_cast<size_t>(buffer.size())});
}
}),
io::MultiHandleWait::IgnoreErrors);
ProcessInput(Source, buffer);
}
}),
io::MultiHandleWait::IgnoreErrors);
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