Skip to content

Commit a61cc0d

Browse files
committed
Complete subprocess communication protocol
1 parent 66e73a1 commit a61cc0d

File tree

3 files changed

+64
-22
lines changed

3 files changed

+64
-22
lines changed

compiler/test/dotty/tools/dotc/vulpix/RunnerOrchestration.scala

Lines changed: 44 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ import scala.concurrent.{ Await, Future }
1313
import scala.concurrent.ExecutionContext.Implicits.global
1414
import scala.collection.mutable
1515

16+
import vulpix.Statuses._
17+
1618
trait RunnerOrchestration {
1719

1820
/** The maximum amount of active runners, which contain a child JVM */
@@ -36,14 +38,30 @@ trait RunnerOrchestration {
3638
def runMain(dir: JFile): Status = withRunner(_.runMain(dir))
3739

3840
private class Runner(private var process: Process) {
39-
private[this] val ois = new ObjectInputStream(process.getInputStream)
40-
private[this] val oos = new ObjectOutputStream(process.getOutputStream)
41-
41+
private[this] var ois: ObjectInputStream = _
42+
private[this] var oos: ObjectOutputStream = _
43+
44+
/** Checks if `process` is still alive
45+
*
46+
* When `process.exitValue()` is called on an active process the caught
47+
* exception is thrown. As such we can know if the subprocess exited or
48+
* not.
49+
*
50+
* @note used for debug
51+
*/
52+
def isAlive: Boolean =
53+
try { process.exitValue(); false }
54+
catch { case _: IllegalThreadStateException => true }
55+
56+
/** Destroys the underlying process and kills IO streams */
4257
def kill(): Unit = {
4358
if (process ne null) process.destroy()
4459
process = null
60+
ois = null
61+
oos = null
4562
}
4663

64+
/** Blocks less than `maxDuration` while running `Test.main` from `dir` */
4765
def runMain(dir: JFile): Status = {
4866
assert(process ne null,
4967
"Runner was killed and then reused without setting a new process")
@@ -52,37 +70,51 @@ trait RunnerOrchestration {
5270
def respawn(): Unit = {
5371
process.destroy()
5472
process = createProcess
73+
ois = null
74+
oos = null
5575
}
5676

77+
if (oos eq null) oos = new ObjectOutputStream(process.getOutputStream)
78+
5779
// pass file to running process
5880
oos.writeObject(dir)
81+
oos.flush()
5982

6083
// Create a future reading the object:
61-
val readObject = Future(ois.readObject().asInstanceOf[Status])
84+
val readObject = Future {
85+
if (ois eq null) ois = new ObjectInputStream(process.getInputStream)
86+
ois.readObject().asInstanceOf[Status]
87+
}
6288

6389
// Await result for `maxDuration` and then timout and destroy the
6490
// process:
6591
val status =
6692
try Await.result(readObject, maxDuration)
67-
catch { case _: TimeoutException => { Timeout } }
93+
catch { case _: TimeoutException => new Timeout() }
6894

6995
// Handle failure of the VM:
7096
status match {
7197
case _ if safeMode => respawn()
72-
case status: Failure => respawn()
73-
case Timeout => respawn()
98+
case _: Failure => respawn()
99+
case _: Timeout => respawn()
74100
case _ => ()
75101
}
76-
77-
// return run status:
78102
status
79103
}
80104
}
81105

82-
private def createProcess: Process = ???
106+
private def createProcess: Process = {
107+
val sep = sys.props("file.separator")
108+
val cp = sys.props("java.class.path")
109+
val java = sys.props("java.home") + sep + "bin" + sep + "java"
110+
new ProcessBuilder(java, "-cp", cp, "dotty.tools.dotc.vulpix.ChildMain")//classOf[ChildMain].getName)
111+
.redirectErrorStream(true)
112+
.redirectInput(ProcessBuilder.Redirect.PIPE)
113+
.redirectOutput(ProcessBuilder.Redirect.PIPE)
114+
.start()
115+
}
83116

84-
private[this] val allRunners =
85-
List.fill(numberOfSlaves)(new Runner(createProcess))
117+
private[this] val allRunners = List.fill(numberOfSlaves)(new Runner(createProcess))
86118

87119
private[this] val freeRunners = mutable.Queue(allRunners: _*)
88120
private[this] val busyRunners = mutable.Set.empty[Runner]

compiler/test/dotty/tools/dotc/vulpix/Status.scala

Lines changed: 0 additions & 10 deletions
This file was deleted.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package dotty.tools.dotc.vulpix;
2+
3+
import java.io.Serializable;
4+
5+
/** The status of each call to `main` in the test applications */
6+
public class Statuses {
7+
interface Status {}
8+
9+
static class Success implements Status, Serializable {
10+
public final String output;
11+
public Success(String output) { this.output = output; }
12+
}
13+
14+
static class Failure implements Status, Serializable {
15+
public final String output;
16+
public Failure(String output) { this.output = output; }
17+
}
18+
19+
static class Timeout implements Status, Serializable {}
20+
}

0 commit comments

Comments
 (0)