private void ReadLoop() { var line = reader.ReadLine(); while (line != null) { Logger.Trace("< {0}", line); queue.Push(line); line = reader.ReadLine(); } }
private void Run(Command command) { //Ideally no push after disposing to avoid holding references to objects //that wont be executed. The trick is to discard runner references right //after disposing to make all available to GC. queue.Push(command); }
public static void Interactive(IStream io, Args args) { var thread = Thread.CurrentThread.Name; var reader = new Runner(new Runner.Args() { ThreadName = string.Format("{0}_R", thread) }); var erroer = new Runner(new Runner.Args() { ThreadName = string.Format("{0}_W", thread) }); using (reader) using (erroer) { var process = new DaemonProcess(args); //eof below must close process immediatelly //to ensure exited message happens after real exit using (process) { io.WriteLine("Process {0} has started", process.Id); var queue = new LockedQueue <bool>(); reader.Run(() => { var line = process.ReadLine(); while (line != null) { Logger.Trace("<o:{0} {1}", process.Id, line); io.WriteLine(line); line = process.ReadLine(); } Logger.Trace("<o:{0} EOF", process.Id); }); reader.Run(() => queue.Push(true)); erroer.Run(() => { var line = process.ReadError(); while (line != null) { Logger.Trace("<e:{0} {1}", process.Id, line); line = process.ReadError(); } Logger.Trace("<e:{0} EOF", process.Id); }); erroer.Run(() => queue.Push(true)); while (true) { //non blocking readline needed to notice reader exit var line = io.TryReadLine(out var eof); if (eof) { Logger.Trace("EOF input > process"); } if (eof) { break; } if (line != null) { Logger.Trace("i:{0}> {1}", process.Id, line); process.WriteLine(line); } if (queue.Pop(1, false)) { break; } } } //previous loop may swallow exit! by feeding it to process //unit test should wait for syncing message below before exit! io.WriteLine("Process {0} has exited", process.Id); } }