Merge nucleic/lucid-river-toad-6efj into dev

This commit is contained in:
2026-07-29 17:09:35 -07:00
parent 1e6068e273
commit e41bafdb7c
7 changed files with 305 additions and 44 deletions
+31 -2
View File
@@ -64,14 +64,32 @@ public interface IWslc
/// <summary>cgroup counters for the resource monitor; null when not running.</summary>
Task<ContainerStatsInfo?> ContainerStatsAsync(string name, CancellationToken ct);
/// <summary>Start a process in a running container. `procId` is minted by the broker and
/// keys every event this process emits through <see cref="IBrokerEvents"/>.</summary>
/// <summary>
/// Create a process in a running container and attach its event handlers, but **do not run
/// it** — the caller runs it with <see cref="IWslcProcess.StartAsync"/> once it has sent the
/// `procId` downstream. `procId` is minted by the broker and keys every event this process
/// emits through <see cref="IBrokerEvents"/>.
///
/// The two-step split is not ceremony. See <see cref="IWslcProcess.StartAsync"/>.
/// </summary>
Task<IWslcProcess> ExecAsync(long procId, ProcSpec spec, CancellationToken ct);
}
/// <summary>Control half of a running in-container process (output arrives via events).</summary>
public interface IWslcProcess
{
/// <summary>
/// Actually run the process. Separate from <see cref="IWslc.ExecAsync"/> because a short
/// command can finish before the `proc.exec` RESPONSE has been written: output and exit ride
/// the same ordered outbound queue, so starting first puts `proc.exit` on the wire ahead of
/// the `procId` that identifies it, and a client that registers interest on receiving that
/// procId waits forever. Observed on hardware with `echo` (docs/WINDOWS_PORT.md §13.3).
///
/// This is the same reasoning that makes wslc itself split `CreateProcess` from `Start` — so
/// handlers can attach before output flows — applied one level up, to the RPC boundary.
/// </summary>
Task StartAsync(CancellationToken ct);
Task WriteStdinAsync(ReadOnlyMemory<byte> data, CancellationToken ct);
Task CloseStdinAsync(CancellationToken ct);
Task SignalAsync(int signal, CancellationToken ct);
@@ -107,6 +125,17 @@ public sealed class WslcError(string kind, string message) : Exception(message)
/// permanent capability gap, not a transient failure — hostd must not retry.</summary>
public const string Unsupported = "unsupported";
/// <summary>
/// A CONTAINER of that name already exists in the session. Distinct from
/// <see cref="SessionExists"/> because wslc answers `ERROR_ALREADY_EXISTS` for both and the
/// remedies differ completely — remove one container, versus restart the whole WSL stack.
///
/// Reachable today because this broker's container roster is process-local (there is no
/// enumeration on the compat surface), so a container left behind by a crashed broker holds
/// its name against every later one. See docs/WINDOWS_PORT.md §13.3.
/// </summary>
public const string AlreadyExists = "already_exists";
/// <summary>A session of that name is already running and this facade cannot re-adopt it
/// (the compat SDK's `Start()` answers ERROR_ALREADY_EXISTS, and its constructor is lazy, so
/// a second handle is not a second session). Distinct from <see cref="StartFailed"/> because