Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System;
using System.Management.Automation;
using Dbg = System.Management.Automation.Diagnostics;
using System.Threading;


namespace Microsoft.PowerShell
Expand All @@ -28,14 +29,30 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt
// destroy the data structures representing outstanding progress records
// take down and destroy the progress display

if (_progPane != null)
// If we have multiple runspaces on the host then any finished pipeline in any runspace will lead to call 'ResetProgress'
// so we need the lock
lock (_instanceLock)
{
Dbg.Assert(_pendingProgress != null, "How can you have a progress pane and no backing data structure?");
if (_progPaneUpdateTimer != null)
{
// Stop update a progress pane and destroy timer
_progPaneUpdateTimer.Dispose();
_progPaneUpdateTimer = null;
}
// We don't set 'progPaneUpdateFlag = 0' here, because:
// 1. According to MSDN, the timer callback can occur after the Dispose() method has been called.
// So we cannot guarantee the flag is truly set to 0.
// 2. When creating a new timer in 'HandleIncomingProgressRecord', we will set the flag to 1 anyway

_progPane.Hide();
_progPane = null;
if (_progPane != null)
{
Dbg.Assert(_pendingProgress != null, "How can you have a progress pane and no backing data structure?");

_progPane.Hide();
_progPane = null;
}
_pendingProgress = null;
}
_pendingProgress = null;
}


Expand Down Expand Up @@ -64,15 +81,46 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt

if (_progPane == null)
{
// This is the first time we've received a progress record. Create a progress pane, then show it.
// This is the first time we've received a progress record
// Create a progress pane
// Set up a update flag
// Create a timer for updating the flag

_progPane = new ProgressPane(this);

if (_progPaneUpdateTimer == null)
{
// Show a progress pane at the first time we've received a progress record
progPaneUpdateFlag = 1;

// The timer will be auto restarted every 'UpdateTimerThreshold' ms
_progPaneUpdateTimer = new Timer( new TimerCallback(ProgressPaneUpdateTimerElapsed), null, UpdateTimerThreshold, UpdateTimerThreshold);
}
}

if (Interlocked.CompareExchange(ref progPaneUpdateFlag, 0, 1) == 1 || record.RecordType == ProgressRecordType.Completed)
{
// Update the progress pane only when the timer set up the update flag or WriteProgress is completed.
// As a result, we do not block WriteProgress and whole script and eliminate unnecessary console locks and updates.
_progPane.Show(_pendingProgress);
}
_progPane.Show(_pendingProgress);
}



/// <summary>
///
/// TimerCallback for '_progPaneUpdateTimer' to update 'progPaneUpdateFlag'
///
/// </summary>

private
void
ProgressPaneUpdateTimerElapsed(object sender)
{
Interlocked.CompareExchange(ref progPaneUpdateFlag, 1, 0);
}

private
void
PreWrite()
Expand Down Expand Up @@ -166,6 +214,10 @@ class ConsoleHostUserInterface : System.Management.Automation.Host.PSHostUserInt

private ProgressPane _progPane = null;
private PendingProgress _pendingProgress = null;
// The timer set up 'progPaneUpdateFlag' every 'UpdateTimerThreshold' milliseconds to update 'ProgressPane'
private Timer _progPaneUpdateTimer = null;
private const int UpdateTimerThreshold = 200;
private int progPaneUpdateFlag = 0;
}
} // namespace

Expand Down