Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions context/design.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ The implementations live under `scheduler/selector/`, selected with Cargo featur

The Linux `io-uring` feature selects a dedicated ring for socket/file reads and writes and `file_sync`. `file_truncate` uses the ring when its opcode is available, with a blocking-file fallback on older kernels. Optional `FileAllocate` adds Linux range reservation with `AllocationMode::Extend` or `KeepSize`, using a probed `Fallocate` request or the blocking syscall fallback. Other platforms currently omit that capability. Synchronization, allocation, and native truncation retain the file without a payload buffer and use the same original-completion retirement contract as transfers. Connect, accept, explicit readiness waits and sleep still use async-io. Initialization probes required opcodes and reliable completion overflow; it returns an error if unavailable rather than silently changing implementation. Shutdown cancels and drains original completions. Operation identifiers are never reused, and cancellation completions cannot release original buffers. Unexpected selector failure retains resources whose kernel lifetime cannot be established and panics their waiting operations. Normal cancellation does not retain completed resources.

The owned-buffer API supports `IoBuf`, `IoBufMut`, and `BufferSlice`, returning `(OperationResult<usize>, B)` with ownership on every normal result. Read buffers must already have an initialized length. Operations may be partial; dropping a waiting future can abandon I/O that consumes or transmits bytes. Socket and listener types are associated with the concrete implementation. Tokio registrations reject use through another runtime's adapter.
The owned-buffer API supports `IoBuf`, `IoBufMut`, and `BufferSlice`, returning `(OperationResult<usize>, B)` with ownership on every normal result. Read buffers must already have an initialized length. Operations may be partial; dropping a waiting future can abandon I/O that consumes or transmits bytes. Each implementation chooses one associated socket resource for both accepted and listening sockets. Tokio registrations reject use through another runtime's adapter.

This is an initial implementation: each ring operation uses a boxed typed request, a command, and a completion channel, and operation records and buffers are not pooled. General descriptors, UDP and native overlapped Windows files remain future work. Blocking file operations can outlive task cancellation; neither Socketry nor the Tokio adapter shuts down the process-wide or external blocking pool.
This is an initial implementation: each ring operation uses a boxed typed request, a command, and a completion channel, and operation records and buffers are not pooled. Raw descriptor import beyond std TCP, socket message/address APIs, and native overlapped Windows files remain future work. Blocking file operations can outlive task cancellation; neither Socketry nor the Tokio adapter shuts down the process-wide or external blocking pool.

## Timer port

Expand Down
4 changes: 2 additions & 2 deletions context/gaps.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ The executor does not expose a Barrier or require a group/owner argument. Librar

## 3. The I/O boundary is still narrow

`Socket` covers TCP listener creation, address inspection, connect, accept, reads, writes, and readiness. OS-resource import is a separate `SocketRegistration` capability. `File` opens associated resources and borrows them for seeking, truncation, synchronization, shared-cursor and positioned I/O. Explicit close/submission now consumes an exclusively owned handle, and optional `FileAllocate` supplies Linux allocation. Metadata hooks remain to implement. File/socket operations support cancellation and owned buffer views. `Clock` supplies monotonic time and cancellable absolute and relative waits.
`Socket` uses one associated resource type for unconnected, bound, listening, connected, and datagram sockets. It exposes `socket_open`, `socket_bind`, syscall-like `socket_listen`, `socket_connect`, `socket_accept`, address inspection, reads, writes, and readiness. The initial API supports IPv4/IPv6 and stream/datagram sockets with optional TCP/UDP protocol selection. OS-resource import is a separate `SocketRegistration` capability. Socket close/shutdown, options, message/address APIs, and ancillary data remain future work. `File` opens associated resources and borrows them for seeking, truncation, synchronization, shared-cursor and positioned I/O. Explicit close/submission now consumes an exclusively owned handle, and optional `FileAllocate` supplies Linux allocation. Metadata hooks remain to implement. File/socket operations support cancellation and owned buffer views. `Clock` supplies monotonic time and cancellable absolute and relative waits.

`Blocking` now adds bounded asynchronous admission for owned synchronous closures, implemented through dedicated native and Tokio pools. Existing file fallbacks still use backend pools. General socket creation/options, DNS, randomness, and processes remain outside the portable boundary. Deadline policies can now compose `Clock` and cancellation; higher-level timeout helpers remain separate. Ordinary synchronization uses futures and wakers above scheduler primitives. Expand capabilities as real consumers need them, keeping the application's implementation choice explicit. A broader boundary would also allow more operating-system behavior to be substituted in deterministic tests.
`Blocking` now adds bounded asynchronous admission for owned synchronous closures, implemented through dedicated native and Tokio pools. Existing file fallbacks still use backend pools. Socket options, message/address APIs, DNS, randomness, and processes remain outside the portable boundary. Deadline policies can now compose `Clock` and cancellation; higher-level timeout helpers remain separate. Ordinary synchronization uses futures and wakers above scheduler primitives. Expand capabilities as real consumers need them, keeping the application's implementation choice explicit. A broader boundary would also allow more operating-system behavior to be substituted in deterministic tests.

