mirror of https://github.com/sbt/sbt.git
Merge pull request #5793 from eatkins/kill-processes
Kill external processes on sigint
This commit is contained in:
commit
788fd4aa28
|
|
@ -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