Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
9db9e59
wslc: idle-terminate per-user container VMs and lazily restart
Jun 23, 2026
a708a01
wslc: don't pin the session VM for merely-created containers
Jun 26, 2026
aef3497
wslc: fix stale Created/Running comments on the activity hold
Jun 26, 2026
b74e68e
wslc: address idle-termination review feedback
Jun 30, 2026
8c860b8
wslc: update recovery warning tests for log-only behavior
Jun 30, 2026
fdb6bf7
wslc: address review feedback on lazy VM lifecycle
Jun 30, 2026
623aa41
wslc: use non-throwing filesystem::exists for storage VHD probe
Jul 2, 2026
6d5cb7e
wslc: extract WSLCSessionRuntime from WSLCSession
Jul 6, 2026
4625dde
fix formatting
Jul 6, 2026
e51b0d9
wslc: skip containerd VHD unmount when storage was never mounted
Jul 7, 2026
13f4601
wslc: publish termination reason before signaling the terminated event
Jul 8, 2026
8b0e5be
wslc: add idle-termination test hook and pass runtime into container …
Jul 9, 2026
89d478a
wslc: force-delete recovery test container on all exit paths
Jul 9, 2026
dc53500
Merge remote-tracking branch 'origin/master' into user/benhill/wslc-i…
Jul 9, 2026
c08eaa7
wslc: list WSLCIdleState.h in wslcsession HEADERS
Jul 9, 2026
bff5ec9
Merge remote-tracking branch 'origin/master' into user/benhill/wslc-i…
Jul 9, 2026
9a4bf16
wslc: clang-format Open() call site
Jul 9, 2026
1d80fe1
wslc: correct idle grace-period comment to reference IdleTimeoutSec
Jul 9, 2026
2faea8e
wslc: avoid reserved identifier in Fork structured binding
Jul 9, 2026
e9bdf88
Add WSLC VM start/stop plugin hooks
Jul 9, 2026
40b2c76
Pair OnVmStopping only when OnVmStarted fired
Jul 9, 2026
944c1f6
wslc: address PR feedback and harden idle-terminate VM lifecycle
Jul 13, 2026
0b50bde
Merge remote-tracking branch 'origin/master' into user/benhill/wslc-i…
Jul 13, 2026
c9f0872
wslc: fix reentrant deadlock in VM start/stop notifications
Jul 13, 2026
e46ec33
test: exercise reentrant mount from the WSLC OnVmStarted plugin hook
Jul 13, 2026
4fda245
wslc: hold a VmLease across container archive upload/download
Jul 13, 2026
d15a66e
test: fail fast instead of hanging on idle-termination deadlock detec…
Jul 13, 2026
1aedaa9
wslc: fix idle-teardown activity race and stopping-only hook pairing
Jul 13, 2026
d78e2d9
wslc: skip guest volume unmount when the VM has already exited
Jul 13, 2026
76e97ac
wslc: track VM-exited with an atomic to avoid a lock-free event race
Jul 14, 2026
058ef3d
wslc: close two VM-lifecycle races found in multi-model review
Jul 14, 2026
911d458
wslc: narrow the WSLCSession/WSLCSessionRuntime seam
Jul 14, 2026
93b017d
wslc: mark per-operation activity leases [[maybe_unused]]
Jul 14, 2026
7c639d6
wslc: fix idle-timer crash race and notification ordering race
Jul 16, 2026
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 src/windows/common/WSLCSessionDefaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,6 @@ inline constexpr const wchar_t DefaultAdminSessionName[] = L"wslc-cli-admin";
inline constexpr const wchar_t DefaultStorageSubPath[] = L"wslc\\sessions";
inline constexpr const wchar_t DefaultStorageVhdName[] = L"storage.vhdx";
inline constexpr uint32_t DefaultBootTimeoutMs = 30000;
inline constexpr const char ContainerdStorageMountPoint[] = "/var/lib/docker";

} // namespace wsl::windows::wslc
8 changes: 8 additions & 0 deletions src/windows/common/WSLCUserSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ static constexpr std::string_view s_DefaultSettingsTemplate =
" # used without an explicit address (default: 127.0.0.1)\n"
" # defaultBindingAddress: default\n"
"\n"
" # Seconds an idle session VM stays running before it is torn down (default: 30)\n"
" # idleTimeout: default\n"
"\n"
"# Credential storage backend: \"wincred\" or \"file\" (default: wincred)\n"
"# credentialStore: wincred\n";