## 4. The backends establish behavior before performance

Expand Down
4 changes: 2 additions & 2 deletions context/implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ This guide describes the current implementation and its boundaries. Read [the de

## Interface experiment

`crates/executor/examples/interface_probe.rs` runs generic file-copy and echo-server functions against native, Tokio, and an in-memory implementation. It uses the exported `File` and `Socket` traits for associated resources, creation, cancellation and address inspection. It uses scheduler implementations directly and retries partial writes through owned buffer views. The simulator exercises short transfers and ordinary resource destruction without native I/O dependencies. It supports cancellation but does not model timers, kernel completion tracking, or a simulated task scheduler; findings and next changes are recorded in `crates/executor/design.md`.
`crates/executor/examples/interface_probe.rs` runs generic file-copy and echo-server functions against native, Tokio, and an in-memory implementation. It uses the exported `File` and `Socket` traits for associated resources, creation, cancellation and address inspection. Socket setup follows open, bind, and listen/connect steps; no listener-specific resource type is required. It uses scheduler implementations directly and retries partial writes through owned buffer views. The simulator exercises short transfers and ordinary resource destruction without native I/O dependencies. It supports cancellation but does not model timers, kernel completion tracking, or a simulated task scheduler; findings and next changes are recorded in `crates/executor/design.md`.

## Verification

Expand All @@ -95,7 +95,7 @@ Coverage measures source regions for native and Tokio schedulers on each support

## Explicit file closure

- Native and Tokio `File::File` is an owned, non-`Clone` `FileHandle`. Backend retention uses a private `Arc<std::fs::File>`; consuming it for close uses `Arc::try_unwrap` and panics on outstanding use. Do not cancel or wait for other operations during close.
- Native and Tokio `File::File` is an owned, non-`Clone` `FileDescriptor`. Backend retention uses a private `Arc<std::fs::File>`; consuming it for close uses `Arc::try_unwrap` and panics on outstanding use. Do not cancel or wait for other operations during close.
- `file_close` awaits bounded admission and execution; `file_close_submit` awaits only admission. Neither accepts cancellation. Accepted close jobs survive waiter destruction and run on a dedicated cleanup pool independent of user blocking closures. Native shutdown outside future and blocking-pool workers and awaited Tokio shutdown drain them. Completion and capacity wakeups run in blocking-pool worker context, so reentrant scheduler destruction requests shutdown without waiting on its own cleanup queue.
- All operation result notifications must follow release of backend file references, including cancellation and requests discarded before submission. io_uring still retains published requests until original terminal CQEs; cancellation CQEs cannot release them.
- `examples/file_close.rs` explains cancellation clones, keeping the operation future alive through cancellation, completion races, and explicit close before propagating an I/O result. Dropping an operation future abandons completion and may leave backend work running; io_uring requests cancellation, but immediate close can still panic until backend access ends.
Expand Down
7 changes: 4 additions & 3 deletions crates/executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ path = "src/lib.rs"
async-task = "4.7.1"
async-io = { version = "2.6.0", optional = true }
blocking = { version = "1.6.2", optional = true }
socket2 = { version = "0.6.3", optional = true }
crossbeam-deque = "0.8.7"
event-listener = "5.4.2"
futures-channel = "0.3.31"
Expand All @@ -27,18 +28,18 @@ libc = { version = "0.2.189", optional = true }
signal-hook = { version = "0.4.5", optional = true, default-features = false, features = ["iterator"] }

[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.61.2", optional = true, features = ["Win32_Foundation"] }
windows-sys = { version = "0.61.2", optional = true, features = ["Win32_Foundation", "Win32_Networking_WinSock"] }

[target.'cfg(target_os = "linux")'.dependencies]
io-uring = { version = "0.7.11", optional = true, features = ["io_safety"] }
polling = { version = "3.11.0", optional = true }

[features]
default = ["native"]
native = ["dep:async-io", "dep:blocking", "dep:libc", "dep:windows-sys"]
native = ["dep:socket2", "dep:async-io", "dep:blocking", "dep:libc", "dep:windows-sys"]
io-uring = ["native", "dep:io-uring", "dep:libc", "dep:polling"]
signals = ["dep:signal-hook"]
tokio = ["dep:tokio", "dep:libc", "dep:windows-sys"]
tokio = ["dep:socket2", "dep:async-io", "dep:tokio", "dep:libc", "dep:windows-sys"]

[dev-dependencies]
tokio = { version = "1.53.1", features = ["test-util"] }
Expand Down
Loading
Loading