feat(client): allow TAP adapter sharing across threads

The Windows client frame pump needs one task reading TAP frames while another
writes relay frames back to the adapter. The TAP crate already owns the raw
Windows file handle; this change makes the handle's thread-safety boundary
explicit with `Send` and `Sync` impls and documents the Windows handle
assumption next to the unsafe code.

This does not add the pump yet. It only prepares the adapter type for the
separate read/write loops that will wire TAP I/O to the relay session.

Test Plan:
- cargo fmt --check
- cargo test --workspace
- cargo clippy --workspace --all-targets -- -D warnings
- CC_x86_64_pc_windows_msvc=clang-cl AR_x86_64_pc_windows_msvc=llvm-lib \
  CARGO_TARGET_X86_64_PC_WINDOWS_MSVC_LINKER=lld-link cargo clippy \
  -p lanparty-client-tap --target x86_64-pc-windows-msvc -- -D warnings
- git diff --check

Refs: PLAN.md
This commit is contained in:
2026-05-21 18:59:58 +02:00
parent 70fb23b538
commit c0d4fdf7b4
+10
View File
@@ -234,6 +234,16 @@ pub fn available_adapters() -> Result<Vec<TapAdapterInfo>> {
#[derive(Debug)] #[derive(Debug)]
struct OwnedHandle(HANDLE); struct OwnedHandle(HANDLE);
// SAFETY: Windows file handles are process-wide kernel object references that may be used from
// multiple threads. `OwnedHandle` only closes the handle in `Drop`; callers must still uphold any
// higher-level synchronization required by the device protocol.
unsafe impl Send for OwnedHandle {}
// SAFETY: Sharing references to `OwnedHandle` only exposes the raw handle to synchronous Windows
// APIs. The handle value itself is immutable, and Windows permits issuing I/O on a file handle from
// more than one thread.
unsafe impl Sync for OwnedHandle {}
impl OwnedHandle { impl OwnedHandle {
fn new(handle: HANDLE) -> io::Result<Self> { fn new(handle: HANDLE) -> io::Result<Self> {
if handle == INVALID_HANDLE_VALUE { if handle == INVALID_HANDLE_VALUE {