Expand Down Expand Up @@ -163,6 +166,11 @@ namespace details {
return value;
}

WSLC_VALIDATE_SETTING(SessionIdleTimeout)
{
return value > 0 ? std::optional{value} : std::nullopt;
}

WSLC_VALIDATE_SETTING(CredentialStore)
{
if (value == "wincred")
Expand Down
2 changes: 2 additions & 0 deletions src/windows/common/WSLCUserSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum class Setting : size_t
SessionPortRelay,
SessionDefaultBindingAddress,
SessionStoragePath,
SessionIdleTimeout,

Max
};
Expand Down Expand Up @@ -101,6 +102,7 @@ namespace details {
DEFINE_SETTING_MAPPING(SessionPortRelay, std::string, PortRelayType, PortRelayType::VirtioNet, "experimental.portRelay")
DEFINE_SETTING_MAPPING(SessionDefaultBindingAddress, std::string, std::string, std::string{}, "session.defaultBindingAddress")
DEFINE_SETTING_MAPPING(SessionStoragePath, std::string, std::string, std::string{}, "session.storagePath")
DEFINE_SETTING_MAPPING(SessionIdleTimeout, uint32_t, uint32_t, 30, "session.idleTimeout")

#undef DEFINE_SETTING_MAPPING
// clang-format on
Expand Down
15 changes: 15 additions & 0 deletions src/windows/inc/WslPluginApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,19 @@ typedef HRESULT (*WSLPluginAPI_ImageCreated)(const struct WSLCSessionInformation
// Called when an image is deleted. 'ImageId' is the deleted image identifier. Errors are ignored.
typedef HRESULT (*WSLPluginAPI_ImageDeleted)(const struct WSLCSessionInformation* Session, LPCSTR ImageId);

// Called when the VM backing a WSLC session has started. Unlike OnSessionCreated (which fires once
// per session), this fires every time a VM is created for the session: on the first operation that
// needs a VM, and again each time the VM is recreated after being idle-terminated. Errors are logged
// but ignored (they do not abort VM startup or the triggering operation).
typedef HRESULT (*WSLPluginAPI_OnWslcVmStarted)(const struct WSLCSessionInformation* Session);

// Called when the VM backing a WSLC session is about to stop (idle teardown, explicit termination,
// or unexpected exit). Fires every time a VM is torn down, paired with a prior OnWslcVmStarted.
// Errors are logged but ignored. On an idle teardown the session remains alive, so a callback that
// needs the VM (e.g. WSLCCreateProcess) transparently restarts it; during a permanent session
// termination the same call fails cleanly because the session is being torn down.
typedef HRESULT (*WSLPluginAPI_OnWslcVmStopping)(const struct WSLCSessionInformation* Session);

//
// WSLC plugin API calls.
//
Expand Down Expand Up @@ -220,6 +233,8 @@ struct WSLPluginHooksV1
WSLPluginAPI_ContainerStopping ContainerStopping;
WSLPluginAPI_ImageCreated ImageCreated;
WSLPluginAPI_ImageDeleted ImageDeleted;
WSLPluginAPI_OnWslcVmStarted WslcVmStarted; // Introduced in 2.9.5
WSLPluginAPI_OnWslcVmStopping WslcVmStopping; // Introduced in 2.9.5
};

struct WSLPluginAPIV1
Expand Down
4 changes: 3 additions & 1 deletion src/windows/service/exe/HcsVirtualMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,9 @@ HcsVirtualMachine::HcsVirtualMachine(_In_ const WSLCSessionSettings* Settings)

HcsVirtualMachine::~HcsVirtualMachine()
{
std::lock_guard lock(m_lock);
// Do not hold m_lock: waiting on m_vmExitEvent and closing the compute system below both block
// on in-flight HCS exit/crash callbacks, which may themselves need m_lock. OnExit() is lock-free,
// and closing the compute system drains all callbacks, so the rest of teardown needs no lock.

// Wait up to 5 seconds for the VM to terminate gracefully.
bool forceTerminate = false;
Expand Down
38 changes: 38 additions & 0 deletions src/windows/service/exe/PluginManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -691,3 +691,41 @@ void PluginManager::OnWslcImageDeleted(const WSLCSessionInformation* Session, LP
}
}
}

