From 29691015c75daf955414aef07124d385e3f36404 Mon Sep 17 00:00:00 2001 From: Felix Mulder Date: Mon, 3 Apr 2017 17:28:21 +0200 Subject: Add initial RunnerOrchestration interface --- .../tools/dotc/vulpix/RunnerOrchestration.scala | 81 ++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 compiler/test/dotty/tools/dotc/vulpix/RunnerOrchestration.scala (limited to 'compiler/test/dotty/tools/dotc/vulpix/RunnerOrchestration.scala') diff --git a/compiler/test/dotty/tools/dotc/vulpix/RunnerOrchestration.scala b/compiler/test/dotty/tools/dotc/vulpix/RunnerOrchestration.scala new file mode 100644 index 000000000..64eed1035 --- /dev/null +++ b/compiler/test/dotty/tools/dotc/vulpix/RunnerOrchestration.scala @@ -0,0 +1,81 @@ +package dotty +package tools +package dotc +package vulpix + +import java.io.{ + File => JFile, + InputStream, ObjectInputStream, + OutputStream, ObjectOutputStream +} + +import scala.concurrent.duration.Duration +import scala.collection.mutable + +trait RunnerOrchestration { + + /** The maximum amount of active runners, which contain a child JVM */ + val numberOfSlaves: Int + + /** The maximum duration the child process is allowed to consume before + * getting destroyed + */ + val maxDuration: Duration + + /** Destroy and respawn process after each test */ + val safeMode: Boolean + + /** Running a `Test` class's main method from the specified `dir` */ + def runMain(dir: JFile): Status = monitor.runMain(dir) + + private[this] val monitor = new RunnerMonitor + + private class RunnerMonitor { + + def runMain(dir: JFile): Status = withRunner(_.runMain(dir)) + + private class Runner(private var process: Process) { + def kill(): Unit = ??? + def runMain(dir: JFile): Status = ??? + } + + private def createProcess: Process = ??? + + private[this] val allRunners = + List.fill(numberOfSlaves)(new Runner(createProcess)) + + private[this] val freeRunners = mutable.Queue(allRunners: _*) + private[this] val busyRunners = mutable.Set.empty[Runner] + + private def getRunner(): Runner = synchronized { + while (freeRunners.isEmpty) wait() + + val runner = freeRunners.dequeue() + busyRunners += runner + + notify() + runner + } + + private def freeRunner(runner: Runner): Unit = synchronized { + freeRunners.enqueue(runner) + busyRunners -= runner + notify() + } + + private def withRunner[T](op: Runner => T): T = { + val runner = getRunner() + val result = op(runner) + freeRunner(runner) + result + } + + private def killAll(): Unit = allRunners.foreach(_.kill()) + + // On shutdown, we need to kill all runners: + sys.addShutdownHook(killAll()) + // If for some reason the test runner (i.e. sbt) doesn't kill the VM, we + // need to clean up ourselves. + SummaryReport.addCleanup(killAll) + } +} -- cgit v1.2.3