示例#1
0
        /// <summary>
        /// Returns a Task with a null BuildResponse if no server
        /// response was received.
        /// </summary>
        public static Task <BuildResponse> TryRunServerCompilation(
            RequestLanguage language,
            string workingDir,
            IList <string> arguments,
            CancellationToken cancellationToken,
            string keepAlive      = null,
            string libEnvVariable = null)
        {
            try
            {
                NamedPipeClientStream pipe;

                var  expectedServerExePath = Path.Combine(GetExpectedServerExeDir(), s_serverName);
                var  mutexName             = expectedServerExePath.Replace('\\', '/');
                bool holdsMutex;
                using (var mutex = new Mutex(initiallyOwned: true,
                                             name: mutexName,
                                             createdNew: out holdsMutex))
                {
                    try
                    {
                        if (!holdsMutex)
                        {
                            try
                            {
                                holdsMutex = mutex.WaitOne(TimeOutMsNewProcess,
                                                           exitContext: false);
                            }
                            catch (AbandonedMutexException)
                            {
                                holdsMutex = true;
                            }
                        }

                        if (holdsMutex)
                        {
                            var request = BuildRequest.Create(language, workingDir, arguments, keepAlive, libEnvVariable);
                            // Check for already running processes in case someone came in before us
                            pipe = TryExistingProcesses(expectedServerExePath, cancellationToken);
                            if (pipe != null)
                            {
                                return(TryCompile(pipe, request, cancellationToken));
                            }
                            else
                            {
                                int processId = TryCreateServerProcess(expectedServerExePath);
                                if (processId != 0 &&
                                    null != (pipe = TryConnectToProcess(processId,
                                                                        TimeOutMsNewProcess,
                                                                        cancellationToken)))
                                {
                                    // Let everyone else access our process
                                    mutex.ReleaseMutex();
                                    holdsMutex = false;

                                    return(TryCompile(pipe, request, cancellationToken));
                                }
                            }
                        }
                    }
                    finally
                    {
                        if (holdsMutex)
                        {
                            mutex.ReleaseMutex();
                        }
                    }
                }
            }
            // Swallow all unhandled exceptions from server compilation. If
            // they are show-stoppers then they will crash the in-proc
            // compilation as well
            // TODO: Put in non-fatal Watson code so we still get info
            // when things unexpectedely fail
            catch { }
            return(Task.FromResult <BuildResponse>(null));
        }
示例#2
0
 internal static BuildRequest CreateEmptyCSharpWithKeepAlive(TimeSpan keepAlive) => BuildRequest.Create(
     RequestLanguage.CSharpCompile,
     Array.Empty <string>(),
     compilerHash: BuildProtocolConstants.GetCommitHash(),
     keepAlive: keepAlive.TotalSeconds.ToString());
示例#3
0
        /// <summary>
        /// Returns a Task with a null BuildResponse if no server
        /// response was received.
        /// </summary>
        public static Task <BuildResponse> TryRunServerCompilation(
            RequestLanguage language,
            string clientDir,
            string workingDir,
            IList <string> arguments,
            CancellationToken cancellationToken,
            string keepAlive      = null,
            string libEnvVariable = null)
        {
            try
            {
                if (clientDir == null)
                {
                    return(Task.FromResult <BuildResponse>(null));
                }

                var pipeName = GetBasePipeName(clientDir);

                var  clientMutexName = $"{pipeName}.client";
                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 = $"{pipeName}.server";
                        Mutex mutexIgnore;
                        bool  wasServerRunning = Mutex.TryOpenExisting(serverMutexName, out mutexIgnore);
                        var   timeout          = wasServerRunning ? TimeOutMsExistingProcess : TimeOutMsNewProcess;

                        NamedPipeClientStream pipe = null;

                        if (wasServerRunning || TryCreateServerProcess(clientDir, pipeName))
                        {
                            pipe = TryConnectToProcess(pipeName,
                                                       timeout,
                                                       cancellationToken);
                        }

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

                            return(TryCompile(pipe, request, cancellationToken));
                        }
                    }
                    finally
                    {
                        if (holdsMutex)
                        {
                            clientMutex.ReleaseMutex();
                        }
                    }
                }
            }
            // Swallow all unhandled exceptions from server compilation. If
            // they are show-stoppers then they will crash the in-proc
            // compilation as well
            // TODO: Put in non-fatal Watson code so we still get info
            // when things unexpectedly fail
            catch { }
            return(Task.FromResult <BuildResponse>(null));
        }
示例#4
0
 internal static BuildRequest CreateEmptyCSharpWithKeepAlive(TimeSpan keepAlive, string workingDirectory, string tempDirectory = null) => BuildRequest.Create(
     RequestLanguage.CSharpCompile,
     Array.Empty <string>(),
     workingDirectory,
     tempDirectory ?? Path.GetTempPath(),
     compilerHash: BuildProtocolConstants.GetCommitHash(),
     keepAlive: keepAlive.TotalSeconds.ToString());
示例#5
0
        public async Task <WorkResponse> Work(int requestId, string cscParamsFile, CancellationToken cancellationToken)
        {
            var pipeClient =
                new NamedPipeClientStream(".", _pipe,
                                          PipeDirection.InOut, PipeOptions.None,
                                          TokenImpersonationLevel.Impersonation);

            await pipeClient.ConnectAsync(_connectTimeout, cancellationToken).ConfigureAwait(false);

            var root     = Path.GetDirectoryName(Directory.GetCurrentDirectory());
            var external = Path.Combine(Directory.GetCurrentDirectory(), "external");
            var args     = new List <string> {
                "/noconfig", $"@{Path.GetFullPath(cscParamsFile)}"
            };

            if (_pathmap != null)
            {
                args.Add($@"/pathmap:{external}={_pathmap},{root}={_pathmap}");
            }

            var buildRequest = BuildRequest.Create(RequestLanguage.CSharpCompile, args, Directory.GetCurrentDirectory(), _tempDir, _commitHash);

            await buildRequest.WriteAsync(pipeClient, cancellationToken).ConfigureAwait(false);

            var buildResponseTask = BuildResponse.ReadAsync(pipeClient, cancellationToken);
            var monitorTask       = MonitorDisconnectAsync(pipeClient, cancellationToken);

            await Task.WhenAny(buildResponseTask, monitorTask).ConfigureAwait(false);

            if (!buildResponseTask.IsCompleted)
            {
                return(new WorkResponse
                {
                    ExitCode = 1,
                    RequestId = requestId,
                    Output = "Server disconnected"
                });
            }

            if (buildResponseTask.Result is CompletedBuildResponse completedBuildResponse)
            {
                var output = completedBuildResponse.Output;

                if (_pathmap != null)
                {
                    output = output.Replace(external, _pathmap).Replace(root, _pathmap);
                }

                return(new WorkResponse
                {
                    ExitCode = completedBuildResponse.ReturnCode,
                    RequestId = requestId,
                    Output = output
                });
            }

            return(new WorkResponse
            {
                ExitCode = 1 + (int)buildResponseTask.Result.Type,
                RequestId = requestId,
                Output = $"Unknown build response type {buildResponseTask.Result.Type}"
            });
        }