void PluginManager::OnWslcVmStarted(const WSLCSessionInformation* Session) const
{
ExecutionContext context(Context::Plugin);

for (const auto& e : m_plugins)
{
if (e.hooks.WslcVmStarted != nullptr)
{
const auto result = e.hooks.WslcVmStarted(Session);
WSL_LOG(
"PluginOnWslcVmStartedCall",
TraceLoggingValue(e.name.c_str(), "Plugin"),
TraceLoggingValue(Session->SessionId, "SessionId"),
TraceLoggingValue(result, "Result"));
LOG_IF_FAILED_MSG(result, "Error thrown from plugin: '%ls'", e.name.c_str());
}
}
}

void PluginManager::OnWslcVmStopping(const WSLCSessionInformation* Session) const
{
ExecutionContext context(Context::Plugin);

for (const auto& e : m_plugins)
{
if (e.hooks.WslcVmStopping != nullptr)
{
const auto result = e.hooks.WslcVmStopping(Session);
WSL_LOG(
"PluginOnWslcVmStoppingCall",
TraceLoggingValue(e.name.c_str(), "Plugin"),
TraceLoggingValue(Session->SessionId, "SessionId"),
TraceLoggingValue(result, "Result"));
LOG_IF_FAILED_MSG(result, "Error thrown from plugin: '%ls'", e.name.c_str());
}
}
}
2 changes: 2 additions & 0 deletions src/windows/service/exe/PluginManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class PluginManager
void OnWslcContainerStopping(const WSLCSessionInformation* Session, LPCSTR ContainerId) const;
void OnWslcImageCreated(const WSLCSessionInformation* Session, LPCSTR InspectJson) const;
void OnWslcImageDeleted(const WSLCSessionInformation* Session, LPCSTR ImageId) const;
void OnWslcVmStarted(const WSLCSessionInformation* Session) const;
void OnWslcVmStopping(const WSLCSessionInformation* Session) const;

void ThrowIfFatalPluginError() const;

Expand Down
20 changes: 20 additions & 0 deletions src/windows/service/exe/WSLCPluginNotifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,23 @@ try
return S_OK;
}
CATCH_RETURN();

HRESULT WSLCPluginNotifier::OnVmStarted()
try
{
COMServiceExecutionContext context;

m_plugins.OnWslcVmStarted(&m_sessionInfo);
return S_OK;
}
CATCH_RETURN();

HRESULT WSLCPluginNotifier::OnVmStopping()
try
{
COMServiceExecutionContext context;

m_plugins.OnWslcVmStopping(&m_sessionInfo);
return S_OK;
}
CATCH_RETURN();
2 changes: 2 additions & 0 deletions src/windows/service/exe/WSLCPluginNotifier.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ class DECLSPEC_UUID("E29B0F1A-4E18-4F09-83A2-2D6B1B9F8C4D") WSLCPluginNotifier
IFACEMETHOD(OnContainerStopping)(_In_ LPCSTR ContainerId) override;
IFACEMETHOD(OnImageCreated)(_In_ LPCSTR InspectJson) override;
IFACEMETHOD(OnImageDeleted)(_In_ LPCSTR ImageId) override;
IFACEMETHOD(OnVmStarted)() override;
IFACEMETHOD(OnVmStopping)() override;

