Add logic to force terminate the VM if the session lock can't be acquired for 30 seconds when the service stops (#13493)
Blue committed
Sep 24, 2025 at 21:46 UTC
4bba074bd29253c4ce6b928b1b1a69a557934698
3 files changed
+46
-9
src/windows/service/exe/LxssUserSession.cpp
+36
-6
@@ -510,7 +510,7 @@ try
510
const auto session = m_session.lock();
511
RETURN_HR_IF(RPC_E_DISCONNECTED, !session);
512
513
- return session->Shutdown(false, Force);
513
+ return session->Shutdown(false, Force ? ShutdownBehavior::Force : ShutdownBehavior::Wait);
514
}
515
CATCH_RETURN()
516
@@ -2052,13 +2052,11 @@ HRESULT LxssUserSessionImpl::SetVersion(_In_ LPCGUID DistroGuid, _In_ ULONG Vers
2052
return result;
2053
}
2054
2055
-HRESULT LxssUserSessionImpl::Shutdown(_In_ bool PreventNewInstances, bool ForceTerminate)
2055
+HRESULT LxssUserSessionImpl::Shutdown(_In_ bool PreventNewInstances, ShutdownBehavior Behavior)
2056
{
2057
try
2058
{
2059
- // If the user asks for a forced termination, kill the VM
2060
- if (ForceTerminate)
2061
- {
2059
+ auto forceTerminate = [this]() {
2060
auto vmId = m_vmId.load();
2061
if (!IsEqualGUID(vmId, GUID_NULL))
2062
{
@@ -2071,11 +2069,43 @@ HRESULT LxssUserSessionImpl::Shutdown(_In_ bool PreventNewInstances, bool ForceT
2069
2070
WSL_LOG("ForceTerminateVm", TraceLoggingValue(result, "Result"));
2071
}
2072
+ };
2073
+
2074
+ // If the user asks for a forced termination, kill the VM
2075
+ if (Behavior == ShutdownBehavior::Force)
2076
+ {
2077
+ forceTerminate();
2078
}
2079
2080
{
2081
+ bool locked = false;
2082
+ auto unlock = wil::scope_exit_log(WI_DIAGNOSTICS_INFO, [this, &locked]() {
2083
+ if (locked)
2084
+ {
2085
+ m_instanceLock.unlock();
2086
+ }
2087
+ });
2088
+
2089
+ if (Behavior == ShutdownBehavior::ForceAfter30Seconds)
2090
+ {
2091
+ if (m_instanceLock.try_lock_for(std::chrono::seconds(30)))
2092
+ {
2093
+ locked = true;
2094
+ }
2095
+ else
2096
+ {
2097
+ WSL_LOG("VmShutdownLockTimedOut");
2098
+ forceTerminate();
2099
+ }
2100
+ }
2101
+
2102
+ if (!locked)
2103
+ {
2104
+ m_instanceLock.lock();
2105
+ locked = true;
2106
+ }
2107
+
2108
// Stop each instance with the lock held.
2078
- std::lock_guard lock(m_instanceLock);
2109
while (!m_runningInstances.empty())
2110
{
2111
_TerminateInstanceInternal(&m_runningInstances.begin()->first, false);
src/windows/service/exe/LxssUserSession.h
+9
-2
@@ -54,6 +54,13 @@ typedef struct _LXSS_VM_MODE_SETUP_CONTEXT
54
std::shared_ptr<LxssRunningInstance> instance;
55
} LXSS_VM_MODE_SETUP_CONTEXT, *PLXSS_VM_MODE_SETUP_CONTEXT;
56
57
+enum class ShutdownBehavior
58
+{
59
+ Wait,
60
+ Force,
61
+ ForceAfter30Seconds
62
+};
63
+
64
/// <summary>
65
/// Each COM client gets a unique LxssUserSession object which contains a std::weak_ptr to a LxssUserSessionImpl for that user.
66
/// </summary>
@@ -491,7 +498,7 @@ public:
498
/// <summary>
499
/// Terminates all running instances and the Linux utility vm.
500
/// </summary>
494
- HRESULT Shutdown(_In_ bool PreventNewInstances = false, _In_ bool ForceTerminate = false);
501
+ HRESULT Shutdown(_In_ bool PreventNewInstances = false, ShutdownBehavior Behavior = ShutdownBehavior::Wait);
502
503
/// <summary>
504
/// Worker thread for logging telemetry about processes running inside of WSL.
@@ -784,7 +791,7 @@ private:
791
/// <summary>
792
/// Lock for protecting various lists.
793
/// </summary>
787
- std::recursive_mutex m_instanceLock;
794
+ std::recursive_timed_mutex m_instanceLock;
795
796
/// <summary>
797
/// Contains the currently running utility VM's.
src/windows/service/exe/LxssUserSessionFactory.cpp
+1
-1
@@ -49,7 +49,7 @@ void ClearSessionsAndBlockNewInstancesLockHeld(std::optional<std::vector<std::sh
49
// since that could lead to a deadlock if FindSessionByCookie is called since that would try to lock g_sessionLock
50
// while holding the session inner lock
51
52
- session->Shutdown(true);
52
+ session->Shutdown(true, ShutdownBehavior::ForceAfter30Seconds);
53
}
54
55
sessions.reset();