示例#1
0
        internal static async Task <ServerResponse> Send(string pipeName, ServerRequest request)
        {
            using (var client = await Client.ConnectAsync(pipeName, timeout: null, cancellationToken: default).ConfigureAwait(false))
            {
                await request.WriteAsync(client.Stream).ConfigureAwait(false);

                return(await ServerResponse.ReadAsync(client.Stream).ConfigureAwait(false));
            }
        }
示例#2
0
        protected async override Task <int> ExecuteCoreAsync()
        {
            if (!IsServerRunning())
            {
                // server isn't running right now
                Out.Write("Server is not running.");
                return(0);
            }

            try
            {
                using (var client = await Client.ConnectAsync(Pipe.Value(), timeout: TimeSpan.FromSeconds(5), cancellationToken: Cancelled))
                {
                    if (client == null)
                    {
                        throw new InvalidOperationException("Couldn't connect to the server.");
                    }

                    var request = ServerRequest.CreateShutdown();
                    await request.WriteAsync(client.Stream, Cancelled).ConfigureAwait(false);

                    var response = ((ShutdownServerResponse)await ServerResponse.ReadAsync(client.Stream, Cancelled));

                    if (Wait.HasValue())
                    {
                        try
                        {
                            var process = Process.GetProcessById(response.ServerProcessId);
                            process.WaitForExit();
                        }
                        catch (Exception ex)
                        {
                            // There is an inherent race here with the server process.  If it has already shutdown
                            // by the time we try to access it then the operation has succeeded.
                            Error.Write(ex);
                        }

                        Out.Write("Server pid:{0} shut down completed.", response.ServerProcessId);
                    }
                }
            }
            catch (Exception ex) when(IsServerRunning())
            {
                // Ignore an exception that occurred while the server was shutting down.
                Error.Write(ex);
            }

            return(0);
        }
示例#3
0
        protected async override Task <int> ExecuteCoreAsync()
        {
            if (!IsServerRunning())
            {
                // server isn't running right now
                Out.Write("Server is not running.");
                return(0);
            }

            try
            {
                using (var client = await Client.ConnectAsync(Pipe.Value(), timeout: null, cancellationToken: Cancelled))
                {
                    var request = BuildRequest.CreateShutdown();
                    await request.WriteAsync(client.Stream, Cancelled).ConfigureAwait(false);

                    var response = ((ShutdownBuildResponse)await BuildResponse.ReadAsync(client.Stream, Cancelled));

                    if (Wait.HasValue())
                    {
                        try
                        {
                            var process = Process.GetProcessById(response.ServerProcessId);
                            process.WaitForExit();
                        }
                        catch (Exception)
                        {
                            // There is an inherent race here with the server process.  If it has already shutdown
                            // by the time we try to access it then the operation has succeed.
                        }

                        Out.Write("Server pid:{0} shut down", response.ServerProcessId);
                    }
                }
            }
            catch (Exception) when(IsServerRunning())
            {
                // Ignore an exception that occurred while the server was shutting down.
            }

            return(0);
        }
示例#4
0
        private static async Task <ServerResponse> RunOnServerCore(
            IList <string> arguments,
            ServerPaths serverPaths,
            string pipeName,
            string keepAlive,
            int?timeoutOverride,
            TryCreateServerCoreDelegate <string, string, int?, bool, bool> tryCreateServerFunc,
            CancellationToken cancellationToken,
            bool debug)
        {
            if (pipeName == null)
            {
                return(new RejectedServerResponse());
            }

            if (serverPaths.TempDirectory == null)
            {
                return(new RejectedServerResponse());
            }

            var           clientDir              = serverPaths.ClientDirectory;
            var           timeoutNewProcess      = timeoutOverride ?? TimeOutMsNewProcess;
            var           timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess;
            var           clientMutexName        = MutexName.GetClientMutexName(pipeName);
            Task <Client> pipeTask = null;

            Mutex clientMutex = null;
            var   holdsMutex  = false;

            try
            {
                try
                {
                    clientMutex = new Mutex(initiallyOwned: true, name: clientMutexName, createdNew: out holdsMutex);
                }
                catch (Exception ex)
                {
                    // The Mutex constructor can throw in certain cases. One specific example is docker containers
                    // where the /tmp directory is restricted. In those cases there is no reliable way to execute
                    // the server and we need to fall back to the command line.
                    // Example: https://github.com/dotnet/roslyn/issues/24124

                    ServerLogger.LogException(ex, "Client mutex creation failed.");

                    return(new RejectedServerResponse());
                }

                if (!holdsMutex)
                {
                    try
                    {
                        holdsMutex = clientMutex.WaitOne(timeoutNewProcess);

                        if (!holdsMutex)
                        {
                            return(new RejectedServerResponse());
                        }
                    }
                    catch (AbandonedMutexException)
                    {
                        holdsMutex = true;
                    }
                }

                // Check for an already running server
                var serverMutexName  = MutexName.GetServerMutexName(pipeName);
                var wasServerRunning = WasServerMutexOpen(serverMutexName);
                var timeout          = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess;

                if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName, out var _, debug))
                {
                    pipeTask = Client.ConnectAsync(pipeName, TimeSpan.FromMilliseconds(timeout), cancellationToken);
                }
            }
            finally
            {
                if (holdsMutex)
                {
                    clientMutex?.ReleaseMutex();
                }

                clientMutex?.Dispose();
            }

            if (pipeTask != null)
            {
                var client = await pipeTask.ConfigureAwait(false);

                if (client != null)
                {
                    var request = ServerRequest.Create(
                        serverPaths.WorkingDirectory,
                        serverPaths.TempDirectory,
                        arguments,
                        keepAlive);

                    return(await TryProcessRequest(client, request, cancellationToken).ConfigureAwait(false));
                }
            }

            return(new RejectedServerResponse());
        }
