From 439206755d2f9c30a4fc0dfd957da238e1ba63e9 Mon Sep 17 00:00:00 2001 From: Sam Harwell Date: Fri, 27 Apr 2018 07:58:46 -0500 Subject: [PATCH] Handle empty queue in WaitForPendingWorkAsync Cancellation allows item removal from the pending work queue from non-UI threads, so the UI thread handling needs to account for the possibility of it being empty after WaitForItemsAsync completes. --- .../ForegroundNotificationService.cs | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/EditorFeatures/Core/Implementation/ForegroundNotification/ForegroundNotificationService.cs b/src/EditorFeatures/Core/Implementation/ForegroundNotification/ForegroundNotificationService.cs index 348613ca16d..a2b92c6f1fd 100644 --- a/src/EditorFeatures/Core/Implementation/ForegroundNotification/ForegroundNotificationService.cs +++ b/src/EditorFeatures/Core/Implementation/ForegroundNotification/ForegroundNotificationService.cs @@ -196,26 +196,29 @@ private void NotifyOnForegroundWorker() private async Task WaitForPendingWorkAsync() { - await _workQueue.WaitForItemsAsync().ConfigureAwait(false); while (true) { - var current = Environment.TickCount; - var nextItem = _workQueue.PeekNextItemTime(); + await _workQueue.WaitForItemsAsync().ConfigureAwait(false); + if (!_workQueue.TryPeekNextItemTime(out var nextItem)) + { + // Need to go back and wait for an item + continue; + } // The next item is ready to run - if (nextItem - current <= 0) + if (nextItem - Environment.TickCount <= 0) { break; } // wait some and re-check since there could be another one inserted before the first one while we were waiting. - await Task.Delay(MinimumDelayBetweenProcessing).ConfigureAwait(continueOnCapturedContext: false); + await Task.Delay(MinimumDelayBetweenProcessing).ConfigureAwait(false); } // Throttle how often we run by waiting MinimumDelayBetweenProcessing since the last time we processed notifications if (Environment.TickCount - _lastProcessedTimeInMS < MinimumDelayBetweenProcessing) { - await Task.Delay(MinimumDelayBetweenProcessing).ConfigureAwait(continueOnCapturedContext: false); + await Task.Delay(MinimumDelayBetweenProcessing).ConfigureAwait(false); } } @@ -344,12 +347,18 @@ private void Enqueue_NoLock(LinkedListNode entry) return; } - public int PeekNextItemTime() + public bool TryPeekNextItemTime(out int minimumRunPoint) { lock (_gate) { - Contract.Requires(_list.Count > 0); - return _list.First.Value.MinimumRunPointInMS; + if (_list.Count == 0) + { + minimumRunPoint = 0; + return false; + } + + minimumRunPoint = _list.First.Value.MinimumRunPointInMS; + return true; } } -- GitLab