Пример #1
0
        public static int RunCompiler(
            string clientDirectory,
            string[] args,
            string baseDirectory,
            string sdkDirectory,
            string libDirectory,
            IAnalyzerAssemblyLoader analyzerLoader,
            TextWriter output,
            CancellationToken cancellationToken,
            out bool utf8output)
        {
            var compiler = new CSharpCompilerServer(args, clientDirectory, baseDirectory, sdkDirectory, libDirectory, analyzerLoader);

            utf8output = compiler.Arguments.Utf8Output;

            foreach (var analyzer in compiler.Arguments.AnalyzerReferences)
            {
                CompilerServerFileWatcher.AddPath(analyzer.FilePath);
            }

            return(compiler.Run(output, cancellationToken));
        }
Пример #2
0
        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 ? CompilerServerFileWatcher.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.
            }
        }