private:
wsl::windows::service::PluginManager& m_plugins;
Expand Down
11 changes: 9 additions & 2 deletions src/windows/service/exe/WSLCSessionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ struct SessionSettings
Settings.MemoryMb = memoryMb > 0 ? memoryMb : SessionSettings::DefaultMemoryMb();
Settings.MaximumStorageSizeMb = userSettings.Get<settings::Setting::SessionStorageSizeMb>();
Settings.BootTimeoutMs = wsl::windows::wslc::DefaultBootTimeoutMs;
Settings.IdleTimeoutSec = userSettings.Get<settings::Setting::SessionIdleTimeout>();
Settings.NetworkingMode = userSettings.Get<settings::Setting::SessionNetworkingMode>();

// TODO: Add a config setting to opt-out of GPU support.
Expand Down Expand Up @@ -180,6 +181,12 @@ try
}
CATCH_LOG()

bool WSLCSessionManagerImpl::InPluginNotificationContext() noexcept
{
const auto* context = wsl::windows::common::ExecutionContext::Current();
return context != nullptr && WI_IsFlagSet(context->CurrentContext(), wsl::windows::common::Context::Plugin);
}

void WSLCSessionManagerImpl::CreateSession(
_In_ const WSLCSessionSettings* Settings, _In_ WSLCSessionFlags Flags, _In_opt_ IWarningCallback* WarningCallback, _Out_ IWSLCSession** WslcSession)
{
Expand Down Expand Up @@ -285,8 +292,7 @@ void WSLCSessionManagerImpl::CreateSession(
g_pluginManager, sessionId, creatorPid, std::wstring(resolvedDisplayName), wil::shared_handle(sharedToken), std::vector<BYTE>(storedSid));

// Create the VM factory in the SYSTEM service (privileged). The per-user session
// uses it to create the VM. Funneling VM creation through a factory lets the session
// own when VMs are created, rather than having one handed to it up front.
// uses it to create VMs on demand and recreate them after idle-termination.
auto vmFactory = Microsoft::WRL::Make<WSLCVirtualMachineFactory>(Settings);

// Launch per-user COM server factory and add it to a fresh per-session job object for crash cleanup.
Expand Down Expand Up @@ -473,6 +479,7 @@ WSLCSessionInitSettings WSLCSessionManagerImpl::CreateSessionSettings(
sessionSettings.RootVhdTypeOverride = Settings->RootVhdTypeOverride;
sessionSettings.StorageFlags = Settings->StorageFlags;
sessionSettings.SwapSizeMb = Settings->MemoryMb;
sessionSettings.IdleTimeoutSec = Settings->IdleTimeoutSec;
return sessionSettings;
}

Expand Down
13 changes: 13 additions & 0 deletions src/windows/service/exe/WSLCSessionManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,16 @@ class WSLCSessionManagerImpl
wil::com_ptr<IWSLCSession> lockedSession;
if (FAILED_LOG(entry.Ref->OpenSession(&lockedSession)))
{
// Session is gone. Notifying plugins fires OnWslcSessionStopping, which is a plugin
// callback and must not nest inside another plugin callback (ExecutionContext forbids
// it). If a plugin called back into WSLC from within a notification (e.g. creating a
// process from OnWslcVmStopping), defer this lazy notify + prune to a later, non-
// reentrant pass rather than firing OnWslcSessionStopping on top of the current one.
if (InPluginNotificationContext())
{
return false; // Keep in tracking; clean up on a later pass.
}

// Session is gone: notify plugins (if not already), then drop persistent reference if any.
NotifySessionStoppingLockHeld(entry);

Expand Down Expand Up @@ -174,6 +184,9 @@ class WSLCSessionManagerImpl

void NotifySessionStoppingLockHeld(SessionEntry& entry) noexcept;

// Returns true if the calling thread is currently running inside a plugin notification callback.
static bool InPluginNotificationContext() noexcept;

std::atomic<ULONG> m_nextSessionId{1};
std::recursive_mutex m_wslcSessionsLock;

Expand Down
24 changes: 24 additions & 0 deletions src/windows/service/inc/wslc.idl
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,13 @@ interface IWSLCPluginNotifier : IUnknown

// Called when an image is deleted. 'ImageId' is the image identifier. Errors are logged but ignored.
HRESULT OnImageDeleted([in] LPCSTR ImageId);

// Called when the VM backing the session has started (first start or recreation after idle
// teardown). Errors are logged but ignored.
HRESULT OnVmStarted();

// Called when the VM backing the session is about to stop. Errors are logged but ignored.
HRESULT OnVmStopping();
};

typedef struct _WSLCImageInformation
Expand Down Expand Up @@ -467,6 +474,7 @@ typedef struct _WSLCSessionSettings {
WSLCFeatureFlags FeatureFlags;
WSLCHandle DmesgOutput;
WSLCSessionStorageFlags StorageFlags;
ULONG IdleTimeoutSec;

// Below options are used for debugging purposes only.
[unique] LPCWSTR RootVhdOverride;
Expand Down Expand Up @@ -603,6 +611,7 @@ typedef struct _WSLCSessionInitSettings
WSLCNetworkingMode NetworkingMode;
WSLCFeatureFlags FeatureFlags;
[unique] LPCSTR RootVhdTypeOverride;
ULONG IdleTimeoutSec;
} WSLCSessionInitSettings;

[
Expand Down Expand Up @@ -690,6 +699,21 @@ interface IWSLCSession : IUnknown
HRESULT PruneNetworks([in, unique, size_is(FiltersCount)] const WSLCFilter* Filters, [in] ULONG FiltersCount, [out, size_is(, *NetworksCount)] WSLCNetworkName** Networks, [out] ULONG* NetworksCount);

HRESULT RegisterCrashDumpCallback([in] ICrashDumpCallback* Callback, [out] IUnknown** Subscription);

// Used only for testing. Synchronously runs the idle-termination teardown path, ignoring the
// activity-count guard so a test can force the VM down even while a container holds an activity
// reference. The idle-termination-enabled (persistent-storage) guard is still honored: a
// tmpfs-backed session is never torn down, since that would lose unrecoverable state.
// WasAlreadyIdle is TRUE when the VM was not running.
HRESULT TriggerIdleTermination([out] BOOL* WasAlreadyIdle);

// Keeps the VM alive for the duration of a client-side container operation. The CLI performs
// each mutation as two round-trips (OpenContainer followed by the operation) and may stream
// output afterwards. With on-demand VM idle-termination the VM could otherwise tear down
// between those calls, disconnecting the container wrapper and failing the second call with
// RPC_E_DISCONNECTED. The client holds the returned token for the whole operation; releasing
// it (or the client exiting) lets the VM idle-terminate again.
HRESULT BeginContainerOperation([out] IUnknown** Operation);
}

//
Expand Down
11 changes: 11 additions & 0 deletions src/windows/wslc/services/ContainerService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,7 @@ std::wstring ContainerService::FormatRelativeTime(ULONGLONG timestamp)

int ContainerService::Attach(Session& session, const std::string& id)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();
wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));

