private Task CompileNamedTypeAsTask(NamedTypeSymbol symbol) { return(Task.Run(() => { try { CompileNamedType(symbol); return (object)null; } catch (Exception e) if (CompilerFatalError.Report(e)) { throw ExceptionUtilities.Unreachable; } }, this.cancellationToken)); }
/// <summary> /// Checks to see if memory is available, and if it is creates a new /// Connection object, awaits the completion of the connection, then /// runs <see cref="ConnectionCompleted"/> for cleanup. /// </summary> private async Task DispatchConnection(NamedPipeServerStream pipeStream) { try { // There is always a race between timeout and connections because // there is no way to cancel listening on the pipe without // closing the pipe. We immediately increment the connection // semaphore while processing connections in order to narrow // the race window as much as possible. Interlocked.Increment(ref this.activeConnectionCount); if (Environment.Is64BitProcess || MemoryHelper.IsMemoryAvailable()) { CompilerServerLogger.Log("Memory available - accepting connection"); Connection connection = new Connection(pipeStream, handler, this.keepAliveTimer); try { await connection.ServeConnection().ConfigureAwait(false); } catch (ObjectDisposedException e) { // If the client closes the pipe while we're reading or writing // we'll get an object disposed exception on the pipe // Log the failure and continue CompilerServerLogger.Log( "Client pipe closed: received exception " + e.Message); } } else { CompilerServerLogger.Log("Memory tight - rejecting connection."); // As long as we haven't written a response, the client has not // committed to this server instance and can look elsewhere. pipeStream.Close(); // We didn't create a connection -- decrement the semaphore Interlocked.Decrement(ref this.activeConnectionCount); } ConnectionCompleted(); } catch (Exception e) if (CompilerFatalError.Report(e)) { throw ExceptionUtilities.Unreachable; } }
/// <summary> /// Checks to see if memory is available, and if it is creates a new /// Connection object, awaits the completion of the connection, then /// runs <see cref="ConnectionCompleted"/> for cleanup. /// </summary> private async Task DispatchConnection(NamedPipeServerStream pipeStream) { try { // There is always a race between timeout and connections because // there is no way to cancel listening on the pipe without // closing the pipe. We immediately increment the connection // semaphore while processing connections in order to narrow // the race window as much as possible. Interlocked.Increment(ref this.activeConnectionCount); if (Environment.Is64BitProcess || MemoryHelper.IsMemoryAvailable()) { CompilerServerLogger.Log("Memory available - accepting connection"); Connection connection = new Connection(pipeStream, handler); await connection.ServeConnection().ConfigureAwait(false); // The connection should be finished ConnectionCompleted(connection); } else { CompilerServerLogger.Log("Memory tight - rejecting connection."); // As long as we haven't written a response, the client has not // committed to this server instance and can look elsewhere. pipeStream.Close(); // We didn't create a connection -- decrement the semaphore Interlocked.Decrement(ref this.activeConnectionCount); // Start a terminate server timer if there are no active // connections StartTimeoutTimerIfNecessary(); } } catch (Exception e) if (CompilerFatalError.Report(e)) { throw ExceptionUtilities.Unreachable; } }
public async Task ServeConnection() { BuildRequest request; try { Log("Begin reading request"); request = await BuildRequest.ReadAsync(pipeStream, cancellationTokenSource.Token).ConfigureAwait(false); Log("End reading request"); } catch (IOException e) { LogException(e, "Reading request from named pipe."); FinishConnection(CompletionReason.IOFailure); return; } catch (OperationCanceledException e) { LogException(e, "Reading request from named pipe."); FinishConnection(CompletionReason.Cancelled); return; } if (!ClientAndOurIdentitiesMatch(pipeStream)) { Log("Client identity doesn't match."); FinishConnection(CompletionReason.SecurityViolation); return; } CheckForNewKeepAlive(request); // Start a monitor that cancels if the pipe closes on us var _ = MonitorPipeForDisconnection().ConfigureAwait(false); // Do the compilation Log("Begin compilation"); BuildResponse response = await Task.Run(() => { try { return(handler.HandleRequest(request, cancellationTokenSource.Token)); } catch (Exception e) if (CompilerFatalError.ReportUnlessCanceled(e)) { throw ExceptionUtilities.Unreachable; } }).ConfigureAwait(false); Log("End compilation"); try { Log("Begin writing response"); await response.WriteAsync(pipeStream, cancellationTokenSource.Token).ConfigureAwait(false); Log("End writing response"); } catch (IOException e) { LogException(e, "Writing response to named pipe."); FinishConnection(CompletionReason.IOFailure); return; } catch (OperationCanceledException e) { LogException(e, "Writing response to named pipe."); FinishConnection(CompletionReason.Cancelled); return; } Log("Completed writing response to named pipe."); FinishConnection(CompletionReason.Success); }