public static Task <ServerResponse> RunOnServer( string pipeName, IList <string> arguments, ServerPaths serverPaths, CancellationToken cancellationToken, string keepAlive = null, bool debug = false) { if (string.IsNullOrEmpty(pipeName)) { pipeName = PipeName.ComputeDefault(serverPaths.ClientDirectory); } return(RunOnServerCore( arguments, serverPaths, pipeName: pipeName, keepAlive: keepAlive, timeoutOverride: null, tryCreateServerFunc: TryCreateServerCore, cancellationToken: cancellationToken, debug: debug)); }
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()); }