mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
Make Test-Connection always use the default synchronization context for sending ping requests (#11517)
This commit is contained in:
committed by
Travis Plunk
parent
b54b188c18
commit
331eac8fbc
+10
-39
@@ -62,10 +62,6 @@ namespace Microsoft.PowerShell.Commands
|
||||
|
||||
private Ping? _sender;
|
||||
|
||||
private readonly ManualResetEventSlim _pingComplete = new ManualResetEventSlim();
|
||||
|
||||
private PingCompletedEventArgs? _pingCompleteArgs;
|
||||
|
||||
#endregion
|
||||
|
||||
#region Parameters
|
||||
@@ -797,7 +793,6 @@ namespace Microsoft.PowerShell.Commands
|
||||
if (disposing)
|
||||
{
|
||||
_sender?.Dispose();
|
||||
_pingComplete?.Dispose();
|
||||
}
|
||||
|
||||
_disposed = true;
|
||||
@@ -815,50 +810,26 @@ namespace Microsoft.PowerShell.Commands
|
||||
try
|
||||
{
|
||||
_sender = new Ping();
|
||||
_sender.PingCompleted += OnPingComplete;
|
||||
|
||||
timer?.Start();
|
||||
_sender.SendAsync(targetAddress, timeout, buffer, pingOptions, this);
|
||||
_pingComplete.Wait();
|
||||
timer?.Stop();
|
||||
_pingComplete.Reset();
|
||||
|
||||
if (_pingCompleteArgs == null)
|
||||
{
|
||||
throw new PingException(string.Format(
|
||||
TestConnectionResources.NoPingResult,
|
||||
targetAddress,
|
||||
IPStatus.Unknown));
|
||||
}
|
||||
|
||||
if (_pingCompleteArgs.Cancelled)
|
||||
{
|
||||
// The only cancellation we have implemented is on pipeline stops via StopProcessing().
|
||||
throw new PipelineStoppedException();
|
||||
}
|
||||
|
||||
if (_pingCompleteArgs.Error != null)
|
||||
{
|
||||
throw new PingException(_pingCompleteArgs.Error.Message, _pingCompleteArgs.Error);
|
||||
}
|
||||
|
||||
return _pingCompleteArgs.Reply;
|
||||
// 'SendPingAsync' always uses the default synchronization context (threadpool).
|
||||
// This is what we want to avoid the deadlock resulted by async work being scheduled back to the
|
||||
// pipeline thread due to a change of the current synchronization context of the pipeline thread.
|
||||
return _sender.SendPingAsync(targetAddress, timeout, buffer, pingOptions).GetAwaiter().GetResult();
|
||||
}
|
||||
catch (PingException ex) when (ex.InnerException is TaskCanceledException)
|
||||
{
|
||||
// The only cancellation we have implemented is on pipeline stops via StopProcessing().
|
||||
throw new PipelineStoppedException();
|
||||
}
|
||||
finally
|
||||
{
|
||||
timer?.Stop();
|
||||
_sender?.Dispose();
|
||||
_sender = null;
|
||||
}
|
||||
}
|
||||
|
||||
// This event is triggered when the ping is completed, and passes along the eventargs so that we know
|
||||
// if the ping was cancelled, or an exception was thrown.
|
||||
private static void OnPingComplete(object sender, PingCompletedEventArgs e)
|
||||
{
|
||||
((TestConnectionCommand)e.UserState)._pingCompleteArgs = e;
|
||||
((TestConnectionCommand)e.UserState)._pingComplete.Set();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The class contains information about the source, the destination and ping results.
|
||||
/// </summary>
|
||||
|
||||
@@ -304,3 +304,24 @@ Describe "Connection" -Tag "CI", "RequireAdminOnWindows" {
|
||||
Test-Connection $UnreachableAddress -TcpPort 80 -TimeOut 1 | Should -BeFalse
|
||||
}
|
||||
}
|
||||
|
||||
Describe "Test-Connection should run in the default synchronization context (threadpool)" -Tag "CI" {
|
||||
It "Test-Connection works after constructing a WindowsForm object" -Skip:(!$IsWindows) {
|
||||
$pwsh = Join-Path $PSHOME "pwsh"
|
||||
$pingResults = & $pwsh -NoProfile {
|
||||
Add-Type -AssemblyName System.Windows.Forms
|
||||
$null = New-Object System.Windows.Forms.Form
|
||||
Test-Connection localhost
|
||||
}
|
||||
|
||||
$pingResults.Length | Should -Be 4
|
||||
$result = $pingResults | Select-Object -First 1
|
||||
|
||||
$result.Ping | Should -Be 1
|
||||
$result.Source | Should -BeExactly ([System.Net.Dns]::GetHostName())
|
||||
$result.Destination | Should -BeExactly localhost
|
||||
$result.Latency | Should -BeOfType "long"
|
||||
$result.Reply.Status | Should -BeExactly "Success"
|
||||
$result.BufferSize | Should -Be 32
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user