internal static Task CreateWatchFilesTask()
            {
                var source = new TaskCompletionSource <bool>();
                var _      = new AnalyzerWatcher(source);

                return(source.Task);
            }
Exemple #2
0
        /// <summary>
        /// Create a new server that listens on the given base pipe name.
        /// When a request comes in, it is dispatched on a separate thread
        /// via the IRequestHandler interface passed in.
        /// </summary>
        /// <param name="basePipeName">Base name for named pipe</param>
        /// <param name="handler">Handler that handles requests</param>
        /// <param name="serverDieTimeout">
        /// The timeout in milliseconds before the server automatically dies.
        /// </param>
        public ServerDispatcher(string basePipeName,
                                IRequestHandler handler,
                                int serverDieTimeout)
        {
            this.basePipeName = basePipeName;
            this.handler      = handler;

            this.keepAliveTimer = new KeepAliveTimer(serverDieTimeout);

            var _ = new AnalyzerWatcher(this);
        }
        public void ListenAndDispatchConnections(string pipeName, TimeSpan?keepAlive, bool watchAnalyzerFiles, CancellationToken cancellationToken = default(CancellationToken))
        {
            Debug.Assert(SynchronizationContext.Current == null);

            var  isKeepAliveDefault = true;
            var  connectionList     = new List <ConnectionData>();
            Task gcTask             = null;
            Task timeoutTask        = null;
            Task <NamedPipeServerStream> listenTask = null;
            CancellationTokenSource      listenCancellationTokenSource = null;

            // If we aren't being asked to watch analyzer files then simple create a Task which never
            // completes.  This is the behavior of AnalyzerWatcher when files don't change on disk.
            Task analyzerTask = watchAnalyzerFiles ? AnalyzerWatcher.CreateWatchFilesTask() : new TaskCompletionSource <bool>().Task;

            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 = CreateListenTask(pipeName, 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, analyzerTask }, cancellationToken);

                // If there is a connection event that has highest priority.
                if (listenTask.IsCompleted && !cancellationToken.IsCancellationRequested)
                {
                    var changeKeepAliveSource = new TaskCompletionSource <TimeSpan?>();
                    var connectionTask        = CreateHandleConnectionTask(listenTask, changeKeepAliveSource, cancellationToken);
                    connectionList.Add(new ConnectionData(connectionTask, changeKeepAliveSource.Task));
                    listenTask = null;
                    listenCancellationTokenSource = null;
                    timeoutTask = null;
                    gcTask      = null;
                    continue;
                }

                if ((timeoutTask != null && timeoutTask.IsCompleted) || analyzerTask.IsCompleted || cancellationToken.IsCancellationRequested)
                {
                    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.
                    listenCancellationTokenSource.Cancel();
                    break;
                }

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

            try
            {
                Task.WaitAll(connectionList.Select(x => x.ConnectionTask).ToArray());
            }
            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.
            }
        }
        /// <summary>
        /// Create a new server that listens on the given base pipe name.
        /// When a request comes in, it is dispatched on a separate thread
        /// via the IRequestHandler interface passed in.
        /// </summary>
        /// <param name="basePipeName">Base name for named pipe</param>
        /// <param name="handler">Handler that handles requests</param>
        /// <param name="serverDieTimeout">
        /// The timeout in milliseconds before the server automatically dies.
        /// </param>
        public ServerDispatcher(string basePipeName,
                                IRequestHandler handler,
                                int serverDieTimeout)
        {
            this.basePipeName = basePipeName;
            this.handler = handler;

            this.serverDieTimeout = serverDieTimeout;

            var _ = new AnalyzerWatcher(this);
        }
 internal static Task CreateWatchFilesTask()
 {
     var source = new TaskCompletionSource<bool>();
     var _ = new AnalyzerWatcher(source);
     return source.Task;
 }