WSLA: Invoke WSLAContainer callbacks without the callback lock held

This commit is contained in:
Ben Hillis 2025-12-15 12:36:40 -08:00
parent 68a6c4869d
commit 8546224401
2 changed files with 29 additions and 11 deletions

View File

@ -112,16 +112,26 @@ void ContainerEventTracker::OnEvent(const std::string& event)
auto containerIdIt = innerEvent.find("container_id");
THROW_HR_IF_MSG(E_INVALIDARG, containerIdIt == innerEvent.end(), "Failed to parse json: %hs", innerEventJson.c_str());
std::lock_guard lock{m_lock};
std::string containerId = containerIdIt->get<std::string>();
for (const auto& e : m_callbacks)
// Copy callbacks to invoke outside the lock to avoid deadlock if callback tries to register/unregister
std::vector<ContainerStateChangeCallback> callbacksToInvoke;
{
if (e.ContainerId == containerId)
std::lock_guard lock{m_lock};
for (const auto& e : m_callbacks)
{
e.Callback(it->second);
if (e.ContainerId == containerId)
{
callbacksToInvoke.push_back(e.Callback);
}
}
}
// Invoke callbacks outside the lock
for (const auto& callback : callbacksToInvoke)
{
callback(it->second);
}
}
void ContainerEventTracker::Run(ServiceRunningProcess& process)

View File

@ -163,16 +163,24 @@ CATCH_RETURN();
WSLA_CONTAINER_STATE WSLAContainer::State() noexcept
{
std::lock_guard<std::recursive_mutex> lock(m_lock);
std::optional<ServiceRunningProcess> processToDestroy;
WSLA_CONTAINER_STATE result;
// If the container is running, refresh the init process state before returning.
if (m_state == WslaContainerStateRunning && m_containerProcess->State() != WSLAProcessStateRunning)
{
m_state = WslaContainerStateExited;
m_containerProcess.reset();
std::lock_guard<std::recursive_mutex> lock(m_lock);
// If the container is running, refresh the init process state before returning.
if (m_state == WslaContainerStateRunning && m_containerProcess->State() != WSLAProcessStateRunning)
{
m_state = WslaContainerStateExited;
processToDestroy = std::move(m_containerProcess);
}
result = m_state;
}
return m_state;
// Destructor runs outside the lock to avoid potential deadlock
return result;
}
HRESULT WSLAContainer::GetState(WSLA_CONTAINER_STATE* Result)