Merge nucleic/olive-jade-civet-rznt into dev
This commit is contained in:
+10
-6
@@ -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
|
||||
|
||||
@@ -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,18 +403,38 @@ 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($" second Start() threw {Describe(e.InnerException)}");
|
||||
}
|
||||
Console.WriteLine(" (no Session.Start() — cannot judge)");
|
||||
}
|
||||
else
|
||||
{
|
||||
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();
|
||||
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",
|
||||
|
||||
Reference in New Issue
Block a user