Expand Down Expand Up @@ -487,6 +488,7 @@ CreateContainerResult ContainerService::Create(Session& session, const std::stri

int ContainerService::Start(Session& session, const std::string& id, bool attach)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();
wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));
WSLCContainerStartFlags flags = attach ? WSLCContainerStartFlagsAttach : WSLCContainerStartFlagsNone;
Expand Down Expand Up @@ -517,20 +519,23 @@ int ContainerService::Start(Session& session, const std::string& id, bool attach

void ContainerService::Stop(Session& session, const std::string& id, StopContainerOptions options)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();
wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));
THROW_IF_FAILED_EXCEPT(container->Stop(options.Signal, options.Timeout), WSLC_E_CONTAINER_NOT_RUNNING);
}

void ContainerService::Kill(Session& session, const std::string& id, WSLCSignal signal)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();
wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));
THROW_IF_FAILED(container->Kill(signal));
}

void ContainerService::Delete(Session& session, const std::string& id, bool force)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();
wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));
THROW_IF_FAILED(container->Delete(force ? WSLCDeleteFlagsForce : WSLCDeleteFlagsNone));
Expand Down Expand Up @@ -585,6 +590,7 @@ std::vector<ContainerInformation> ContainerService::List(

int ContainerService::Exec(Session& session, const std::string& id, ContainerOptions options)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();
wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));

