Esempio n. 1
0
        private void HandleCompletedListenTask(CancellationToken cancellationToken)
        {
            _diagnosticListener.ConnectionReceived();
            var allowCompilationRequests = _state == State.Running;
            var connectionTask           = HandleClientConnection(_listenTask, allowCompilationRequests, cancellationToken);

            _connectionList.Add(connectionTask);

            // Timeout and GC are only done when there are no active connections.  Now that we have a new
            // connection cancel out these tasks.
            _timeoutTask = null;
            _gcTask      = null;

            // Begin listening again for new connections.
            _listenTask = null;
            CreateListenTask();
        }
Esempio n. 2
0
        private void CheckCompletedTasks(CancellationToken cancellationToken)
        {
            if (cancellationToken.IsCancellationRequested)
            {
                ChangeToShuttingDown("Server cancellation");
                Debug.Assert(_gcTask is null);
                Debug.Assert(_timeoutTask is null);
            }

            if (_listenTask?.IsCompleted == true)
            {
                _diagnosticListener.ConnectionReceived();
                var connectionTask = ProcessClientConnectionAsync(
                    _compilerServerHost,
                    _listenTask,
                    allowCompilationRequests: _state == State.Running,
                    cancellationToken
                    );
                _connectionList.Add(connectionTask);

                // Timeout and GC are only done when there are no active connections.  Now that we have a new
                // connection cancel out these tasks.
                _timeoutTask = null;
                _gcTask      = null;
                _listenTask  = null;
            }

            if (_timeoutTask?.IsCompleted == true)
            {
                _diagnosticListener.KeepAliveReached();
                ChangeToShuttingDown("Keep alive hit");
            }

            if (_gcTask?.IsCompleted == true)
            {
                RunGC();
            }

            HandleCompletedConnections();
        }
Esempio n. 3
0
        /// <summary>
        /// This function will accept and process new connections until an event causes
        /// the server to enter a passive shut down mode.  For example if analyzers change
        /// or the keep alive timeout is hit.  At which point this function will cease
        /// accepting new connections and wait for existing connections to complete before
        /// returning.
        /// </summary>
        public void ListenAndDispatchConnections(TimeSpan?keepAlive, CancellationToken cancellationToken = default(CancellationToken))
        {
            var  isKeepAliveDefault             = true;
            var  connectionList                 = new List <Task <ConnectionData> >();
            Task gcTask                         = null;
            Task timeoutTask                    = null;
            Task <IClientConnection> listenTask = null;
            CancellationTokenSource  listenCancellationTokenSource = null;

            do
            {
                // While this loop is running there should be an active named pipe listening for a
                // connection.
                if (listenTask == null)
                {
                    Debug.Assert(listenCancellationTokenSource == null);
                    Debug.Assert(timeoutTask == null);
                    listenCancellationTokenSource = new CancellationTokenSource();
                    listenTask = _clientConnectionHost.CreateListenTask(listenCancellationTokenSource.Token);
                }

                // If there are no active clients running then the server needs to be in a timeout mode.
                if (connectionList.Count == 0 && timeoutTask == null && keepAlive.HasValue)
                {
                    Debug.Assert(listenTask != null);
                    timeoutTask = Task.Delay(keepAlive.Value);
                }

                WaitForAnyCompletion(connectionList, new[] { listenTask, timeoutTask, gcTask }, cancellationToken);

                // If there is a connection event that has highest priority.
                if (listenTask.IsCompleted && !cancellationToken.IsCancellationRequested)
                {
                    _diagnosticListener.ConnectionReceived();
                    var connectionTask = HandleClientConnection(listenTask, cancellationToken);
                    connectionList.Add(connectionTask);
                    listenTask = null;
                    listenCancellationTokenSource = null;
                    timeoutTask = null;
                    gcTask      = null;
                    continue;
                }

                if ((timeoutTask != null && timeoutTask.IsCompleted) || cancellationToken.IsCancellationRequested)
                {
                    _diagnosticListener.KeepAliveReached();
                    listenCancellationTokenSource.Cancel();
                    break;
                }

                if (gcTask != null && gcTask.IsCompleted)
                {
                    gcTask = null;
                    GC.Collect();
                    continue;
                }

                // Only other option is a connection event.  Go ahead and clear out the dead connections
                if (!CheckConnectionTask(connectionList, ref keepAlive, ref isKeepAliveDefault))
                {
                    // If there is a client disconnection detected then the server needs to begin
                    // the shutdown process.  We have to assume that the client disconnected via
                    // Ctrl+C and wants the server process to terminate.  It's possible a compilation
                    // is running out of control and the client wants their machine back.
                    _diagnosticListener.ConnectionRudelyEnded();
                    listenCancellationTokenSource.Cancel();
                    break;
                }

                if (connectionList.Count == 0 && gcTask == null)
                {
                    gcTask = Task.Delay(GCTimeout);
                }
            } while (true);

            try
            {
                if (connectionList.Count > 0)
                {
                    Task.WaitAll(connectionList.ToArray());

                    TimeSpan?ignoredTimeSpan = null;
                    bool     ignoredBool     = false;
                    CheckConnectionTask(connectionList, ref ignoredTimeSpan, ref ignoredBool);
                }
            }
            catch
            {
                // Server is shutting down, don't care why the above failed and Exceptions
                // are expected here.  For example AggregateException via, OperationCancelledException
                // is an expected case.
            }
        }