Merge nucleic/olive-jade-civet-rznt into dev

This commit is contained in:
2026-07-29 01:10:27 -07:00
parent 88175578fc
commit 9f125628a0
2 changed files with 50 additions and 21 deletions
+10 -6
View File
@@ -87,12 +87,16 @@ name**. That second construction is the whole point, and it is the last open que
on: the compat SDK exposes a `Session` *constructor* and no attach, so does constructing over an
existing name re-adopt it, or refuse?
- **Refused** (`WSLC_E_SESSION_RESERVED`, `0x80040607`) — D13's premise is confirmed, and session
reattach genuinely requires `IWSLCSessionManager::OpenSessionByName` on the internal interface.
- **Constructed** — which is what 2.9.4 actually does. That alone proves nothing (construction may
be lazy), so the probe then runs an **identity test**: terminate the FIRST session and read from
the SECOND. A read that worked before and fails after is one underlying session answering both
handles; a read that keeps working means two independent VMs were running.
**Answered on 2.9.4: it cannot.** The constructor is lazy and always succeeds — judging by it is
what made the first reading of this probe wrong. `Start()` is where the service is consulted, and
a second `Start()` on a running name fails with `ERROR_ALREADY_EXISTS` (0x800700B7). Note it is
*not* `WSLC_E_SESSION_RESERVED`, which exists in `wslc.idl` but evidently means something
narrower — don't key on it.
So the probe judges on `Start()`. If a future version lets the second `Start()` through, it then
runs an **identity test**: terminate the FIRST session and read from the SECOND. A read that
worked before and fails after is one underlying session answering both handles; a read that keeps
working means two independent VMs.
The identity test deliberately uses only the compat SDK. The obvious check would be
`wslc session ls` — but **`wslc.exe` is not on PATH by default**, so a spike that depends on it
+38 -13
View File
@@ -15,10 +15,11 @@ namespace WslcApiDump;
///
/// It never mutates anything unless asked: the default run only reads type metadata. `--probe`
/// additionally calls the two safe statics (`GetVersion`, `GetMissingComponents`). `--session`
/// goes further and creates a real session, then creates a SECOND one with the same name — which
/// is the open question D13 turns on: whether the compat SDK's constructor can re-adopt a session
/// by name, or refuses with `WSLC_E_SESSION_RESERVED` and leaves reattach to the internal COM
/// interface (docs/WINDOWS_PORT.md §13.1).
/// goes further and creates a real session, then a SECOND one with the same name, to settle
/// whether the compat SDK can re-adopt a running session. Answered on 2.9.4: it cannot. The
/// constructor is lazy and always succeeds; `Start()` is where the service is consulted, and it
/// refuses with `ERROR_ALREADY_EXISTS`. So reattach needs the internal COM interface, which is
/// what D13 assumes (docs/WINDOWS_PORT.md §13.1).
/// </summary>
internal static class Program
{
@@ -402,19 +403,39 @@ internal static class Program
}
else
{
// Starting it is one more signal: re-adopting a RUNNING session should be a no-op,
// whereas a genuinely separate session would be booting a second VM here.
if (start is not null)
// The constructor is LAZY — it only captures settings, so its success says nothing.
// `Start()` is where the service is actually asked for the session, and therefore
// where exclusivity is enforced. Judge on that.
var secondStarted = false;
string? startFailure = null;
if (start is null)
{
try { start.Invoke(second, null); Console.WriteLine(" second Start() ok"); }
catch (TargetInvocationException e)
Console.WriteLine(" (no Session.Start() — cannot judge)");
}
else
{
Console.WriteLine($" second Start() threw {Describe(e.InnerException)}");
try { start.Invoke(second, null); secondStarted = true; }
catch (TargetInvocationException e) { startFailure = Describe(e.InnerException); }
}
}
Console.WriteLine(" → CONSTRUCTED — the constructor did NOT refuse.");
if (secondStarted)
{
Console.WriteLine(" second Start() ok — it did NOT refuse, so it may have re-adopted");
IdentityTest(sessionType, first, second);
}
else if (startFailure is not null)
{
Console.WriteLine($" second Start() threw {startFailure}");
Console.WriteLine();
Console.WriteLine(" → REFUSED at Start(). The constructor succeeding meant nothing:");
Console.WriteLine(" it is lazy, and the service is only consulted by Start().");
Console.WriteLine(" So the compat SDK CANNOT re-adopt a running session, and D13");
Console.WriteLine(" holds — §2.3 reattach needs IWSLCSessionManager::OpenSessionByName");
Console.WriteLine(" (or EnterSession) on the internal COM interface.");
Console.WriteLine(" Note the code is ERROR_ALREADY_EXISTS, not WSLC_E_SESSION_RESERVED;");
Console.WriteLine(" the reserved code evidently means something narrower.");
}
}
Console.WriteLine();
if (keep)
{
@@ -447,7 +468,8 @@ internal static class Program
Console.WriteLine(" identity test: terminate the FIRST, then read from the SECOND");
if (!Reads(getImages, second, out var before))
{
Console.WriteLine($" inconclusive — the second session already fails to read: {before}");
// Only reachable if Start() reported success but the session is unusable anyway.
Console.WriteLine($" inconclusive — the second session reads fail already: {before}");
return;
}
Console.WriteLine(" second reads ok before termination");
@@ -564,6 +586,9 @@ internal static class Program
0x80070032 => "ERROR_NOT_SUPPORTED — the installed WSL does not implement this call "
+ "(almost always: WSL is older than the SDK)",
0x80070005 => "E_ACCESSDENIED",
0x800700B7 => "ERROR_ALREADY_EXISTS — a session of that name is already running",
0x8000000E => "E_ILLEGAL_METHOD_CALL — the object is not in a state to serve this call "
+ "(e.g. Session.Start() was never called, or failed)",
0x80040601 => "WSLC_E_IMAGE_NOT_FOUND",
0x80040603 => "WSLC_E_CONTAINER_NOT_FOUND",
0x80040605 => "WSLC_E_CONTAINER_NOT_RUNNING",