示例#1
0
 private void CreateListenTask()
 {
     Debug.Assert(_listenTask == null);
     Debug.Assert(_timeoutTask == null);
     _listenCancellationTokenSource = new CancellationTokenSource();
     _listenTask = _clientConnectionHost.CreateListenTask(_listenCancellationTokenSource.Token);
     _diagnosticListener.ConnectionListening();
 }
示例#2
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.
            }
        }