internal int RunServer( string pipeName, ICompilerServerHost?compilerServerHost = null, IClientConnectionHost?clientConnectionHost = null, IDiagnosticListener?listener = null, TimeSpan?keepAlive = null, CancellationToken cancellationToken = default) { keepAlive ??= GetKeepAliveTimeout(); listener ??= new EmptyDiagnosticListener(); compilerServerHost ??= CreateCompilerServerHost(_logger); clientConnectionHost ??= CreateClientConnectionHost(pipeName, _logger); // Grab the server mutex to prevent multiple servers from starting with the same // pipename and consuming excess resources. If someone else holds the mutex // exit immediately with a non-zero exit code var mutexName = BuildServerConnection.GetServerMutexName(pipeName); bool createdNew; using (var serverMutex = BuildServerConnection.OpenOrCreateMutex(name: mutexName, createdNew: out createdNew)) { if (!createdNew) { return(CommonCompiler.Failed); } compilerServerHost.Logger.Log("Keep alive timeout is: {0} milliseconds.", keepAlive?.TotalMilliseconds ?? 0); FatalError.Handler = FailFast.OnFatalException; var dispatcher = new ServerDispatcher(compilerServerHost, clientConnectionHost, listener); dispatcher.ListenAndDispatchConnections(keepAlive, cancellationToken); return(CommonCompiler.Succeeded); } }
public void MutexStopsServerStarting() { var pipeName = Guid.NewGuid().ToString("N"); var mutexName = BuildServerConnection.GetServerMutexName(pipeName); bool holdsMutex; using (var mutex = BuildServerConnection.OpenOrCreateMutex( name: mutexName, createdNew: out holdsMutex)) { Assert.True(holdsMutex); try { var host = new Mock <IClientConnectionHost>(MockBehavior.Strict); var result = BuildServerController.CreateAndRunServer( pipeName, clientConnectionHost: host.Object, keepAlive: null); Assert.Equal(CommonCompiler.Failed, result); } finally { mutex.Dispose(); } } }
public void ConnectToServerFails() { // Create and grab the mutex for the server. This should make // the client believe that a server is active and it will try // to connect. When it fails it should fall back to in-proc // compilation. bool holdsMutex; using (var serverMutex = BuildServerConnection.OpenOrCreateMutex( name: BuildServerConnection.GetServerMutexName(_pipeName), createdNew: out holdsMutex)) { Assert.True(holdsMutex); var ranLocal = false; // Note: Connecting to a server can take up to a second to time out var client = CreateClient( compileFunc: delegate { ranLocal = true; return(0); }); var exitCode = client.RunCompilation(new[] { "/shared" }, _buildPaths, pipeName: _pipeName).ExitCode; Assert.Equal(0, exitCode); Assert.True(ranLocal); } }
public async Task ServerShutdownsDuringProcessing() { using (var readyMre = new ManualResetEvent(initialState: false)) using (var doneMre = new ManualResetEvent(initialState: false)) { var pipeName = Guid.NewGuid().ToString(); var mutexName = BuildServerConnection.GetServerMutexName(pipeName); bool created = false; bool connected = false; var thread = new Thread(() => { using (var stream = NamedPipeUtil.CreateServer(pipeName)) { var mutex = BuildServerConnection.OpenOrCreateMutex(name: mutexName, createdNew: out created); readyMre.Set(); stream.WaitForConnection(); connected = true; // Client is waiting for a response. Close the mutex now. Then close the connection // so the client gets an error. mutex.Dispose(); stream.Close(); doneMre.WaitOne(); } }); // Block until the mutex and named pipe is setup. thread.Start(); readyMre.WaitOne(); var exitCode = await RunShutdownAsync(pipeName, waitForProcess : false); // Let the fake server exit. doneMre.Set(); thread.Join(); Assert.Equal(CommonCompiler.Succeeded, exitCode); Assert.True(connected); Assert.True(created); } }
protected override int RunServerCore(string pipeName, IClientConnectionHost connectionHost, IDiagnosticListener listener, TimeSpan?keepAlive, CancellationToken cancellationToken) { // Grab the server mutex to prevent multiple servers from starting with the same // pipename and consuming excess resources. If someone else holds the mutex // exit immediately with a non-zero exit code var mutexName = BuildServerConnection.GetServerMutexName(pipeName); bool createdNew; using (var serverMutex = BuildServerConnection.OpenOrCreateMutex(name: mutexName, createdNew: out createdNew)) { if (!createdNew) { return(CommonCompiler.Failed); } return(base.RunServerCore(pipeName, connectionHost, listener, keepAlive, cancellationToken)); } }
public async Task NoServerConnection() { using (var readyMre = new ManualResetEvent(initialState: false)) using (var doneMre = new ManualResetEvent(initialState: false)) { var pipeName = Guid.NewGuid().ToString(); var mutexName = BuildServerConnection.GetServerMutexName(pipeName); bool created = false; bool connected = false; var thread = new Thread(() => { using (var mutex = BuildServerConnection.OpenOrCreateMutex(name: mutexName, createdNew: out created)) using (var stream = NamedPipeUtil.CreateServer(pipeName)) { readyMre.Set(); // Get a client connection and then immediately close it. Don't give any response. stream.WaitForConnection(); connected = true; stream.Close(); doneMre.WaitOne(); mutex.Dispose(); } }); // Block until the mutex and named pipe is setup. thread.Start(); readyMre.WaitOne(); var exitCode = await RunShutdownAsync(pipeName, waitForProcess : false); // Let the fake server exit. doneMre.Set(); thread.Join(); Assert.Equal(CommonCompiler.Failed, exitCode); Assert.True(connected); Assert.True(created); } }