From e0665fff03d73123ae0d9ec4e14933ad2de7cf8d Mon Sep 17 00:00:00 2001 From: Craig Loewen Date: Fri, 17 Jul 2026 15:58:34 -0400 Subject: [PATCH 1/3] Added keep alive setting --- localization/strings/en-US/Resources.resw | 14 ++++++++++++++ .../Settings/OptionalFeaturesViewModel.cs | 19 +++++++++++++++++++ .../Views/Settings/OptionalFeaturesPage.xaml | 5 ++++- 3 files changed, 37 insertions(+), 1 deletion(-) diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw index aa0f5bf72c..4d1201ed42 100644 --- a/localization/strings/en-US/Resources.resw +++ b/localization/strings/en-US/Resources.resw @@ -1981,6 +1981,20 @@ You can also access more VS Code Remote options through the command palette with The number of milliseconds that a VM is idle, before it is shut down. + + Keep WSL VM alive + + + Keep the WSL virtual machine running instead of shutting it down after it has been idle. When enabled, the VM only stops on "wsl --shutdown" or when the service is stopped. + {Locked="wsl --shutdown"} is a command that must not be translated. + + + Keep WSL VM alive. + + + Keep the WSL virtual machine running instead of shutting it down after it has been idle. When enabled, the VM only stops on "wsl --shutdown" or when the service is stopped. + {Locked="wsl --shutdown"} is a command that must not be translated. + Reset timeout diff --git a/src/windows/wslsettings/ViewModels/Settings/OptionalFeaturesViewModel.cs b/src/windows/wslsettings/ViewModels/Settings/OptionalFeaturesViewModel.cs index 549f328b75..3c71163834 100644 --- a/src/windows/wslsettings/ViewModels/Settings/OptionalFeaturesViewModel.cs +++ b/src/windows/wslsettings/ViewModels/Settings/OptionalFeaturesViewModel.cs @@ -72,6 +72,23 @@ public bool IsOnSparseVHD set { Set(ref _sparseVHD!, value); } } + public bool IsOnKeepVMAlive + { + get { return _vMIdleTimeout!.Int32Value < 0; } + set + { + Set(ref _vMIdleTimeout!, value ? -1 : _defaultVMIdleTimeout, nameof(IsOnKeepVMAlive)); + OnPropertyChanged(nameof(VMIdleTimeout)); + OnPropertyChanged(nameof(VMIdleTimeoutEnabled)); + VMIdleTimeout_ResetEnabled = !Equals(_defaultVMIdleTimeout, _vMIdleTimeout!.Int32Value); + } + } + + public bool VMIdleTimeoutEnabled + { + get { return _vMIdleTimeout!.Int32Value >= 0; } + } + public string VMIdleTimeout { get @@ -85,6 +102,8 @@ public string VMIdleTimeout if (Int32.TryParse(value, out int parsedValue)) { Set(ref _vMIdleTimeout!, parsedValue); + OnPropertyChanged(nameof(IsOnKeepVMAlive)); + OnPropertyChanged(nameof(VMIdleTimeoutEnabled)); } else { diff --git a/src/windows/wslsettings/Views/Settings/OptionalFeaturesPage.xaml b/src/windows/wslsettings/Views/Settings/OptionalFeaturesPage.xaml index 26c46e2642..9db5b97c25 100644 --- a/src/windows/wslsettings/Views/Settings/OptionalFeaturesPage.xaml +++ b/src/windows/wslsettings/Views/Settings/OptionalFeaturesPage.xaml @@ -41,7 +41,10 @@ - + + + + From 2118d20634b5ba9bcab6a31762def81013a8183c Mon Sep 17 00:00:00 2001 From: Craig Loewen Date: Mon, 27 Jul 2026 14:09:34 -0400 Subject: [PATCH 2/3] Updated to use DistroTimeout instead --- localization/strings/en-US/Resources.resw | 21 ++++- src/windows/inc/WslCoreConfigInterface.h | 1 + src/windows/libwsl/WslCoreConfigInterface.cpp | 11 +++ .../Contracts/Services/IWslConfigService.cs | 1 + src/windows/wslsettings/LibWsl.cs | 3 +- .../Settings/OptionalFeaturesViewModel.cs | 78 +++++++++++++++++-- .../Views/Settings/OptionalFeaturesPage.xaml | 14 ++++ .../Settings/OptionalFeaturesPage.xaml.cs | 12 +++ .../Views/Settings/SettingsApplyHelper.cs | 2 + 9 files changed, 131 insertions(+), 12 deletions(-) diff --git a/localization/strings/en-US/Resources.resw b/localization/strings/en-US/Resources.resw index 4d1201ed42..8887f5b8da 100644 --- a/localization/strings/en-US/Resources.resw +++ b/localization/strings/en-US/Resources.resw @@ -1985,15 +1985,13 @@ You can also access more VS Code Remote options through the command palette with Keep WSL VM alive - Keep the WSL virtual machine running instead of shutting it down after it has been idle. When enabled, the VM only stops on "wsl --shutdown" or when the service is stopped. - {Locked="wsl --shutdown"} is a command that must not be translated. + Keep the WSL virtual machine, and the distributions running inside it, from being automatically shut down after they have been idle. Keep WSL VM alive. - Keep the WSL virtual machine running instead of shutting it down after it has been idle. When enabled, the VM only stops on "wsl --shutdown" or when the service is stopped. - {Locked="wsl --shutdown"} is a command that must not be translated. + Keep the WSL virtual machine, and the distributions running inside it, from being automatically shut down after they have been idle. Reset timeout @@ -2004,6 +2002,21 @@ You can also access more VS Code Remote options through the command palette with The number of milliseconds that a VM is idle, before it is shut down. + + Distribution idle timeout + + + The number of milliseconds that a distribution is idle, before it is terminated. + + + Reset timeout + + + Distribution idle timeout + + + The number of milliseconds that a distribution is idle, before it is terminated. + Apply changes diff --git a/src/windows/inc/WslCoreConfigInterface.h b/src/windows/inc/WslCoreConfigInterface.h index a7a9569fb9..def8bc67e9 100644 --- a/src/windows/inc/WslCoreConfigInterface.h +++ b/src/windows/inc/WslCoreConfigInterface.h @@ -47,6 +47,7 @@ enum WslConfigEntry KernelPath, SystemDistroPath, KernelModulesPath, + InstanceIdleTimeout, }; enum NetworkingConfiguration diff --git a/src/windows/libwsl/WslCoreConfigInterface.cpp b/src/windows/libwsl/WslCoreConfigInterface.cpp index 920a238e2d..22f5e114cc 100644 --- a/src/windows/libwsl/WslCoreConfigInterface.cpp +++ b/src/windows/libwsl/WslCoreConfigInterface.cpp @@ -195,6 +195,10 @@ WslConfigSetting GetWslConfigSetting(WslConfig_t wslConfig, WslConfigEntry wslCo static_assert(std::is_sameConfig.KernelModulesPath.c_str())>::value); wslConfigSetting.StringValue = wslConfig->Config.KernelModulesPath.c_str(); break; + case InstanceIdleTimeout: + static_assert(std::is_sameConfig.InstanceIdleTimeout)>::value); + wslConfigSetting.Int32Value = wslConfig->Config.InstanceIdleTimeout; + break; default: FAIL_FAST(); } @@ -560,6 +564,13 @@ unsigned long SetWslConfigSetting(WslConfig_t wslConfig, WslConfigSetting wslCon wslConfigSetting.StringValue, wslConfig->Config.KernelModulesPath); } + case InstanceIdleTimeout: + return SetWslConfigSetting( + wslConfig, + ConfigSetting::InstanceIdleTimeout, + defaultConfig.InstanceIdleTimeout, + wslConfigSetting.Int32Value, + wslConfig->Config.InstanceIdleTimeout); default: FAIL_FAST(); } diff --git a/src/windows/wslsettings/Contracts/Services/IWslConfigService.cs b/src/windows/wslsettings/Contracts/Services/IWslConfigService.cs index cb59aa6702..7f57a2f33e 100644 --- a/src/windows/wslsettings/Contracts/Services/IWslConfigService.cs +++ b/src/windows/wslsettings/Contracts/Services/IWslConfigService.cs @@ -76,6 +76,7 @@ WslConfigEntry.SystemDistroPath or WslConfigEntry.ProcessorCount or WslConfigEntry.InitialAutoProxyTimeout or + WslConfigEntry.InstanceIdleTimeout or WslConfigEntry.VMIdleTimeout => WslConfigValueKind.Int32, WslConfigEntry.MemorySizeBytes or diff --git a/src/windows/wslsettings/LibWsl.cs b/src/windows/wslsettings/LibWsl.cs index bd49c76f37..c05fc9018b 100644 --- a/src/windows/wslsettings/LibWsl.cs +++ b/src/windows/wslsettings/LibWsl.cs @@ -43,7 +43,8 @@ public enum WslConfigEntry HardwarePerformanceCountersEnabled = 23, KernelPath = 24, SystemDistroPath = 25, - KernelModulesPath = 26 + KernelModulesPath = 26, + InstanceIdleTimeout = 27 } public enum NetworkingConfiguration diff --git a/src/windows/wslsettings/ViewModels/Settings/OptionalFeaturesViewModel.cs b/src/windows/wslsettings/ViewModels/Settings/OptionalFeaturesViewModel.cs index 3c71163834..8f3f4acb9e 100644 --- a/src/windows/wslsettings/ViewModels/Settings/OptionalFeaturesViewModel.cs +++ b/src/windows/wslsettings/ViewModels/Settings/OptionalFeaturesViewModel.cs @@ -16,12 +16,15 @@ public partial class OptionalFeaturesViewModel : WslConfigSettingViewModel private IWslConfigSetting? _sparseVHD; private IWslConfigSetting? _vMIdleTimeout; private int _defaultVMIdleTimeout; + private IWslConfigSetting? _instanceIdleTimeout; + private int _defaultInstanceIdleTimeout; public OptionalFeaturesViewModel() { InitializeConfigSettings(); VMIdleTimeout_ResetEnabled = !Equals(_defaultVMIdleTimeout, _vMIdleTimeout!.Int32Value); + InstanceIdleTimeout_ResetEnabled = !Equals(_defaultInstanceIdleTimeout, _instanceIdleTimeout!.Int32Value); } protected override void InitializeConfigSettings() @@ -33,8 +36,10 @@ protected override void InitializeConfigSettings() _safeMode = wslConfigService.GetWslConfigSetting(WslConfigEntry.SafeModeEnabled); _sparseVHD = wslConfigService.GetWslConfigSetting(WslConfigEntry.SparseVHDEnabled); _vMIdleTimeout = wslConfigService.GetWslConfigSetting(WslConfigEntry.VMIdleTimeout); + _instanceIdleTimeout = wslConfigService.GetWslConfigSetting(WslConfigEntry.InstanceIdleTimeout); _defaultVMIdleTimeout = wslConfigService.GetWslConfigSetting(WslConfigEntry.VMIdleTimeout, true).Int32Value; + _defaultInstanceIdleTimeout = wslConfigService.GetWslConfigSetting(WslConfigEntry.InstanceIdleTimeout, true).Int32Value; } public List MemoryReclaimModes @@ -72,21 +77,30 @@ public bool IsOnSparseVHD set { Set(ref _sparseVHD!, value); } } + // Keeping WSL alive is driven by the distribution idle timeout: a negative value tells the + // service to never idle-terminate a distribution, and because the VM is only considered idle + // once every distribution has stopped, this keeps the WSL VM running as well. public bool IsOnKeepVMAlive { - get { return _vMIdleTimeout!.Int32Value < 0; } + get { return _instanceIdleTimeout!.Int32Value < 0; } set { - Set(ref _vMIdleTimeout!, value ? -1 : _defaultVMIdleTimeout, nameof(IsOnKeepVMAlive)); - OnPropertyChanged(nameof(VMIdleTimeout)); + Set(ref _instanceIdleTimeout!, value ? -1 : _defaultInstanceIdleTimeout, nameof(IsOnKeepVMAlive)); + OnPropertyChanged(nameof(InstanceIdleTimeout)); + OnPropertyChanged(nameof(InstanceIdleTimeoutEnabled)); OnPropertyChanged(nameof(VMIdleTimeoutEnabled)); - VMIdleTimeout_ResetEnabled = !Equals(_defaultVMIdleTimeout, _vMIdleTimeout!.Int32Value); + InstanceIdleTimeout_ResetEnabled = !Equals(_defaultInstanceIdleTimeout, _instanceIdleTimeout!.Int32Value); } } public bool VMIdleTimeoutEnabled { - get { return _vMIdleTimeout!.Int32Value >= 0; } + get { return !IsOnKeepVMAlive; } + } + + public bool InstanceIdleTimeoutEnabled + { + get { return !IsOnKeepVMAlive; } } public string VMIdleTimeout @@ -102,8 +116,6 @@ public string VMIdleTimeout if (Int32.TryParse(value, out int parsedValue)) { Set(ref _vMIdleTimeout!, parsedValue); - OnPropertyChanged(nameof(IsOnKeepVMAlive)); - OnPropertyChanged(nameof(VMIdleTimeoutEnabled)); } else { @@ -139,4 +151,56 @@ private void VMIdleTimeout_ResetExecuted(string? param) } public ICommand VMIdleTimeout_ResetCommand => new RelayCommand(VMIdleTimeout_ResetExecuted); + + public string InstanceIdleTimeout + { + get + { + return _instanceIdleTimeout!.Int32Value.ToString(); + } + set + { + if (ValidateInput(value, Constants.IntegerRegex)) + { + if (Int32.TryParse(value, out int parsedValue)) + { + Set(ref _instanceIdleTimeout!, parsedValue); + OnPropertyChanged(nameof(IsOnKeepVMAlive)); + OnPropertyChanged(nameof(InstanceIdleTimeoutEnabled)); + OnPropertyChanged(nameof(VMIdleTimeoutEnabled)); + } + else + { + OnPropertyChanged(); + } + } + } + } + + public void SetInstanceIdleTimeout_ResetEnabled(string? value) + { + if (Int32.TryParse(value, out Int32 parseResult)) + { + InstanceIdleTimeout_ResetEnabled = !Equals(_defaultInstanceIdleTimeout, parseResult); + } + else + { + InstanceIdleTimeout_ResetEnabled = true; + } + } + + private bool _instanceIdleTimeout_ResetEnabled; + + public bool InstanceIdleTimeout_ResetEnabled + { + get => _instanceIdleTimeout_ResetEnabled; + set => SetProperty(ref _instanceIdleTimeout_ResetEnabled, value); + } + + private void InstanceIdleTimeout_ResetExecuted(string? param) + { + InstanceIdleTimeout = _defaultInstanceIdleTimeout.ToString(); + } + + public ICommand InstanceIdleTimeout_ResetCommand => new RelayCommand(InstanceIdleTimeout_ResetExecuted); } \ No newline at end of file diff --git a/src/windows/wslsettings/Views/Settings/OptionalFeaturesPage.xaml b/src/windows/wslsettings/Views/Settings/OptionalFeaturesPage.xaml index 9db5b97c25..f821a49fe4 100644 --- a/src/windows/wslsettings/Views/Settings/OptionalFeaturesPage.xaml +++ b/src/windows/wslsettings/Views/Settings/OptionalFeaturesPage.xaml @@ -58,6 +58,20 @@ + + + + + + +