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();