From 82ffd50271988f11f6bff57fce06b8a3813ec0d7 Mon Sep 17 00:00:00 2001 From: Danilo Del Busso Date: Wed, 25 Oct 2023 09:53:09 +0100 Subject: [PATCH] CA-379971: Ensure `ParallelAction` is not waiting on `_lock` when no actions are running There is a chance that all actions have completed before we hit the `Wait` call, we need to make sure we don't hit a deadlock. This can happen if for instance there is only one action, and it is a "dummy" action, such as the one used in the EUA check. Also I have removed the compound assignment for the `volatile _completedActionsCount` since Visual Studio was flagging it as a "suspicious usage of a volatile variable". I personally don't think it's a problem but better safe than sorry. Contains minor whitespace fixes, too Signed-off-by: Danilo Del Busso --- XenModel/Actions/ParallelAction.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/XenModel/Actions/ParallelAction.cs b/XenModel/Actions/ParallelAction.cs index fd27bb1bd1..0f1ce0cecb 100644 --- a/XenModel/Actions/ParallelAction.cs +++ b/XenModel/Actions/ParallelAction.cs @@ -57,7 +57,7 @@ public class ParallelAction : MultipleAction private readonly int _maxNumberOfParallelActions; private readonly int _actionsCount; private readonly object _lock = new object(); - private volatile int _completedActionsCount ; + private volatile int _completedActionsCount; /// /// Use this constructor to create a cross connection ParallelAction. @@ -124,7 +124,10 @@ protected override void RunSubActions(List exceptions) lock (_lock) { - Monitor.Wait(_lock); + // CA-379971: There is a chance that all actions have completed before we + // hit the Wait call, we need to make sure we don't hit a deadlock + if (_completedActionsCount != _actionsCount) + Monitor.Wait(_lock); } } @@ -165,7 +168,7 @@ protected override void RecalculatePercentComplete() foreach (var connection in _actionsByConnection.Keys) { - foreach (var action in _actionsByConnection[connection]) + foreach (var action in _actionsByConnection[connection]) total += action.PercentComplete; } @@ -180,7 +183,7 @@ private void action_Completed(ActionBase sender) sender.Completed -= action_Completed; lock (_lock) { - _completedActionsCount++; + _completedActionsCount = _completedActionsCount + 1; if (_completedActionsCount == _actionsCount) { Monitor.Pulse(_lock);