summaryrefslogtreecommitdiff
path: root/main/src
diff options
context:
space:
mode:
authorLi Haoyi <haoyi.sg@gmail.com>2018-05-19 09:37:25 -0700
committerGitHub <noreply@github.com>2018-05-19 09:37:25 -0700
commita7cb99f1bce04366f688d36bc9faef30161da8e7 (patch)
tree8e4d03449536bd0400f454c863fc3031c4f02f7b /main/src
parentb03cf740533810e95774c079c76788d7ad61d8a2 (diff)
downloadmill-a7cb99f1bce04366f688d36bc9faef30161da8e7.tar.gz
mill-a7cb99f1bce04366f688d36bc9faef30161da8e7.tar.bz2
mill-a7cb99f1bce04366f688d36bc9faef30161da8e7.zip
WIP keep mill server alive if you Ctrl-C during --watch (#339)
* wip * Clean up more resources in the Mill client after every command * catch and ignore SIGINT in Mill server to make it survive Ctrl-C on the client
Diffstat (limited to 'main/src')
-rw-r--r--main/src/mill/MillMain.scala (renamed from main/src/mill/Main.scala)11
-rw-r--r--main/src/mill/main/MainRunner.scala6
-rw-r--r--main/src/mill/main/MillServerMain.scala (renamed from main/src/mill/main/Server.scala)86
3 files changed, 67 insertions, 36 deletions
diff --git a/main/src/mill/Main.scala b/main/src/mill/MillMain.scala
index 5573a325..ad1bd39d 100644
--- a/main/src/mill/Main.scala
+++ b/main/src/mill/MillMain.scala
@@ -9,7 +9,7 @@ import io.github.retronym.java9rtexport.Export
import mill.eval.Evaluator
import mill.util.DummyInputStream
-object Main {
+object MillMain {
def main(args: Array[String]): Unit = {
val as = args match {
@@ -23,7 +23,8 @@ object Main {
System.in,
System.out,
System.err,
- System.getenv().asScala.toMap
+ System.getenv().asScala.toMap,
+ b => ()
)
System.exit(if(result) 0 else 1)
}
@@ -34,7 +35,8 @@ object Main {
stdin: InputStream,
stdout: PrintStream,
stderr: PrintStream,
- env: Map[String, String]): (Boolean, Option[Evaluator.State]) = {
+ env: Map[String, String],
+ setIdle: Boolean => Unit): (Boolean, Option[Evaluator.State]) = {
import ammonite.main.Cli
val removed = Set("predef-code", "no-home-predef")
@@ -103,7 +105,8 @@ object Main {
config.copy(colored = Some(mainInteractive)),
stdout, stderr, stdin,
stateCache,
- env
+ env,
+ setIdle
)
if (mill.main.client.Util.isJava9OrAbove) {
diff --git a/main/src/mill/main/MainRunner.scala b/main/src/mill/main/MainRunner.scala
index a289db5f..bf0d5901 100644
--- a/main/src/mill/main/MainRunner.scala
+++ b/main/src/mill/main/MainRunner.scala
@@ -22,7 +22,8 @@ class MainRunner(val config: ammonite.main.Cli.Config,
errPrintStream: PrintStream,
stdIn: InputStream,
stateCache0: Option[Evaluator.State] = None,
- env : Map[String, String])
+ env : Map[String, String],
+ setIdle: Boolean => Unit)
extends ammonite.MainRunner(
config, outprintStream, errPrintStream,
stdIn, outprintStream, errPrintStream
@@ -35,8 +36,9 @@ class MainRunner(val config: ammonite.main.Cli.Config,
def statAll() = watched.forall{ case (file, lastMTime) =>
Interpreter.pathSignature(file) == lastMTime
}
-
+ setIdle(true)
while(statAll()) Thread.sleep(100)
+ setIdle(false)
}
/**
diff --git a/main/src/mill/main/Server.scala b/main/src/mill/main/MillServerMain.scala
index 07703bed..092d958c 100644
--- a/main/src/mill/main/Server.scala
+++ b/main/src/mill/main/MillServerMain.scala
@@ -3,14 +3,16 @@ package mill.main
import java.io._
import java.net.Socket
-import mill.Main
+import mill.MillMain
+
import scala.collection.JavaConverters._
import org.scalasbt.ipcsocket._
import mill.main.client._
import mill.eval.Evaluator
import mill.util.DummyInputStream
+import sun.misc.{Signal, SignalHandler}
-trait ServerMain[T]{
+trait MillServerMain[T]{
var stateCache = Option.empty[T]
def main0(args: Array[String],
stateCache: Option[T],
@@ -18,11 +20,22 @@ trait ServerMain[T]{
stdin: InputStream,
stdout: PrintStream,
stderr: PrintStream,
- env : Map[String, String]): (Boolean, Option[T])
+ env : Map[String, String],
+ setIdle: Boolean => Unit): (Boolean, Option[T])
}
-object ServerMain extends mill.main.ServerMain[Evaluator.State]{
+object MillServerMain extends mill.main.MillServerMain[Evaluator.State]{
def main(args0: Array[String]): Unit = {
+ // Disable SIGINT interrupt signal in the Mill server.
+ //
+ // This gets passed through from the client to server whenever the user
+ // hits `Ctrl-C`, which by default kills the server, which defeats the purpose
+ // of running a background server. Furthermore, the background server already
+ // can detect when the Mill client goes away, which is necessary to handle
+ // the case when a Mill client that did *not* spawn the server gets `CTRL-C`ed
+ Signal.handle(new Signal("INT"), new SignalHandler () {
+ def handle(sig: Signal) = {} // do nothing
+ })
new Server(
args0(0),
this,
@@ -37,20 +50,24 @@ object ServerMain extends mill.main.ServerMain[Evaluator.State]{
stdin: InputStream,
stdout: PrintStream,
stderr: PrintStream,
- env : Map[String, String]) = Main.main0(
- args,
- stateCache,
- mainInteractive,
- DummyInputStream,
- stdout,
- stderr,
- env
- )
+ env : Map[String, String],
+ setIdle: Boolean => Unit) = {
+ MillMain.main0(
+ args,
+ stateCache,
+ mainInteractive,
+ DummyInputStream,
+ stdout,
+ stderr,
+ env,
+ setIdle
+ )
+ }
}
class Server[T](lockBase: String,
- sm: ServerMain[T],
+ sm: MillServerMain[T],
interruptServer: () => Unit,
acceptTimeout: Int,
locks: Locks) {
@@ -71,6 +88,7 @@ class Server[T](lockBase: String,
}
val sockOpt = Server.interruptWith(
+ "MillSocketTimeoutInterruptThread",
acceptTimeout,
socketClose(),
serverSocket.accept()
@@ -111,7 +129,8 @@ class Server[T](lockBase: String,
val env = Util.parseMap(argStream)
argStream.close()
- var done = false
+ @volatile var done = false
+ @volatile var idle = false
val t = new Thread(() =>
try {
@@ -122,7 +141,8 @@ class Server[T](lockBase: String,
socketIn,
stdout,
stderr,
- env.asScala.toMap
+ env.asScala.toMap,
+ idle = _
)
sm.stateCache = newStateCache
@@ -134,18 +154,18 @@ class Server[T](lockBase: String,
sm.stateCache = sc
} finally{
done = true
- }
+ idle = true
+ },
+ "MillServerActionRunner"
)
-
t.start()
// We cannot simply use Lock#await here, because the filesystem doesn't
// realize the clientLock/serverLock are held by different threads in the
// two processes and gives a spurious deadlock error
- while(!done && !locks.clientLock.probe()) {
- Thread.sleep(3)
- }
+ while(!done && !locks.clientLock.probe()) Thread.sleep(3)
+
+ if (!idle) interruptServer()
- if (!done) interruptServer()
t.interrupt()
t.stop()
@@ -176,17 +196,22 @@ object Server{
}
}
- def interruptWith[T](millis: Int, close: => Unit, t: => T): Option[T] = {
+ def interruptWith[T](threadName: String, millis: Int, close: => Unit, t: => T): Option[T] = {
@volatile var interrupt = true
@volatile var interrupted = false
- new Thread(() => {
- Thread.sleep(millis)
- if (interrupt) {
- interrupted = true
- close
- }
- }).start()
+ val thread = new Thread(
+ () => {
+ try Thread.sleep(millis)
+ catch{ case t: InterruptedException => /* Do Nothing */ }
+ if (interrupt) {
+ interrupted = true
+ close
+ }
+ },
+ threadName
+ )
+ thread.start()
try {
val res =
try Some(t)
@@ -196,6 +221,7 @@ object Server{
else res
} finally {
+ thread.interrupt()
interrupt = false
}
}