private async Task ProcessExitedHandlerAsync()
            {
                try
                {
                    using (await _disposeSemaphore.DisposableWaitAsync().ConfigureAwait(false))
                    {
                        if (_processExitHandlerStatus == ProcessExitHandlerStatus.Hooked)
                        {
                            Process.Exited           -= ProcessExitedHandler;
                            _processExitHandlerStatus = ProcessExitHandlerStatus.Handled;
                            // Should set _processExitHandlerStatus before calling OnProcessExited to avoid deadlocks.
                            // Calling the host should be within the lock to prevent its disposing during the execution.
                        }
                    }

                    var host = _host;
                    if (host != null)
                    {
                        await host.OnProcessExited(Process).ConfigureAwait(false);
                    }
                }
                catch (Exception e) when(FatalError.Report(e))
                {
                    throw ExceptionUtilities.Unreachable;
                }
            }
            private volatile ProcessExitHandlerStatus _processExitHandlerStatus; // set to Handled on dispose

            internal RemoteService(InteractiveHost host, Process process, int processId, Service service)
            {
                Debug.Assert(host != null);
                Debug.Assert(process != null);
                Debug.Assert(service != null);

                Process = process;
                Service = service;

                _host = host;
                _joinOutputWritingThreadsOnDisposal = host._joinOutputWritingThreadsOnDisposal;
                _processId = processId;
                _processExitHandlerStatus = ProcessExitHandlerStatus.Uninitialized;

                // TODO (tomat): consider using single-thread async readers
                _readOutputThread              = new Thread(() => ReadOutput(error: false));
                _readOutputThread.Name         = "InteractiveHost-OutputReader-" + processId;
                _readOutputThread.IsBackground = true;
                _readOutputThread.Start();

                _readErrorOutputThread              = new Thread(() => ReadOutput(error: true));
                _readErrorOutputThread.Name         = "InteractiveHost-ErrorOutputReader-" + processId;
                _readErrorOutputThread.IsBackground = true;
                _readErrorOutputThread.Start();
            }
Exemple #3
0
            private volatile ProcessExitHandlerStatus _processExitHandlerStatus; // set to Handled on dispose

            internal RemoteService(
                InteractiveHost host,
                Process process,
                int processId,
                JsonRpc jsonRpc,
                InteractiveHostPlatformInfo platformInfo,
                InteractiveHostOptions options
                )
            {
                Process      = process;
                JsonRpc      = jsonRpc;
                PlatformInfo = platformInfo;
                Options      = options;

                _host = host;
                _joinOutputWritingThreadsOnDisposal = _host._joinOutputWritingThreadsOnDisposal;
                _processId = processId;
                _processExitHandlerStatus = ProcessExitHandlerStatus.Uninitialized;

                // TODO (tomat): consider using single-thread async readers
                _readOutputThread              = new Thread(() => ReadOutput(error: false));
                _readOutputThread.Name         = "InteractiveHost-OutputReader-" + processId;
                _readOutputThread.IsBackground = true;
                _readOutputThread.Start();

                _readErrorOutputThread              = new Thread(() => ReadOutput(error: true));
                _readErrorOutputThread.Name         = "InteractiveHost-ErrorOutputReader-" + processId;
                _readErrorOutputThread.IsBackground = true;
                _readErrorOutputThread.Start();
            }
 internal void HookAutoRestartEvent()
 {
     using (_disposeSemaphore.DisposableWait())
     {
         // hook the event only once per process:
         if (_processExitHandlerStatus == ProcessExitHandlerStatus.Uninitialized)
         {
             Process.Exited           += ProcessExitedHandler;
             _processExitHandlerStatus = ProcessExitHandlerStatus.Hooked;
         }
     }
 }
            // Dispose may called anytime, on any thread.
            internal void Dispose()
            {
                // There can be a call from host initiated from OnProcessExit.
                // We should not proceed with disposing if _disposeSemaphore is locked.
                using (_disposeSemaphore.DisposableWait())
                {
                    if (_processExitHandlerStatus == ProcessExitHandlerStatus.Hooked)
                    {
                        Process.Exited           -= ProcessExitedHandler;
                        _processExitHandlerStatus = ProcessExitHandlerStatus.Handled;
                    }
                }

                InitiateTermination(Process, _processId);

                if (_joinOutputWritingThreadsOnDisposal)
                {
                    try
                    {
                        _readOutputThread?.Join();
                    }
                    catch (ThreadStateException)
                    {
                        // thread hasn't started
                    }

                    try
                    {
                        _readErrorOutputThread?.Join();
                    }
                    catch (ThreadStateException)
                    {
                        // thread hasn't started
                    }
                }

                // null the host so that we don't attempt to write to the buffer anymore:
                _host = null;

                _readOutputThread = _readErrorOutputThread = null;
            }
            internal void Dispose(bool joinThreads)
            {
                // There can be a call from host initiated from OnProcessExit.
                // This check on the beginning helps to avoid a reentrancy.
                if (_processExitHandlerStatus == ProcessExitHandlerStatus.Hooked)
                {
                    using (_disposeSemaphore.DisposableWait())
                    {
                        if (_processExitHandlerStatus == ProcessExitHandlerStatus.Hooked)
                        {
                            Process.Exited           -= ProcessExitedHandler;
                            _processExitHandlerStatus = ProcessExitHandlerStatus.Handled;
                        }
                    }
                }

                InitiateTermination(Process, _processId);

                try
                {
                    _readOutputThread?.Join();
                }
                catch (ThreadStateException)
                {
                    // thread hasn't started
                }

                try
                {
                    _readErrorOutputThread?.Join();
                }
                catch (ThreadStateException)
                {
                    // thread hasn't started
                }

                // null the host so that we don't attempt to write to the buffer anymore:
                _host = null;

                _readOutputThread = _readErrorOutputThread = null;
            }