Expand Down Expand Up @@ -616,6 +622,7 @@ int ContainerService::Exec(Session& session, const std::string& id, ContainerOpt

InspectContainer ContainerService::Inspect(Session& session, const std::string& id)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();
wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));
wil::unique_cotaskmem_ansistring output;
Expand All @@ -634,6 +641,8 @@ void ContainerService::Export(Session& session, const std::string& id, const std

void ContainerService::Export(Session& session, const std::string& id, HANDLE outputHandle)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();

wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));

Expand Down Expand Up @@ -661,6 +670,7 @@ void ContainerService::CopyFromContainer(Session& session, const std::string& id

void ContainerService::Logs(Session& session, const std::string& id, bool follow, bool timestamps, ULONGLONG since, ULONGLONG until, ULONGLONG tail)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();
wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));

Expand Down Expand Up @@ -688,6 +698,7 @@ void ContainerService::Logs(Session& session, const std::string& id, bool follow

wsl::windows::common::docker_schema::ContainerStats ContainerService::Stats(Session& session, const std::string& id)
{
[[maybe_unused]] auto operation = session.BeginContainerOperation();
wil::com_ptr<IWSLCContainer> container;
THROW_IF_FAILED(session.Get()->OpenContainer(id.c_str(), &container));
wil::unique_cotaskmem_ansistring output;
Expand Down
10 changes: 10 additions & 0 deletions src/windows/wslc/services/SessionModel.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ struct Session
return m_session.get();
}

// Acquires an activity token that keeps the VM alive for the duration of a client-side
// container operation (resolve + operate, plus any streamed output). Hold the returned
// pointer for the whole operation; releasing it lets the VM idle-terminate again.
[[nodiscard]] wil::com_ptr<IUnknown> BeginContainerOperation() const
{
wil::com_ptr<IUnknown> operation;
THROW_IF_FAILED(m_session->BeginContainerOperation(&operation));
return operation;
}

private:
wil::com_ptr<IWSLCSession> m_session;
};
Expand Down
4 changes: 3 additions & 1 deletion src/windows/wslc/services/SessionService.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ Session SessionService::OpenOrCreateDefaultSession()
{
auto manager = CreateSessionManager();

// Null Settings = default session with server-determined name and settings.
// Null Settings = default session with server-determined name and settings. The warning callback
// is consumed during CreateSession (session initialization); it is not retained afterwards.
wil::com_ptr<IWSLCSession> session;
auto warningCallback = Microsoft::WRL::Make<WarningCallback>();
THROW_IF_FAILED(manager->CreateSession(nullptr, WSLCSessionFlagsNone, warningCallback.Get(), &session));
wsl::windows::common::security::ConfigureForCOMImpersonation(session.get());

return Session(std::move(session));
}

Expand Down
Loading
Loading