Esempio n. 1
0
        public static Task <BuildResponse> RunServerCompilationAsync(
            Guid requestId,
            RequestLanguage language,
            string?sharedCompilationId,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string?keepAlive,
            string?libEnvVariable,
            ICompilerServerLogger logger,
            CancellationToken cancellationToken)
        {
            var pipeNameOpt = sharedCompilationId ?? GetPipeNameForPath(buildPaths.ClientDirectory);

            return(RunServerCompilationCoreAsync(
                       requestId,
                       language,
                       arguments,
                       buildPaths,
                       pipeNameOpt,
                       keepAlive,
                       libEnvVariable,
                       timeoutOverride: null,
                       createServerFunc: TryCreateServerCore,
                       logger: logger,
                       cancellationToken: cancellationToken));
        }
Esempio n. 2
0
        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));
        }
Esempio n. 3
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));
                }
            }
Esempio n. 4
0
        protected override int RunLocalCompilation(string[] arguments, BuildPathsAlt buildPaths, TextWriter textWriter)
        {
            return(_compileFunc(arguments, buildPaths, textWriter,
#if DESKTOP
                                new DesktopAnalyzerAssemblyLoader()
#else
                                ReflCoreClrAnalyzerAssemblyLoader.ctor()
#endif
                                ));
        }
