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.util.Logger
|
||||||
import sbt.ConcurrentRestrictions.Tag
|
import sbt.ConcurrentRestrictions.Tag
|
||||||
import sbt.protocol.testing._
|
import sbt.protocol.testing._
|
||||||
import sbt.internal.util.ConsoleAppender
|
|
||||||
import sbt.internal.util.Util.{ AnyOps, none }
|
import sbt.internal.util.Util.{ AnyOps, none }
|
||||||
|
import sbt.internal.util.{ ConsoleAppender, RunningProcesses }
|
||||||
|
|
||||||
private[sbt] object ForkTests {
|
private[sbt] object ForkTests {
|
||||||
def apply(
|
def apply(
|
||||||
|
|
@ -147,7 +147,13 @@ private[sbt] object ForkTests {
|
||||||
classOf[ForkMain].getCanonicalName,
|
classOf[ForkMain].getCanonicalName,
|
||||||
server.getLocalPort.toString
|
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 =
|
val result =
|
||||||
if (ec != 0)
|
if (ec != 0)
|
||||||
TestOutput(
|
TestOutput(
|
||||||
|
|
|
||||||
|
|
@ -480,6 +480,7 @@ object EvaluateTask {
|
||||||
def cancelAndShutdown(): Unit = {
|
def cancelAndShutdown(): Unit = {
|
||||||
println("")
|
println("")
|
||||||
log.warn("Canceling execution...")
|
log.warn("Canceling execution...")
|
||||||
|
RunningProcesses.killAll()
|
||||||
ConcurrentRestrictions.cancelAll()
|
ConcurrentRestrictions.cancelAll()
|
||||||
shutdown()
|
shutdown()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,14 @@ import java.net.SocketException
|
||||||
import scala.sys.process.Process
|
import scala.sys.process.Process
|
||||||
|
|
||||||
import sbt.internal.scripted.{ StatementHandler, TestFailed }
|
import sbt.internal.scripted.{ StatementHandler, TestFailed }
|
||||||
|
import sbt.internal.util.RunningProcesses
|
||||||
|
|
||||||
import xsbt.IPC
|
import xsbt.IPC
|
||||||
|
|
||||||
final case class SbtInstance(process: Process, server: IPC.Server)
|
final case class SbtInstance(process: Process, server: IPC.Server)
|
||||||
|
|
||||||
final class SbtHandler(remoteSbtCreator: RemoteSbtCreator) extends StatementHandler {
|
final class SbtHandler(remoteSbtCreator: RemoteSbtCreator) extends StatementHandler {
|
||||||
|
Signals.register(() => RunningProcesses.killAll())
|
||||||
|
|
||||||
type State = Option[SbtInstance]
|
type State = Option[SbtInstance]
|
||||||
|
|
||||||
|
|
@ -63,6 +65,9 @@ final class SbtHandler(remoteSbtCreator: RemoteSbtCreator) extends StatementHand
|
||||||
()
|
()
|
||||||
} catch {
|
} catch {
|
||||||
case _: IOException => process.destroy()
|
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 = {
|
def newRemote(server: IPC.Server): Process = {
|
||||||
val p = remoteSbtCreator.newRemote(server)
|
val p = remoteSbtCreator.newRemote(server)
|
||||||
|
RunningProcesses.add(p)
|
||||||
try receive("Remote sbt initialization failed", server)
|
try receive("Remote sbt initialization failed", server)
|
||||||
catch { case _: SocketException => throw new TestFailed("Remote sbt initialization failed") }
|
catch { case _: SocketException => throw new TestFailed("Remote sbt initialization failed") }
|
||||||
p
|
p
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue