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 on: the compat SDK exposes a `Session` *constructor* and no attach, so does constructing over an
existing name re-adopt it, or refuse? existing name re-adopt it, or refuse?
- **Refused** (`WSLC_E_SESSION_RESERVED`, `0x80040607`) — D13's premise is confirmed, and session **Answered on 2.9.4: it cannot.** The constructor is lazy and always succeeds — judging by it is
reattach genuinely requires `IWSLCSessionManager::OpenSessionByName` on the internal interface. what made the first reading of this probe wrong. `Start()` is where the service is consulted, and
- **Constructed** — which is what 2.9.4 actually does. That alone proves nothing (construction may a second `Start()` on a running name fails with `ERROR_ALREADY_EXISTS` (0x800700B7). Note it is
be lazy), so the probe then runs an **identity test**: terminate the FIRST session and read from *not* `WSLC_E_SESSION_RESERVED`, which exists in `wslc.idl` but evidently means something
the SECOND. A read that worked before and fails after is one underlying session answering both narrower — don't key on it.
handles; a read that keeps working means two independent VMs were running.
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 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 `wslc session ls` — but **`wslc.exe` is not on PATH by default**, so a spike that depends on it
+40 -15
View File
@@ -15,10 +15,11 @@ namespace WslcApiDump;
/// ///
/// It never mutates anything unless asked: the default run only reads type metadata. `--probe` /// It never mutates anything unless asked: the default run only reads type metadata. `--probe`
/// additionally calls the two safe statics (`GetVersion`, `GetMissingComponents`). `--session` /// 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 /// goes further and creates a real session, then a SECOND one with the same name, to settle
/// is the open question D13 turns on: whether the compat SDK's constructor can re-adopt a session /// whether the compat SDK can re-adopt a running session. Answered on 2.9.4: it cannot. The
/// by name, or refuses with `WSLC_E_SESSION_RESERVED` and leaves reattach to the internal COM /// constructor is lazy and always succeeds; `Start()` is where the service is consulted, and it
/// interface (docs/WINDOWS_PORT.md §13.1). /// refuses with `ERROR_ALREADY_EXISTS`. So reattach needs the internal COM interface, which is
/// what D13 assumes (docs/WINDOWS_PORT.md §13.1).
/// </summary> /// </summary>
internal static class Program internal static class Program
{ {
@@ -402,18 +403,38 @@ internal static class Program
} }
else else
{ {
// Starting it is one more signal: re-adopting a RUNNING session should be a no-op, // The constructor is LAZY — it only captures settings, so its success says nothing.
// whereas a genuinely separate session would be booting a second VM here. // `Start()` is where the service is actually asked for the session, and therefore
if (start is not null) // 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"); } Console.WriteLine(" (no Session.Start() — cannot judge)");
catch (TargetInvocationException e) }
{ else
Console.WriteLine($" second Start() threw {Describe(e.InnerException)}"); {
} try { start.Invoke(second, null); secondStarted = true; }
catch (TargetInvocationException e) { startFailure = Describe(e.InnerException); }
}
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(" → CONSTRUCTED — the constructor did NOT refuse.");
IdentityTest(sessionType, first, second);
} }
Console.WriteLine(); Console.WriteLine();
if (keep) if (keep)
@@ -447,7 +468,8 @@ internal static class Program
Console.WriteLine(" identity test: terminate the FIRST, then read from the SECOND"); Console.WriteLine(" identity test: terminate the FIRST, then read from the SECOND");
if (!Reads(getImages, second, out var before)) 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; return;
} }
Console.WriteLine(" second reads ok before termination"); 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 " 0x80070032 => "ERROR_NOT_SUPPORTED — the installed WSL does not implement this call "
+ "(almost always: WSL is older than the SDK)", + "(almost always: WSL is older than the SDK)",
0x80070005 => "E_ACCESSDENIED", 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", 0x80040601 => "WSLC_E_IMAGE_NOT_FOUND",
0x80040603 => "WSLC_E_CONTAINER_NOT_FOUND", 0x80040603 => "WSLC_E_CONTAINER_NOT_FOUND",
0x80040605 => "WSLC_E_CONTAINER_NOT_RUNNING", 0x80040605 => "WSLC_E_CONTAINER_NOT_RUNNING",