mirror of https://github.com/sbt/sbt.git
Kill external processes on sigint
On linux and mac, entering ctrl+c will automatically kill any forked processes that were created by the sbt server because sigint is automatically forwarded to the child process. This is not the case on windows where it is necessary to forcibly kill these processes.
This commit is contained in:
parent
8fe7e33a31
commit
d3f8cc8161
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* sbt
|
||||
* Copyright 2011 - 2018, Lightbend, Inc.
|
||||
* Copyright 2008 - 2010, Mark Harrah
|
||||
* Licensed under Apache License 2.0 (see LICENSE)
|
||||
*/
|
||||
|
||||
package sbt.internal.util
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import scala.sys.process.Process
|
||||
|
||||
/**
|
||||
* Manages forked processes created by sbt. Any process registered
|
||||
* with RunningProcesses can be killed with the killAll method. In
|
||||
* particular, this can be used in a signal handler to kill these
|
||||
* processes when the user inputs ctrl+c.
|
||||
*/
|
||||
private[sbt] object RunningProcesses {
|
||||
val active = ConcurrentHashMap.newKeySet[Process]
|
||||
def add(process: Process): Unit = active.synchronized {
|
||||
active.add(process)
|
||||
()
|
||||
}
|
||||
def remove(process: Process): Unit = active.synchronized {
|
||||
active.remove(process)
|
||||
()
|
||||
}
|
||||
def killAll(): Unit = active.synchronized {
|
||||
active.forEach(_.destroy())
|
||||
active.clear()
|
||||
}
|
||||
}
|
||||
|
|
@ -17,8 +17,8 @@ import sbt.io.IO
|
|||
import sbt.util.Logger
|
||||
import sbt.ConcurrentRestrictions.Tag
|
||||
import sbt.protocol.testing._
|
||||
import sbt.internal.util.ConsoleAppender
|
||||
import sbt.internal.util.Util.{ AnyOps, none }
|
||||
import sbt.internal.util.{ ConsoleAppender, RunningProcesses }
|
||||
|
||||
private[sbt] object ForkTests {
|
||||
def apply(
|
||||
|
|
@ -147,7 +147,13 @@ private[sbt] object ForkTests {
|
|||
classOf[ForkMain].getCanonicalName,
|
||||
server.getLocalPort.toString
|
||||
)
|
||||
val ec = Fork.java(fork, options)
|
||||
val p = Fork.java.fork(fork, options)
|
||||
RunningProcesses.add(p)
|
||||
val ec = try p.exitValue()
|
||||
finally {
|
||||
if (p.isAlive) p.destroy()
|
||||
RunningProcesses.remove(p)
|
||||
}
|
||||
val result =
|
||||
if (ec != 0)
|
||||
TestOutput(
|
||||
|
|
|
|||
|
|
@ -480,6 +480,7 @@ object EvaluateTask {
|
|||
def cancelAndShutdown(): Unit = {
|
||||
println("")
|
||||
log.warn("Canceling execution...")
|
||||
RunningProcesses.killAll()
|
||||
ConcurrentRestrictions.cancelAll()
|
||||
shutdown()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,12 +14,14 @@ import java.net.SocketException
|
|||
import scala.sys.process.Process
|
||||
|
||||
import sbt.internal.scripted.{ StatementHandler, TestFailed }
|
||||
import sbt.internal.util.RunningProcesses
|
||||
|
||||
import xsbt.IPC
|
||||
|
||||
final case class SbtInstance(process: Process, server: IPC.Server)
|
||||
|
||||
final class SbtHandler(remoteSbtCreator: RemoteSbtCreator) extends StatementHandler {
|
||||
Signals.register(() => RunningProcesses.killAll())
|
||||
|
||||
type State = Option[SbtInstance]
|
||||
|
||||
|
|
@ -63,6 +65,9 @@ final class SbtHandler(remoteSbtCreator: RemoteSbtCreator) extends StatementHand
|
|||
()
|
||||
} catch {
|
||||
case _: IOException => process.destroy()
|
||||
} finally {
|
||||
if (process.isAlive) process.destroy()
|
||||
RunningProcesses.remove(process)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -76,6 +81,7 @@ final class SbtHandler(remoteSbtCreator: RemoteSbtCreator) extends StatementHand
|
|||
|
||||
def newRemote(server: IPC.Server): Process = {
|
||||
val p = remoteSbtCreator.newRemote(server)
|
||||
RunningProcesses.add(p)
|
||||
try receive("Remote sbt initialization failed", server)
|
||||
catch { case _: SocketException => throw new TestFailed("Remote sbt initialization failed") }
|
||||
p
|
||||
|
|
|
|||
Loading…
Reference in New Issue