示例#5
0
        public async Task ServerRunning_CancelCompilation_CancelsSuccessfully()
        {
            // Arrange
            const int requestCount     = 5;
            var       count            = 0;
            var       completionSource = new TaskCompletionSource <bool>();
            var       host             = CreateCompilerHost(c => c.ExecuteFunc = (req, ct) =>
            {
                if (Interlocked.Increment(ref count) == requestCount)
                {
                    completionSource.SetResult(true);
                }

                ct.WaitHandle.WaitOne();
                return(new RejectedServerResponse());
            });

            var semaphore = new SemaphoreSlim(1);
            Action <object, EventArgs> onListening = (s, e) =>
            {
                semaphore.Release();
            };

            using (var serverData = ServerUtilities.CreateServer(compilerHost: host, onListening: onListening))
            {
                // Send all the requests.
                var clients = new List <Client>();
                for (var i = 0; i < requestCount; i++)
                {
                    // Wait for the server to start listening.
                    await semaphore.WaitAsync(TimeSpan.FromMinutes(1));

                    var client = await Client.ConnectAsync(serverData.PipeName, timeout : null, cancellationToken : default);

                    await EmptyServerRequest.WriteAsync(client.Stream);

                    clients.Add(client);
                }

                // Act
                // Wait until all of the connections are being processed by the server.
                await completionSource.Task;

                // Now cancel
                var stats = await serverData.CancelAndCompleteAsync();

                // Assert
                Assert.Equal(requestCount, stats.Connections);
                Assert.Equal(requestCount, count);

                // Read the server response to each client.
                foreach (var client in clients)
                {
                    var task = ServerResponse.ReadAsync(client.Stream);
                    // We expect this to throw because the stream is already closed.
                    await Assert.ThrowsAnyAsync <IOException>(() => task);

                    client.Dispose();
                }
            }
        }
示例#6
0
        private static async Task <ServerResponse> RunOnServerCore(
            IList <string> arguments,
            ServerPaths buildPaths,
            string pipeName,
            string keepAlive,
            int?timeoutOverride,
            Func <string, string, bool, bool> tryCreateServerFunc,
            CancellationToken cancellationToken,
            bool debug)
        {
            if (pipeName == null)
            {
                return(new RejectedServerResponse());
            }

            if (buildPaths.TempDirectory == null)
            {
                return(new RejectedServerResponse());
            }

            var           clientDir              = buildPaths.ClientDirectory;
            var           timeoutNewProcess      = timeoutOverride ?? TimeOutMsNewProcess;
            var           timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess;
            var           clientMutexName        = MutexName.GetClientMutexName(pipeName);
            Task <Client> pipeTask = null;

            using (var clientMutex = new Mutex(initiallyOwned: true, name: clientMutexName, createdNew: out var holdsMutex))
            {
                try
                {
                    if (!holdsMutex)
                    {
                        try
                        {
                            holdsMutex = clientMutex.WaitOne(timeoutNewProcess);

                            if (!holdsMutex)
                            {
                                return(new RejectedServerResponse());
                            }
                        }
                        catch (AbandonedMutexException)
                        {
                            holdsMutex = true;
                        }
                    }

                    // Check for an already running server
                    var serverMutexName  = MutexName.GetServerMutexName(pipeName);
                    var wasServerRunning = WasServerMutexOpen(serverMutexName);
                    var timeout          = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess;

                    if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName, debug))
                    {
                        pipeTask = Client.ConnectAsync(pipeName, TimeSpan.FromMilliseconds(timeout), cancellationToken);
                    }
                }
                finally
                {
                    if (holdsMutex)
                    {
                        clientMutex.ReleaseMutex();
                    }
                }
            }

            if (pipeTask != null)
            {
                var client = await pipeTask.ConfigureAwait(false);

                if (client != null)
                {
                    var request = ServerRequest.Create(
                        buildPaths.WorkingDirectory,
                        buildPaths.TempDirectory,
                        arguments,
                        keepAlive);

                    return(await TryProcessRequest(client, request, cancellationToken).ConfigureAwait(false));
                }
            }

            return(new RejectedServerResponse());
        }