public Runner(Args args = null) { args = args ?? new Args(); this.handler = Logger.Trace; this.delay = Math.Max(0, args.IdleMsDelay); this.idle = args.IdleAction; if (idle == null) { this.delay = -1; } queue = new LockedQueue <Command>(); thread = new Thread(Loop); thread.IsBackground = true; thread.Name = args.ThreadName; thread.Start(); }
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); } }