Example #1
0
        public static Task <GenerationResponse> RunServerGeneration(
            string sharedCompilationId,
            List <string> arguments,
            GenerationsPathsInfo buildPaths,
            string keepAlive,
            CancellationToken cancellationToken)
        {
            var pipeNameOpt = sharedCompilationId ?? GetPipeNameForPathOpt(buildPaths.ClientDirectory);

            return(RunServerGenerationCore(
                       arguments,
                       buildPaths,
                       pipeNameOpt,
                       keepAlive,
                       timeoutOverride: null,
                       tryCreateServerFunc: TryCreateServerCore,
                       cancellationToken: cancellationToken));
        }
Example #2
0
        internal static async Task <GenerationResponse> RunServerGenerationCore(
            List <string> arguments,
            GenerationsPathsInfo buildPaths,
            string pipeName,
            string keepAlive,
            int?timeoutOverride,
            Func <string, string, bool, bool> tryCreateServerFunc,
            CancellationToken cancellationToken)
        {
            if (pipeName == null)
            {
                return(new RejectedGenerationResponse());
            }

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

            // 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(GenerationProtocolConstants.GetCommitHash()))
            {
                return(new IncorrectHashGenerationResponse());
            }

            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 RejectedGenerationResponse());
                }

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

                        if (!holdsMutex)
                        {
                            return(new RejectedGenerationResponse());
                        }
                    }
                    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, false))
                {
                    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 = GenerationRequest.Create(buildPaths.WorkingDirectory,
                                                           buildPaths.TempDirectory,
                                                           GenerationProtocolConstants.GetCommitHash(),
                                                           arguments,
                                                           keepAlive);

                    return(await TryGeneration(pipe, request, cancellationToken).ConfigureAwait(false));
                }
            }

            return(new RejectedGenerationResponse());
        }
Example #3
0
 internal bool TryShutdownGenerationServer(string pipeName, GenerationsPathsInfo buildPaths)
 {
     return(TryCreateServerCore(buildPaths.ClientDirectory, pipeName, isShutdown: true));
 }