private String ReadLineAsync() { String line = null; AsyncThread thread = AsyncThread.Borrow(() => { line = program.StandardOutput.ReadLine(); outputDone.Set(); }); WakeUp(); timer.Start(); while (timer.ElapsedMilliseconds <= Settings.TimeLimit) { bool success = outputDone.WaitOne((int)(Settings.TimeLimit + Settings.ReadTimeMargin - timer.ElapsedMilliseconds)); if (success) { break; // success may also be true when the program crashes, see Start() } } timer.Stop(); Sleep(); outputDone.Reset(); AsyncThread.Return(thread, line != null); bool potentialCrash = line == null ? true : line.Length == 0; if (potentialCrash && program.HasExited) { throw new Crash(); } if (timer.ElapsedMilliseconds > Settings.TimeLimit) { throw new Timeout(); } return(line); }
public static void Return(AsyncThread thread, bool terminatedGracefully) { if (!terminatedGracefully) { thread.Reset(); } else { thread.function = null; thread.wait.Reset(); // TODO: this somehow fixes a bug... } lock (mainLock) { queue.Add(thread); } }
public static AsyncThread Borrow(AsyncFunction function) { AsyncThread thread = null; lock (mainLock) { if (queue.Count > 0) { thread = queue[0]; queue.RemoveAt(0); } } if (thread == null) { thread = new AsyncThread(); } thread.function = function; thread.wait.Set(); return(thread); }
public static void Stop() { if (!isRunning) { return; } lock (scheduleLock) if (schedule.Count != 0) { throw new Exception("Schedule must be empty before attempting to stop."); } foreach (Thread t in threads) { t.Abort(); } matchesAvailable.Reset(); AsyncThread.KillAll(); matchesScheduled = matchesCompleted = 0; scheduleDone.Set(); isRunning = false; }
public void Quit() { try { Debug.WriteLine(match.Prefix + "Player " + player.name + " used " + timer.ElapsedMilliseconds + " ms."); if (!program.HasExited) { SendLine("Quit"); WakeUp(); if (Settings.KillPrograms) { Thread.Sleep(Settings.MillisecondsBeforeKill); Terminate(); } program.WaitForExit(); } } finally { AsyncThread.Return(errorThread, program.HasExited); } }
public void Start() { Stopwatch startTime = Stopwatch.StartNew(); ProcessStartInfo startInfo = new ProcessStartInfo(cmd) { Arguments = args, UseShellExecute = false, // needs to be false to enable stream redirecting RedirectStandardInput = true, RedirectStandardOutput = true, RedirectStandardError = true }; program = Process.Start(startInfo); timer = new Stopwatch(); Sleep(); program.Exited += new EventHandler((object src, EventArgs args) => { outputDone.Set(); }); // ensure the main match thread will wake up if the program crashes. errorThread = AsyncThread.Borrow(ReadError); startTime.Stop(); Debug.WriteLine(match.Prefix + "Started player " + player.name + " in " + startTime.ElapsedMilliseconds + " ms. Used command: " + cmd + " " + args); }