From 73188ce27a5ad11e0f3487304859fafd79ab0e59 Mon Sep 17 00:00:00 2001 From: Paul Higinbotham Date: Thu, 9 Nov 2017 16:22:39 -0800 Subject: [PATCH] Porting random hang fixes (#5258) --- .../engine/remoting/client/Job.cs | 27 +++++++++++++------ .../remoting/commands/InvokeCommandCommand.cs | 14 ++++++++-- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/src/System.Management.Automation/engine/remoting/client/Job.cs b/src/System.Management.Automation/engine/remoting/client/Job.cs index a86af8f8ec..4119000e26 100644 --- a/src/System.Management.Automation/engine/remoting/client/Job.cs +++ b/src/System.Management.Automation/engine/remoting/client/Job.cs @@ -1542,14 +1542,25 @@ namespace System.Management.Automation /// internal void CloseAllStreams() { - if (_resultsOwner) _results.Complete(); - if (_outputOwner) _output.Complete(); - if (_errorOwner) _error.Complete(); - if (_progressOwner) _progress.Complete(); - if (_verboseOwner) _verbose.Complete(); - if (_warningOwner) _warning.Complete(); - if (_debugOwner) _debug.Complete(); - if (_informationOwner) _information.Complete(); + // The Complete() method includes raising public notification events that third parties can + // handle and potentially throw exceptions on the notification thread. We don't want to + // propagate those exceptions because it prevents this thread from completing its processing. + if (_resultsOwner) { try { _results.Complete(); } catch (Exception e) { TraceException(e); } } + if (_outputOwner) { try { _output.Complete(); } catch (Exception e) { TraceException(e); } } + if (_errorOwner) { try { _error.Complete(); } catch (Exception e) { TraceException(e); } } + if (_progressOwner) { try { _progress.Complete(); } catch (Exception e) { TraceException(e); } } + if (_verboseOwner) { try { _verbose.Complete(); } catch (Exception e) { TraceException(e); } } + if (_warningOwner) { try { _warning.Complete(); } catch (Exception e) { TraceException(e); } } + if (_debugOwner) { try { _debug.Complete(); } catch (Exception e) { TraceException(e); } } + if (_informationOwner) { try { _information.Complete(); } catch (Exception e) { TraceException(e); } } + } + + private static void TraceException(Exception e) + { + using (PowerShellTraceSource tracer = PowerShellTraceSourceFactory.GetTraceSource()) + { + tracer.TraceException(e); + } } /// diff --git a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs index 5e60df6156..1340ce66b6 100644 --- a/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs +++ b/src/System.Management.Automation/engine/remoting/commands/InvokeCommandCommand.cs @@ -1624,7 +1624,12 @@ namespace Microsoft.PowerShell.Commands /// Write in a non-blocking manner private void WriteJobResults(bool nonblocking) { - if (_job != null) + if (_job == null) + { + return; + } + + try { PipelineStoppedException caughtPipelineStoppedException = null; _job.PropagateThrows = _propagateErrors; @@ -1756,7 +1761,12 @@ namespace Microsoft.PowerShell.Commands session.Name, session.InstanceId)); } } - + } + } + finally + { + if (_job.JobStateInfo.State == JobState.Disconnected) + { // Allow Invoke-Command to end even though not all remote pipelines // finished. HandleThrottleComplete(null, null);