提交 32df6a6f 编写于 作者: S shgu

Merge remote-tracking branch 'origin/dev15.8-preview2' into merges/dev15.8-preview2-to-master

...@@ -137,8 +137,8 @@ public IInteractiveWindow CurrentWindow ...@@ -137,8 +137,8 @@ public IInteractiveWindow CurrentWindow
_currentWindow = value; _currentWindow = value;
_workspace.Window = value; _workspace.Window = value;
_interactiveHost.SetOutput( _currentWindow.OutputWriter); _interactiveHost.Output = _currentWindow.OutputWriter;
_interactiveHost.SetErrorOutput(_currentWindow.ErrorOutputWriter); _interactiveHost.ErrorOutput = _currentWindow.ErrorOutputWriter;
_currentWindow.SubmissionBufferAdded += SubmissionBufferAdded; _currentWindow.SubmissionBufferAdded += SubmissionBufferAdded;
_interactiveCommands = _commandsFactory.CreateInteractiveCommands(_currentWindow, CommandPrefix, _commands); _interactiveCommands = _commandsFactory.CreateInteractiveCommands(_currentWindow, CommandPrefix, _commands);
...@@ -171,8 +171,8 @@ private IInteractiveWindow GetCurrentWindowOrThrow() ...@@ -171,8 +171,8 @@ private IInteractiveWindow GetCurrentWindowOrThrow()
public Task<ExecutionResult> InitializeAsync() public Task<ExecutionResult> InitializeAsync()
{ {
var window = GetCurrentWindowOrThrow(); var window = GetCurrentWindowOrThrow();
_interactiveHost.SetOutput(window.OutputWriter); _interactiveHost.Output = window.OutputWriter;
_interactiveHost.SetErrorOutput(window.ErrorOutputWriter); _interactiveHost.ErrorOutput = window.ErrorOutputWriter;
return ResetAsyncWorker(); return ResetAsyncWorker();
} }
......
...@@ -81,8 +81,8 @@ private async Task<InitializedRemoteService> TryStartAndInitializeProcessAsync(C ...@@ -81,8 +81,8 @@ private async Task<InitializedRemoteService> TryStartAndInitializeProcessAsync(C
if (!initializationResult.Success) if (!initializationResult.Success)
{ {
Host.ReportProcessExited(remoteService.Process);
remoteService.Dispose(joinThreads: false); remoteService.Dispose(joinThreads: false);
Host.ReportProcessExited(remoteService.Process);
return default(InitializedRemoteService); return default(InitializedRemoteService);
} }
......
...@@ -74,14 +74,9 @@ private async void ProcessExitedHandler(object _, EventArgs __) ...@@ -74,14 +74,9 @@ private async void ProcessExitedHandler(object _, EventArgs __)
_processExitHandlerStatus = ProcessExitHandlerStatus.Handled; _processExitHandlerStatus = ProcessExitHandlerStatus.Handled;
// Should set _processExitHandlerStatus before calling OnProcessExited to avoid deadlocks. // Should set _processExitHandlerStatus before calling OnProcessExited to avoid deadlocks.
// Calling the host should be within the lock to prevent its disposing during the execution. // Calling the host should be within the lock to prevent its disposing during the execution.
await _host.OnProcessExited(Process).ConfigureAwait(false);
} }
} }
var host = _host;
if (host != null)
{
await host.OnProcessExited(Process).ConfigureAwait(false);
}
} }
catch (Exception e) when (FatalError.Report(e)) catch (Exception e) when (FatalError.Report(e))
{ {
...@@ -119,17 +114,19 @@ private void ReadOutput(bool error) ...@@ -119,17 +114,19 @@ private void ReadOutput(bool error)
} }
} }
// Dispose may called anytime.
internal void Dispose(bool joinThreads) internal void Dispose(bool joinThreads)
{ {
// There can be a call from host initiated from OnProcessExit. // There can be a call from host initiated from OnProcessExit.
// We should not proceed with disposing if _disposeSemaphore is locked. // This check on the beginning helps to avoid a reentrancy.
using (_disposeSemaphore.DisposableWait()) if (_processExitHandlerStatus == ProcessExitHandlerStatus.Hooked)
{ {
if (_processExitHandlerStatus == ProcessExitHandlerStatus.Hooked) using (_disposeSemaphore.DisposableWait())
{ {
Process.Exited -= ProcessExitedHandler; if (_processExitHandlerStatus == ProcessExitHandlerStatus.Hooked)
_processExitHandlerStatus = ProcessExitHandlerStatus.Handled; {
Process.Exited -= ProcessExitedHandler;
_processExitHandlerStatus = ProcessExitHandlerStatus.Handled;
}
} }
} }
......
...@@ -40,8 +40,6 @@ internal sealed partial class InteractiveHost : MarshalByRefObject ...@@ -40,8 +40,6 @@ internal sealed partial class InteractiveHost : MarshalByRefObject
private TextWriter _output; private TextWriter _output;
private TextWriter _errorOutput; private TextWriter _errorOutput;
private readonly object _outputGuard;
private readonly object _errorOutputGuard;
internal event Action<bool> ProcessStarting; internal event Action<bool> ProcessStarting;
...@@ -57,8 +55,6 @@ internal sealed partial class InteractiveHost : MarshalByRefObject ...@@ -57,8 +55,6 @@ internal sealed partial class InteractiveHost : MarshalByRefObject
_replServiceProviderType = replServiceProviderType; _replServiceProviderType = replServiceProviderType;
_hostPath = hostPath; _hostPath = hostPath;
_initialWorkingDirectory = workingDirectory; _initialWorkingDirectory = workingDirectory;
_outputGuard = new object();
_errorOutputGuard = new object();
var serverProvider = new BinaryServerFormatterSinkProvider { TypeFilterLevel = TypeFilterLevel.Full }; var serverProvider = new BinaryServerFormatterSinkProvider { TypeFilterLevel = TypeFilterLevel.Full };
_serverChannel = new IpcServerChannel(GenerateUniqueChannelLocalName(), "ReplChannel-" + Guid.NewGuid(), serverProvider); _serverChannel = new IpcServerChannel(GenerateUniqueChannelLocalName(), "ReplChannel-" + Guid.NewGuid(), serverProvider);
...@@ -73,9 +69,9 @@ internal sealed partial class InteractiveHost : MarshalByRefObject ...@@ -73,9 +69,9 @@ internal sealed partial class InteractiveHost : MarshalByRefObject
internal Process TryGetProcess() internal Process TryGetProcess()
{ {
InitializedRemoteService initializedService; InitializedRemoteService initializedService;
var lazyRemoteService = _lazyRemoteService;
return (lazyRemoteService?.InitializedService != null && return (_lazyRemoteService?.InitializedService != null &&
lazyRemoteService.InitializedService.TryGetValue(out initializedService)) ? initializedService.ServiceOpt.Process : null; _lazyRemoteService.InitializedService.TryGetValue(out initializedService)) ? initializedService.ServiceOpt.Process : null;
} }
internal Service TryGetService() internal Service TryGetService()
...@@ -171,11 +167,7 @@ private RemoteService TryStartProcess(CultureInfo culture, CancellationToken can ...@@ -171,11 +167,7 @@ private RemoteService TryStartProcess(CultureInfo culture, CancellationToken can
return null; return null;
} }
lock (_outputGuard) _output.WriteLine(FeaturesResources.Attempt_to_connect_to_process_Sharp_0_failed_retrying, newProcessId);
{
_output.WriteLine(FeaturesResources.Attempt_to_connect_to_process_Sharp_0_failed_retrying, newProcessId);
}
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
} }
...@@ -220,12 +212,8 @@ private bool CheckAlive(Process process) ...@@ -220,12 +212,8 @@ private bool CheckAlive(Process process)
bool alive = process.IsAlive(); bool alive = process.IsAlive();
if (!alive) if (!alive)
{ {
string errorString = process.StandardError.ReadToEnd(); _errorOutput.WriteLine(FeaturesResources.Failed_to_launch_0_process_exit_code_colon_1_with_output_colon, _hostPath, process.ExitCode);
lock (_errorOutputGuard) _errorOutput.WriteLine(process.StandardError.ReadToEnd());
{
_errorOutput.WriteLine(FeaturesResources.Failed_to_launch_0_process_exit_code_colon_1_with_output_colon, _hostPath, process.ExitCode);
_errorOutput.WriteLine(errorString);
}
} }
return alive; return alive;
...@@ -236,12 +224,9 @@ private bool CheckAlive(Process process) ...@@ -236,12 +224,9 @@ private bool CheckAlive(Process process)
DisposeRemoteService(disposing: false); DisposeRemoteService(disposing: false);
} }
// Dispose may be called anytime.
public void Dispose() public void Dispose()
{ {
DisposeChannel(); DisposeChannel();
SetOutput(TextWriter.Null);
SetErrorOutput(TextWriter.Null);
DisposeRemoteService(disposing: true); DisposeRemoteService(disposing: true);
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
...@@ -264,31 +249,41 @@ private void DisposeChannel() ...@@ -264,31 +249,41 @@ private void DisposeChannel()
} }
} }
public void SetOutput(TextWriter value) public TextWriter Output
{ {
if (value == null) get
{ {
throw new ArgumentNullException(nameof(value)); return _output;
} }
lock(_outputGuard) set
{ {
_output.Flush(); if (value == null)
_output = value; {
throw new ArgumentNullException(nameof(value));
}
var oldOutput = Interlocked.Exchange(ref _output, value);
oldOutput.Flush();
} }
} }
public void SetErrorOutput(TextWriter value) public TextWriter ErrorOutput
{ {
if (value == null) get
{ {
throw new ArgumentNullException(nameof(value)); return _errorOutput;
} }
lock(_errorOutputGuard) set
{ {
_errorOutput.Flush(); if (value == null)
_errorOutput = value; {
throw new ArgumentNullException(nameof(value));
}
var oldOutput = Interlocked.Exchange(ref _errorOutput, value);
oldOutput.Flush();
} }
} }
...@@ -296,12 +291,8 @@ internal void OnOutputReceived(bool error, char[] buffer, int count) ...@@ -296,12 +291,8 @@ internal void OnOutputReceived(bool error, char[] buffer, int count)
{ {
(error ? ErrorOutputReceived : OutputReceived)?.Invoke(buffer, count); (error ? ErrorOutputReceived : OutputReceived)?.Invoke(buffer, count);
var writer = error ? _errorOutput : _output; var writer = error ? ErrorOutput : Output;
var guard = error ? _errorOutputGuard : _outputGuard; writer.Write(buffer, 0, count);
lock (guard)
{
writer.Write(buffer, 0, count);
}
} }
private LazyRemoteService CreateRemoteService(InteractiveHostOptions options, bool skipInitialization) private LazyRemoteService CreateRemoteService(InteractiveHostOptions options, bool skipInitialization)
...@@ -329,10 +320,7 @@ private void ReportProcessExited(Process process) ...@@ -329,10 +320,7 @@ private void ReportProcessExited(Process process)
if (exitCode.HasValue) if (exitCode.HasValue)
{ {
lock (_errorOutputGuard) _errorOutput.WriteLine(FeaturesResources.Hosting_process_exited_with_exit_code_0, exitCode.Value);
{
_errorOutput.WriteLine(FeaturesResources.Hosting_process_exited_with_exit_code_0, exitCode.Value);
}
} }
} }
...@@ -342,14 +330,11 @@ private async Task<InitializedRemoteService> TryGetOrCreateRemoteServiceAsync(bo ...@@ -342,14 +330,11 @@ private async Task<InitializedRemoteService> TryGetOrCreateRemoteServiceAsync(bo
{ {
LazyRemoteService currentRemoteService = _lazyRemoteService; LazyRemoteService currentRemoteService = _lazyRemoteService;
// disposed or not reset:
Debug.Assert(currentRemoteService != null);
for (int attempt = 0; attempt < MaxAttemptsToCreateProcess; attempt++) for (int attempt = 0; attempt < MaxAttemptsToCreateProcess; attempt++)
{ {
// Remote service may be disposed anytime.
if (currentRemoteService == null)
{
return default;
}
var initializedService = await currentRemoteService.InitializedService.GetValueAsync(currentRemoteService.CancellationSource.Token).ConfigureAwait(false); var initializedService = await currentRemoteService.InitializedService.GetValueAsync(currentRemoteService.CancellationSource.Token).ConfigureAwait(false);
if (initializedService.ServiceOpt != null && initializedService.ServiceOpt.Process.IsAlive()) if (initializedService.ServiceOpt != null && initializedService.ServiceOpt.Process.IsAlive())
{ {
...@@ -374,10 +359,7 @@ private async Task<InitializedRemoteService> TryGetOrCreateRemoteServiceAsync(bo ...@@ -374,10 +359,7 @@ private async Task<InitializedRemoteService> TryGetOrCreateRemoteServiceAsync(bo
} }
} }
lock (_errorOutputGuard) _errorOutput.WriteLine(FeaturesResources.Unable_to_create_hosting_process);
{
_errorOutput.WriteLine(FeaturesResources.Unable_to_create_hosting_process);
}
} }
catch (OperationCanceledException) catch (OperationCanceledException)
{ {
......
...@@ -92,8 +92,8 @@ private void RedirectOutput() ...@@ -92,8 +92,8 @@ private void RedirectOutput()
_synchronizedOutput = new SynchronizedStringWriter(); _synchronizedOutput = new SynchronizedStringWriter();
_synchronizedErrorOutput = new SynchronizedStringWriter(); _synchronizedErrorOutput = new SynchronizedStringWriter();
ClearOutput(); ClearOutput();
_host.SetOutput(_synchronizedOutput); _host.Output = _synchronizedOutput;
_host.SetErrorOutput(_synchronizedErrorOutput); _host.ErrorOutput = _synchronizedErrorOutput;
} }
private bool LoadReference(string reference) private bool LoadReference(string reference)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册