private void HandleFreeMessage(NamedPipe pipe, string msg) { string[] parts = msg.Split(':'); if (parts.Length == 2 && compilerBusy.ContainsKey(parts[1])) { string id = parts[1]; var result = ""; lock (compilerBusy) { if (compilerBusy.ContainsKey(id)) { Compiler c = compilerBusy[id]; compilerBusy.Remove(id); compilerFree[id] = c; result = CompilerServiceClient.JobFinishedMessage; } else { result = $"Error: '<free>guid', specified compiler not found with id='{id}'"; } } pipe.WriteMessage(result); } else { pipe.WriteMessage("Protocol error: expecting '<free>guid', to free the specified compiler"); } }
private void HandleLockMessage(NamedPipe pipe) { Tuple <string, Compiler> pair = GetFreeCompiler(); // send the id to the client for use in subsequent jobs. pipe.WriteMessage(pair.Item1); }
public bool Compile(CommandLineOptions options, TextWriter log) { bool finished = false; bool result = false; NamedPipe service = Connect(log); CompilerOutputStream output = new CompilerOutputStream(log); options.compilerId = id; StringWriter writer = new StringWriter(); XmlSerializer serializer = new XmlSerializer(typeof(CommandLineOptions)); serializer.Serialize(writer, options); service.WriteMessage(writer.ToString()); try { while (!finished && !service.IsClosed) { string msg = service.ReadMessage(); DebugWriteLine(msg); int i = msg.IndexOf(':'); if (i > 0) { string sev = msg.Substring(0, i); SeverityKind severity = SeverityKind.Info; Enum.TryParse <SeverityKind>(sev, out severity); msg = msg.Substring(i + 2); if (msg.StartsWith(JobFinishedMessage)) { string tail = msg.Substring(JobFinishedMessage.Length); finished = true; bool.TryParse(tail, out result); } else { output.WriteMessage(msg, severity); } } else { log.WriteLine(msg); } } } catch (Exception) { result = false; output.WriteMessage("PCompilerService is gone, did someone kill it? Perhaps the P build is happening in parallel?", SeverityKind.Error); finished = true; } return(result); }
private void OnClientConnected(object sender, NamedPipe pipe) { while (!pipe.IsClosed) { // the protocol after client connects is to send a job, we send back results until we // send the <job-finished> message, then we expect a "<job-finished>" handshake from client // or the client sends another job. string msg = pipe.ReadMessage(); if (msg == null) { // pipe is closing. } else if (msg == CompilerServiceClient.CompilerLockMessage) { HandleLockMessage(pipe); } else if (msg.StartsWith(CompilerServiceClient.CompilerFreeMessage)) { // this session is done, double handshake. HandleFreeMessage(pipe, msg); } else if (!string.IsNullOrEmpty(msg)) { try { doMoreWork = true; var output = new SerializedOutput(pipe); bool result = ProcessJob(msg, output); // now make sure client gets the JobFinishedMessage message! output.WriteMessage(CompilerServiceClient.JobFinishedMessage + result, SeverityKind.Info); output.Flush(); } catch (Exception) { // deserialization of the job failed, so ignore it. } } } pipe.Close(); }
private NamedPipe Connect(ICompilerOutput log) { var processLock = new Mutex(false, "PCompilerService"); processLock.WaitOne(); try { if (service == null) { service = new NamedPipe(ServerPipeName); if (!service.Connect()) { Process.Start(new ProcessStartInfo { FileName = typeof(CompilerServiceClient).Assembly.Location, WindowStyle = ProcessWindowStyle.Hidden }); if (!service.Connect()) { log.WriteMessage("Cannot start the CompilerService?", SeverityKind.Error); service = null; return(null); } else { // now lock a Compiler object until we re disposed so we can get better // performance by sharing the same Compiler across compile, link and test. service.WriteMessage(CompilerLockMessage); id = service.ReadMessage(); } } } } finally { processLock.ReleaseMutex(); } return(service); }
private void ClientThread(PipeStream pipe) { try { NamedPipe client = new NamedPipe(this.pipeName, pipe); if (ClientConnected != null) { ClientConnected(this, client); } } catch (Exception e) { IOException io = e as IOException; if (io != null) { uint hr = (uint)io.HResult; if (hr == 0x800700e7) { // multiple instances, all pipe instances are busy, so go to deep sleep // waiting for other instance to go away. Thread.Sleep(1000); } else if (hr == 0x80131620) { closed = true; } else if (hr == 0x8007006d) { // the pipe has ended, so client went away, we can go back to listening. DebugWriteLine("The pipe has ended: " + this.pipeName); } } else { // on standby, waiting for test to fire up... Thread.Sleep(100); } } }
void Run() { System.Diagnostics.Contracts.Contract.ContractFailed += OnContractFailed; Console.WriteLine("Starting compiler service, listening to named pipe"); // start the server. pipe = new NamedPipe(ServerPipeName, true); pipe.MessageArrived += OnMessageArrived; if (!pipe.Connect()) { Console.WriteLine("Hmmm, is it already running?"); return; } doMoreWork = true; // stay awake waiting for work while (doMoreWork || busyCount > 0) { doMoreWork = false; Thread.Sleep(60 * 60 * 1000); // timeout after 1 hour } Console.WriteLine("Compiler service terminating due to lack of work"); }
private void Run() { Contract.ContractFailed += OnContractFailed; Console.WriteLine("Starting compiler service, listening to named pipe"); // start the server. var pipe = new NamedPipe(ServerPipeName); pipe.ClientConnected += OnClientConnected; // we should never use more than Environment.ProcessorCount, the * 2 provides some slop for pipe cleanup from previous jobs. pipe.StartServer(Environment.ProcessorCount * 2); doMoreWork = true; // stay awake waiting for work while (doMoreWork || busyCount > 0) { doMoreWork = false; Thread.Sleep(60 * 60 * 1000); // timeout after 1 hour } Console.WriteLine("Compiler service terminating due to lack of work"); }
private void ProcessJob(string msg) { Interlocked.Increment(ref busyCount); NamedPipe clientPipe = null; try { XmlSerializer s = new XmlSerializer(typeof(CommandLineOptions)); CommandLineOptions options = (CommandLineOptions)s.Deserialize(new StringReader(msg)); if (!string.IsNullOrEmpty(options.pipeName)) { clientPipe = new NamedPipe(options.pipeName, false); clientPipe.Connect(); } var output = new SerializedOutput(clientPipe); bool retry = true; bool masterCreated = false; while (retry) { retry = false; // We have to serialize compiler jobs, the Compiler is not threadsafe. lock (compilerlock) { if (master == null) { masterCreated = true; output.WriteMessage("Generating P compiler", SeverityKind.Info); master = new Compiler(false); } // share the compiled P program across compiler instances. Compiler compiler = master; // new Compiler(master); bool result = false; try { result = compiler.Compile(options.inputFileName, new SerializedOutput(clientPipe), options); } catch (Exception ex) { if (!masterCreated) { // sometimes the compiler gets out of whack, and rebuilding it solves the problem. retry = true; master = null; } else { output.WriteMessage("Compile failed: " + ex.ToString(), SeverityKind.Error); } } if (!retry) { compiler.Log.WriteMessage("finished:" + result, SeverityKind.Info); } } } Thread.Sleep(1000); } finally { if (clientPipe != null) { clientPipe.Close(); } Interlocked.Decrement(ref busyCount); } }
public SerializedOutput(NamedPipe pipe) { this.pipe = pipe; }
public bool Compile(CommandLineOptions options, TextWriter log) { service = new NamedPipe(ServerPipeName, false); Mutex processLock = new Mutex(false, "PCompilerService"); processLock.WaitOne(); try { if (!service.Connect()) { ProcessStartInfo info = new ProcessStartInfo(); info.FileName = typeof(CompilerServiceClient).Assembly.Location; info.WindowStyle = ProcessWindowStyle.Hidden; Process p = Process.Start(info); if (!service.Connect()) { log.WriteLine("Cannot start the CompilerService?"); return(false); } } } finally { processLock.ReleaseMutex(); } Guid clientPipe = Guid.NewGuid(); string clientPipeName = clientPipe.ToString() + "-CompilerServiceClient"; client = new NamedPipe(clientPipeName, true); if (!client.Connect()) { log.WriteLine("weird, the process that launched this job is gone?"); return(false); } AutoResetEvent msgEvent = new AutoResetEvent(false); bool finished = false; bool result = false; CompilerOutputStream output = new CompilerOutputStream(log); client.MessageArrived += (s2, e2) => { string msg = e2.Message; int i = msg.IndexOf(':'); if (i > 0) { string sev = msg.Substring(0, i); msg = msg.Substring(i + 2); if (msg.StartsWith("finished:")) { i = msg.IndexOf(':'); string tail = msg.Substring(i + 1); finished = true; bool.TryParse(tail, out result); msgEvent.Set(); } else { SeverityKind severity = SeverityKind.Info; Enum.TryParse <SeverityKind>(sev, out severity); output.WriteMessage(msg, severity); } } else { log.WriteLine(e2.Message); } }; options.pipeName = clientPipeName; StringWriter writer = new StringWriter(); XmlSerializer serializer = new XmlSerializer(typeof(CommandLineOptions)); serializer.Serialize(writer, options); service.WriteMessage(writer.ToString()); while (!finished) { msgEvent.WaitOne(1000); if (client.IsClosed) { result = false; output.WriteMessage("PCompilerService is gone, did someone kill it? Perhaps the P build is happening in parallel?", SeverityKind.Error); finished = true; } } service.Close(); client.Close(); return(result); }