private static Task <BuildResponse> RunServerCompilationCore( RequestLanguage language, List <string> arguments, BuildPaths buildPaths, string pipeName, string keepAlive, string libEnvVariable, int?timeoutOverride, Func <string, string, bool> tryCreateServerFunc, CancellationToken cancellationToken) { var alt = new BuildPathsAlt( buildPaths.ClientDirectory, buildPaths.WorkingDirectory, buildPaths.SdkDirectory, buildPaths.TempDirectory); return(BuildServerConnection.RunServerCompilationCore( language, arguments, alt, pipeName, keepAlive, libEnvVariable, timeoutOverride, tryCreateServerFunc, cancellationToken)); }
public static Task <BuildResponse> RunServerCompilation( RequestLanguage language, string sharedCompilationId, List <string> arguments, BuildPathsAlt buildPaths, string keepAlive, string libEnvVariable, CancellationToken cancellationToken) { var pipeNameOpt = sharedCompilationId ?? GetPipeNameForPathOpt(buildPaths.ClientDirectory); return(RunServerCompilationCore( language, arguments, buildPaths, pipeNameOpt, keepAlive, libEnvVariable, timeoutOverride: null, tryCreateServerFunc: TryCreateServerCore, cancellationToken: cancellationToken)); }
internal static async Task <BuildResponse> RunServerCompilationCore( RequestLanguage language, List <string> arguments, BuildPathsAlt buildPaths, string pipeName, string keepAlive, string libEnvVariable, int?timeoutOverride, Func <string, string, bool> tryCreateServerFunc, CancellationToken cancellationToken) { if (pipeName == null) { return(new RejectedBuildResponse()); } if (buildPaths.TempDirectory == null) { return(new RejectedBuildResponse()); } // early check for the build hash. If we can't find it something is wrong; no point even trying to go to the server if (string.IsNullOrWhiteSpace(BuildProtocolConstants.GetCommitHash())) { return(new IncorrectHashBuildResponse()); } var clientDir = buildPaths.ClientDirectory; var timeoutNewProcess = timeoutOverride ?? TimeOutMsNewProcess; var timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess; Task <NamedPipeClientStream> pipeTask = null; Mutex clientMutex = null; var holdsMutex = false; try { try { var clientMutexName = GetClientMutexName(pipeName); clientMutex = new Mutex(initiallyOwned: true, name: clientMutexName, out holdsMutex); } catch { // 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 return(new RejectedBuildResponse()); } if (!holdsMutex) { try { holdsMutex = clientMutex.WaitOne(timeoutNewProcess); if (!holdsMutex) { return(new RejectedBuildResponse()); } } catch (AbandonedMutexException) { holdsMutex = true; } } // Check for an already running server var serverMutexName = GetServerMutexName(pipeName); bool wasServerRunning = WasServerMutexOpen(serverMutexName); var timeout = wasServerRunning ? timeoutExistingProcess : timeoutNewProcess; if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName)) { pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken); } } finally { if (clientMutex != null) { if (holdsMutex) { clientMutex.ReleaseMutex(); } clientMutex.Dispose(); } } if (pipeTask != null) { var pipe = await pipeTask.ConfigureAwait(false); if (pipe != null) { var request = BuildRequest.Create(language, buildPaths.WorkingDirectory, buildPaths.TempDirectory, BuildProtocolConstants.GetCommitHash(), arguments, keepAlive, libEnvVariable); return(await TryCompile(pipe, request, cancellationToken).ConfigureAwait(false)); } } return(new RejectedBuildResponse()); }