/// <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)); }
internal static BuildRequest CreateEmptyCSharpWithKeepAlive(TimeSpan keepAlive) => BuildRequest.Create( RequestLanguage.CSharpCompile, Array.Empty <string>(), compilerHash: BuildProtocolConstants.GetCommitHash(), keepAlive: keepAlive.TotalSeconds.ToString());
/// <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)); }
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());
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}" }); }