private async Task<BuildResponse> DoCompilationAsync(NamedPipeClientStream pipeStream, BuildRequest req, CancellationToken cancellationToken) { using (pipeStream) { try { // Start a monitor that cancels if the pipe closes on us var monitorCancellation = new CancellationTokenSource(); Task disconnectMonitor = MonitorPipeForDisconnectionAsync(pipeStream, monitorCancellation.Token); // Write the request. CompilerServerLogger.Log("Writing request"); await req.WriteAsync(pipeStream, cancellationToken).ConfigureAwait(false); // Read the response. CompilerServerLogger.Log("Reading response"); BuildResponse response = await BuildResponse.ReadAsync(pipeStream, cancellationToken).ConfigureAwait(false); // Stop monitoring pipe monitorCancellation.Cancel(throwOnFirstException: true); await disconnectMonitor.ConfigureAwait(false); Debug.Assert(response != null); CompilerServerLogger.Log("BuildResponse received; exit code={0}", response.ReturnCode); return response; } catch (PipeBrokenException e) { CompilerServerLogger.LogException(e, "Server process died; pipe broken."); return null; } catch (ObjectDisposedException e) { CompilerServerLogger.LogException(e, "Pipe stream unexpectedly disposed"); return null; } } }
/// <summary> /// Try to compile using the server. Returns null if a response from the /// server cannot be retrieved. /// </summary> private static async Task<BuildResponse> TryCompile(NamedPipeClientStream pipeStream, BuildRequest request, CancellationToken cancellationToken) { BuildResponse response; using (pipeStream) { // Write the request try { Log("Begin writing request"); await request.WriteAsync(pipeStream, cancellationToken).ConfigureAwait(false); Log("End writing request"); } catch (Exception e) { LogException(e, "Error writing build request."); return null; } // Wait for the compilation and a monitor to detect if the server disconnects var serverCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); Log("Begin reading response"); var responseTask = BuildResponse.ReadAsync(pipeStream, serverCts.Token); var monitorTask = CreateMonitorDisconnectTask(pipeStream, serverCts.Token); await Task.WhenAny(responseTask, monitorTask).ConfigureAwait(false); Log("End reading response"); if (responseTask.IsCompleted) { // await the task to log any exceptions try { response = await responseTask.ConfigureAwait(false); } catch (Exception e) { LogException(e, "Error reading response"); response = null; } } else { Log("Server disconnect"); response = null; } // Cancel whatever task is still around serverCts.Cancel(); return response; } }