Esempio n. 5
0
        internal static async Task <BuildResponse> RunServerCompilationCore(
            RequestLanguage language,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string pipeName,
            string keepAlive,
            string libEnvVariable,
            int?timeoutOverride,
            CreateServerFunc createServerFunc,
            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 pipeTask = tryConnectToServer(pipeName, buildPaths, timeoutOverride, createServerFunc, cancellationToken);

            if (pipeTask is null)
            {
                return(new RejectedBuildResponse());
            }
            else
            {
                var pipe = await pipeTask.ConfigureAwait(false);

                if (pipe is null)
                {
                    return(new RejectedBuildResponse());
                }
                else
                {
                    var request = BuildRequest.Create(language,
                                                      buildPaths.WorkingDirectory,
                                                      buildPaths.TempDirectory,
                                                      BuildProtocolConstants.GetCommitHash(),
                                                      arguments,
                                                      keepAlive,
                                                      libEnvVariable);

                    return(await TryCompile(pipe, request, cancellationToken).ConfigureAwait(false));
                }
            }
Esempio n. 6
0
        internal static int Run(IEnumerable <string> arguments, IEnumerable <string> extraArguments, RequestLanguage language, CompileFunc compileFunc, IAnalyzerAssemblyLoader analyzerAssemblyLoader)
        {
            var    client            = new DesktopBuildClient(language, compileFunc, analyzerAssemblyLoader);
            var    clientDir         = AppDomain.CurrentDomain.BaseDirectory;
            var    sdkDir            = RuntimeEnvironment.GetRuntimeDirectory();
            var    workingDir        = Directory.GetCurrentDirectory();
            string tempPath          = Path.GetTempPath();
            var    buildPaths        = new BuildPathsAlt(clientDir: clientDir, workingDir: workingDir, sdkDir: sdkDir, tempDir: tempPath);
            var    originalArguments = BuildClient.GetCommandLineArgs(arguments).Concat(extraArguments).ToArray();

            return(client.RunCompilation(originalArguments, buildPaths).ExitCode);
        }
Esempio n. 7
0
        internal static int Run(IEnumerable <string> arguments, RequestLanguage language, CompileFunc compileFunc)
        {
            // Should be using BuildClient.GetCommandLineArgs(arguments) here.  But the native invoke
            // ends up giving us both CoreRun and the exe file.  Need to find a good way to remove the host
            // as well as the EXE argument.
            // https://github.com/dotnet/roslyn/issues/6677
            var client     = new CoreClrBuildClient(language, compileFunc);
            var clientDir  = AppContext.BaseDirectory;
            var workingDir = Directory.GetCurrentDirectory();
            var buildPaths = new BuildPathsAlt(clientDir: clientDir, workingDir: workingDir, sdkDir: null, tempDir: null);

            return(client.RunCompilation(arguments, buildPaths).ExitCode);
        }
Esempio n. 8
0
        public static Task <BuildResponse> RunServerCompilation(
            RequestLanguage language,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string keepAlive,
            string libEnvVariable,
            CancellationToken cancellationToken)
        {
            var pipeNameOpt = GetPipeNameForPathOpt(buildPaths.ClientDirectory);

            return(RunServerCompilationCore(
                       language,
                       arguments,
                       buildPaths,
                       pipeNameOpt,
                       keepAlive,
                       libEnvVariable,
                       timeoutOverride: null,
                       tryCreateServerFunc: TryCreateServerCore,
                       cancellationToken: cancellationToken));
        }
Esempio n. 9
0
        public static Task<BuildResponse> RunServerCompilation(
            RequestLanguage language,
            List<string> arguments,
            BuildPathsAlt buildPaths,
            string keepAlive,
            string libEnvVariable,
            CancellationToken cancellationToken)
        {
            var pipeNameOpt = GetPipeNameForPathOpt(buildPaths.ClientDirectory);

            return RunServerCompilationCore(
                language,
                arguments,
                buildPaths,
                pipeNameOpt,
                keepAlive,
                libEnvVariable,
                timeoutOverride: null,
                tryCreateServerFunc: TryCreateServerCore,
                cancellationToken: cancellationToken);
        }
Esempio n. 10
0
        internal static 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 Task.FromResult<BuildResponse>(new RejectedBuildResponse());
            }

            if (buildPaths.TempDirectory == null)
            {
                return Task.FromResult<BuildResponse>(new RejectedBuildResponse());
            }

            var clientDir = buildPaths.ClientDirectory;
            var timeoutNewProcess = timeoutOverride ?? TimeOutMsNewProcess;
            var timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess;
            var clientMutexName = GetClientMutexName(pipeName);
            bool holdsMutex;
            using (var clientMutex = new Mutex(initiallyOwned: true,
                                               name: clientMutexName,
                                               createdNew: out holdsMutex))
            {
                try
                {
                    if (!holdsMutex)
                    {
                        try
                        {
                            holdsMutex = clientMutex.WaitOne(timeoutNewProcess);

                            if (!holdsMutex)
                            {
                                return Task.FromResult<BuildResponse>(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;

                    NamedPipeClientStream pipe = null;

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

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

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

            return Task.FromResult<BuildResponse>(new RejectedBuildResponse());
        }
        /// <summary>
        /// Run a compilation through the compiler server and print the output
        /// to the console. If the compiler server fails, run the fallback
        /// compiler.
        /// </summary>
        internal RunCompilationResult RunCompilation(IEnumerable <string> originalArguments, BuildPathsAlt buildPaths, TextWriter textWriter = null)
        {
            textWriter = textWriter ?? Console.Out;

            var args = originalArguments.Select(arg => arg.Trim()).ToArray();

            bool          hasShared;
            string        keepAlive;
            string        errorMessage;
            string        sessionKey;
            List <string> parsedArgs;

            if (!ReflCommandLineParser.TryParseClientArgs(
                    args,
                    out parsedArgs,
                    out hasShared,
                    out keepAlive,
                    out sessionKey,
                    out errorMessage))
            {
                Console.Out.WriteLine(errorMessage);
                return(RunCompilationResult.Failed);
            }

            // It's okay, and expected, for the server compilation to fail.  In that case just fall
            // back to normal compilation.
            var exitCode = RunLocalCompilation(parsedArgs.ToArray(), buildPaths, textWriter);

            return(new RunCompilationResult(exitCode));
        }
 protected abstract string GetSessionKey(BuildPathsAlt buildPaths);
Esempio n. 13
0
 protected override int RunLocalCompilation(string[] arguments, BuildPathsAlt buildPaths, TextWriter textWriter)
 {
     return(_compileFunc(arguments, buildPaths, textWriter, _analyzerAssemblyLoader));
 }
Esempio n. 14
0
        internal static async Task <BuildResponse> RunServerCompilationCore(
            RequestLanguage language,
            List <string> arguments,
            BuildPathsAlt buildPaths,
            string pipeName,
            string keepAlive,
            string libEnvVariable,
            int?timeoutOverride,
            CreateServerFunc createServerFunc,
            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;
            IServerMutex clientMutex              = null;

            try
            {
                var holdsMutex = false;
                try
                {
                    var clientMutexName = GetClientMutexName(pipeName);
                    clientMutex = OpenOrCreateMutex(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.TryLock(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 || createServerFunc(clientDir, pipeName))
                {
                    pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken);
                }
            }
            finally
            {
                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());
        }
Esempio n. 15
0
        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);
        }
Esempio n. 16
0
 protected override string GetSessionKey(BuildPathsAlt buildPaths)
 {
     return(string.Empty);
 }
Esempio n. 17
0
        internal static 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(Task.FromResult <BuildResponse>(new RejectedBuildResponse()));
            }

            if (buildPaths.TempDirectory == null)
            {
                return(Task.FromResult <BuildResponse>(new RejectedBuildResponse()));
            }

            var  clientDir              = buildPaths.ClientDirectory;
            var  timeoutNewProcess      = timeoutOverride ?? TimeOutMsNewProcess;
            var  timeoutExistingProcess = timeoutOverride ?? TimeOutMsExistingProcess;
            var  clientMutexName        = GetClientMutexName(pipeName);
            bool holdsMutex;

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

                            if (!holdsMutex)
                            {
                                return(Task.FromResult <BuildResponse>(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;

                    NamedPipeClientStream pipe = null;

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

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

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

            return(Task.FromResult <BuildResponse>(new RejectedBuildResponse()));
        }
Esempio n. 18
0
        protected override int ExecuteTool(string pathToTool, string responseFileCommands, string commandLineCommands)
        {
            if (ProvideCommandLineArgs)
            {
                CommandLineArgs = GetArguments(commandLineCommands, responseFileCommands)
                    .Select(arg => new TaskItem(arg)).ToArray();
            }

            if (SkipCompilerExecution)
            {
                return 0;
            }

            if (!UseSharedCompilation ||
                !string.IsNullOrEmpty(ToolPath) ||
                !BuildServerConnection.IsCompilerServerSupported)
            {
                return base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
            }

            using (_sharedCompileCts = new CancellationTokenSource())
            {
                try
                {
                    CompilerServerLogger.Log($"CommandLine = '{commandLineCommands}'");
                    CompilerServerLogger.Log($"BuildResponseFile = '{responseFileCommands}'");

                    var clientDir = Path.GetDirectoryName(pathToTool);

                    // Note: we can't change the "tool path" printed to the console when we run
                    // the Csc/Vbc task since MSBuild logs it for us before we get here. Instead,
                    // we'll just print our own message that contains the real client location
                    Log.LogMessage(ErrorString.UsingSharedCompilation, clientDir);

                    var workingDir = CurrentDirectoryToUse();
                    var buildPaths = new BuildPathsAlt(
                        clientDir: clientDir,
                        // MSBuild doesn't need the .NET SDK directory
                        sdkDir: null,
                        workingDir: workingDir,
                        tempDir: BuildServerConnection.GetTempPath(workingDir));

                    var responseTask = BuildServerConnection.RunServerCompilation(
                        Language,
                        GetArguments(commandLineCommands, responseFileCommands).ToList(),
                        buildPaths,
                        keepAlive: null,
                        libEnvVariable: LibDirectoryToUse(),
                        cancellationToken: _sharedCompileCts.Token);

                    responseTask.Wait(_sharedCompileCts.Token);

                    var response = responseTask.Result;
                    if (response != null)
                    {
                        ExitCode = HandleResponse(response, pathToTool, responseFileCommands, commandLineCommands);
                    }
                    else
                    {
                        Log.LogMessage(ErrorString.SharedCompilationFallback, pathToTool);

                        ExitCode = base.ExecuteTool(pathToTool, responseFileCommands, commandLineCommands);
                    }
                }
                catch (OperationCanceledException)
                {
                    ExitCode = 0;
                }
                catch (Exception e)
                {
                    Log.LogErrorWithCodeFromResources("Compiler_UnexpectedException");
                    LogErrorOutput(e.ToString());
                    ExitCode = -1;
                }
            }

            return ExitCode;
        }
Esempio n. 19
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;
            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,
                                                      arguments,
                                                      keepAlive,
                                                      libEnvVariable);

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

            return(new RejectedBuildResponse());
        }
        public Task <RunCompilationResult> RunCompilationAsync(IEnumerable <string> originalArguments, BuildPathsAlt buildPaths, TextWriter textWriter = null)
        {
            var         tcs    = new TaskCompletionSource <RunCompilationResult>();
            ThreadStart action = () =>
            {
                try
                {
                    var result = RunCompilation(originalArguments, buildPaths, textWriter);
                    tcs.SetResult(result);
                }
                catch (Exception ex)
                {
                    tcs.SetException(ex);
                }
            };

            var thread = new Thread(action);

            thread.Start();

            return(tcs.Task);
        }
Esempio n. 21
0
            // This code uses a Mutex.WaitOne / ReleaseMutex pairing. Both of these calls must occur on the same thread
            // or an exception will be thrown. This code lives in a separate non-async function to help ensure this
            // invariant doesn't get invalidated in the future by an `await` being inserted.
            static Task <NamedPipeClientStream> tryConnectToServer(
                string pipeName,
                BuildPathsAlt buildPaths,
                int?timeoutOverride,
                CreateServerFunc createServerFunc,
                CancellationToken cancellationToken)
            {
                var originalThreadId                  = Thread.CurrentThread.ManagedThreadId;
                var clientDir                         = buildPaths.ClientDirectory;
                var timeoutNewProcess                 = timeoutOverride ?? TimeOutMsNewProcess;
                var timeoutExistingProcess            = timeoutOverride ?? TimeOutMsExistingProcess;
                Task <NamedPipeClientStream> pipeTask = null;
                IServerMutex clientMutex              = null;

                try
                {
                    var holdsMutex = false;
                    try
                    {
                        var clientMutexName = GetClientMutexName(pipeName);
                        clientMutex = OpenOrCreateMutex(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(null);
                    }

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

                            if (!holdsMutex)
                            {
                                return(null);
                            }
                        }
                        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 || createServerFunc(clientDir, pipeName))
                    {
                        pipeTask = TryConnectToServerAsync(pipeName, timeout, cancellationToken);
                    }

                    return(pipeTask);
                }
                finally
                {
                    try
                    {
                        clientMutex?.Dispose();
                    }
                    catch (ApplicationException e)
                    {
                        var releaseThreadId = Thread.CurrentThread.ManagedThreadId;
                        var message         = $"ReleaseMutex failed. WaitOne Id: {originalThreadId} Release Id: {releaseThreadId}";
                        throw new Exception(message, e);
                    }
                }
            }
 protected abstract int RunLocalCompilation(string[] arguments, BuildPathsAlt buildPaths, TextWriter textWriter);