Exemple #1
0
        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());
            }

            var clientDir                         = buildPaths.ClientDirectory;
            var timeoutNewProcess                 = timeoutOverride ?? TimeOutMsNewProcess;
            var timeoutExistingProcess            = timeoutOverride ?? TimeOutMsExistingProcess;
            var clientMutexName                   = GetClientMutexName(pipeName);
            Task <NamedPipeClientStream> 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 RejectedBuildResponse());
                            }
                        }
                        catch (AbandonedMutexException)
                        {
                            holdsMutex = true;
                        }
                    }

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

                    if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName))
                    {
                        pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken);
                    }
                }
                finally
                {
                    if (holdsMutex)
                    {
                        clientMutex.ReleaseMutex();
                    }
                }
            }

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

                if (pipe != null)
                {
                    var request = BuildRequest.Create(language,
                                                      buildPaths.WorkingDirectory,
                                                      buildPaths.TempDirectory,
                                                      arguments,
                                                      keepAlive,
                                                      libEnvVariable);

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

            return(new RejectedBuildResponse());
        }
Exemple #2
0
        private static Task <BuildResponse> RunServerCompilationCore(
            RequestLanguage language,
            List <string> arguments,
            BuildPaths buildPaths,
            string pipeName,
            string keepAlive,
            string libEnvVariable,
            Func <string, string, bool> tryCreateServerFunc,
            CancellationToken cancellationToken)
        {
            var clientDir = buildPaths.ClientDirectory;

            var  clientMutexName = BuildProtocolConstants.GetClientMutexName(pipeName);
            bool holdsMutex;

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

                            if (!holdsMutex)
                            {
                                return(Task.FromResult <BuildResponse>(null));
                            }
                        }
                        catch (AbandonedMutexException)
                        {
                            holdsMutex = true;
                        }
                    }

                    // Check for an already running server
                    var   serverMutexName = BuildProtocolConstants.GetServerMutexName(pipeName);
                    Mutex mutexIgnore;
                    bool  wasServerRunning = Mutex.TryOpenExisting(serverMutexName, out mutexIgnore);
                    var   timeout          = wasServerRunning ? TimeOutMsExistingProcess : TimeOutMsNewProcess;

                    NamedPipeClientStream pipe = null;

                    if (wasServerRunning || tryCreateServerFunc(clientDir, pipeName))
                    {
                        pipe = TryConnectToServer(pipeName,
                                                  timeout,
                                                  cancellationToken);
                    }

                    if (pipe != null)
                    {
                        var request = BuildRequest.Create(language,
                                                          buildPaths.WorkingDirectory,
                                                          arguments,
                                                          keepAlive,
                                                          libEnvVariable);

                        return(TryCompile(pipe, request, cancellationToken));
                    }
                }
                finally
                {
                    if (holdsMutex)
                    {
                        clientMutex.ReleaseMutex();
                    }
                }
            }

            return(null);
        }
Exemple #3
0
        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());
        }
Exemple #4
0
        internal static async Task <BuildResponse> RunServerCompilationCoreAsync(
            Guid requestId,
            RequestLanguage language,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string?pipeName,
            string?keepAlive,
            string?libDirectory,
            int?timeoutOverride,
            CreateServerFunc createServerFunc,
            ICompilerServerLogger logger,
            CancellationToken cancellationToken
            )
        {
            if (pipeName is null)
            {
                throw new ArgumentException(nameof(pipeName));
            }

            if (buildPaths.TempDirectory == null)
            {
                throw new ArgumentException(nameof(buildPaths));
            }

            // 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 pipeTask = tryConnectToServer(
                pipeName,
                buildPaths,
                timeoutOverride,
                createServerFunc,
                logger,
                cancellationToken
                );

            if (pipeTask is null)
            {
                return(new RejectedBuildResponse("Failed to connect to server"));
            }
            else
            {
                using var pipe = await pipeTask.ConfigureAwait(false);

                if (pipe is null)
                {
                    return(new RejectedBuildResponse("Failed to connect to server"));
                }
                else
                {
                    var request = BuildRequest.Create(
                        language,
                        arguments,
                        workingDirectory: buildPaths.WorkingDirectory,
                        tempDirectory: buildPaths.TempDirectory,
                        compilerHash: BuildProtocolConstants.GetCommitHash() ?? "",
                        requestId: requestId,
                        keepAlive: keepAlive,
                        libDirectory: libDirectory
                        );

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