mirror of https://github.com/sbt/sbt.git
Merge pull request #5752 from eatkins/cancel-all
Cancel all running tasks with ctrl+c
This commit is contained in:
commit
8ce423b088
|
|
@ -480,6 +480,7 @@ object EvaluateTask {
|
||||||
def cancelAndShutdown(): Unit = {
|
def cancelAndShutdown(): Unit = {
|
||||||
println("")
|
println("")
|
||||||
log.warn("Canceling execution...")
|
log.warn("Canceling execution...")
|
||||||
|
ConcurrentRestrictions.cancelAll()
|
||||||
shutdown()
|
shutdown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ package sbt
|
||||||
import java.util.concurrent.atomic.AtomicInteger
|
import java.util.concurrent.atomic.AtomicInteger
|
||||||
|
|
||||||
import sbt.internal.util.AttributeKey
|
import sbt.internal.util.AttributeKey
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
import java.util.concurrent.RejectedExecutionException
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Describes restrictions on concurrent execution for a set of tasks.
|
* Describes restrictions on concurrent execution for a set of tasks.
|
||||||
|
|
@ -48,6 +50,12 @@ import java.util.concurrent.{ Executor, Executors, ExecutorCompletionService }
|
||||||
import annotation.tailrec
|
import annotation.tailrec
|
||||||
|
|
||||||
object ConcurrentRestrictions {
|
object ConcurrentRestrictions {
|
||||||
|
private[this] val completionServices = new java.util.WeakHashMap[CompletionService[_, _], Boolean]
|
||||||
|
import scala.collection.JavaConverters._
|
||||||
|
def cancelAll() = completionServices.keySet.asScala.toVector.foreach {
|
||||||
|
case a: AutoCloseable => a.close()
|
||||||
|
case _ =>
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A ConcurrentRestrictions instance that places no restrictions on concurrently executing tasks.
|
* A ConcurrentRestrictions instance that places no restrictions on concurrently executing tasks.
|
||||||
|
|
@ -138,7 +146,8 @@ object ConcurrentRestrictions {
|
||||||
val pool = Executors.newCachedThreadPool { r =>
|
val pool = Executors.newCachedThreadPool { r =>
|
||||||
new Thread(r, s"sbt-completion-service-pool-$id-${i.getAndIncrement()}")
|
new Thread(r, s"sbt-completion-service-pool-$id-${i.getAndIncrement()}")
|
||||||
}
|
}
|
||||||
(completionService[A, R](pool, tags, warn), () => { pool.shutdownNow(); () })
|
val service = completionService[A, R](pool, tags, warn)
|
||||||
|
(service, () => { service.close(); pool.shutdownNow(); () })
|
||||||
}
|
}
|
||||||
|
|
||||||
def completionService[A, R](
|
def completionService[A, R](
|
||||||
|
|
@ -147,7 +156,9 @@ object ConcurrentRestrictions {
|
||||||
isSentinel: A => Boolean
|
isSentinel: A => Boolean
|
||||||
): (CompletionService[A, R], () => Unit) = {
|
): (CompletionService[A, R], () => Unit) = {
|
||||||
val pool = Executors.newCachedThreadPool()
|
val pool = Executors.newCachedThreadPool()
|
||||||
(completionService[A, R](pool, tags, warn, isSentinel), () => {
|
val service = completionService[A, R](pool, tags, warn, isSentinel)
|
||||||
|
(service, () => {
|
||||||
|
service.close()
|
||||||
pool.shutdownNow()
|
pool.shutdownNow()
|
||||||
()
|
()
|
||||||
})
|
})
|
||||||
|
|
@ -157,7 +168,7 @@ object ConcurrentRestrictions {
|
||||||
backing: Executor,
|
backing: Executor,
|
||||||
tags: ConcurrentRestrictions[A],
|
tags: ConcurrentRestrictions[A],
|
||||||
warn: String => Unit
|
warn: String => Unit
|
||||||
): CompletionService[A, R] = {
|
): CompletionService[A, R] with AutoCloseable = {
|
||||||
completionService[A, R](backing, tags, warn, (_: A) => false)
|
completionService[A, R](backing, tags, warn, (_: A) => false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -170,12 +181,18 @@ object ConcurrentRestrictions {
|
||||||
tags: ConcurrentRestrictions[A],
|
tags: ConcurrentRestrictions[A],
|
||||||
warn: String => Unit,
|
warn: String => Unit,
|
||||||
isSentinel: A => Boolean,
|
isSentinel: A => Boolean,
|
||||||
): CompletionService[A, R] = {
|
): CompletionService[A, R] with AutoCloseable = {
|
||||||
|
|
||||||
// Represents submitted work for a task.
|
// Represents submitted work for a task.
|
||||||
final class Enqueue(val node: A, val work: () => R)
|
final class Enqueue(val node: A, val work: () => R)
|
||||||
|
|
||||||
new CompletionService[A, R] {
|
new CompletionService[A, R] with AutoCloseable {
|
||||||
|
completionServices.put(this, true)
|
||||||
|
private[this] val closed = new AtomicBoolean(false)
|
||||||
|
override def close(): Unit = if (closed.compareAndSet(false, true)) {
|
||||||
|
completionServices.remove(this)
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
/** Backing service used to manage execution on threads once all constraints are satisfied. */
|
/** Backing service used to manage execution on threads once all constraints are satisfied. */
|
||||||
private[this] val jservice = new ExecutorCompletionService[R](backing)
|
private[this] val jservice = new ExecutorCompletionService[R](backing)
|
||||||
|
|
@ -190,7 +207,8 @@ object ConcurrentRestrictions {
|
||||||
private[this] val pending = new LinkedList[Enqueue]
|
private[this] val pending = new LinkedList[Enqueue]
|
||||||
|
|
||||||
def submit(node: A, work: () => R): Unit = synchronized {
|
def submit(node: A, work: () => R): Unit = synchronized {
|
||||||
if (isSentinel(node)) {
|
if (closed.get) throw new RejectedExecutionException
|
||||||
|
else if (isSentinel(node)) {
|
||||||
// skip all checks for sentinels
|
// skip all checks for sentinels
|
||||||
CompletionService.submit(work, jservice)
|
CompletionService.submit(work, jservice)
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -253,7 +271,11 @@ object ConcurrentRestrictions {
|
||||||
submitValid(tried)
|
submitValid(tried)
|
||||||
}
|
}
|
||||||
|
|
||||||
def take(): R = jservice.take().get()
|
def take(): R = {
|
||||||
|
if (closed.get)
|
||||||
|
throw new IllegalStateException("Tried to get values for a closed completion service")
|
||||||
|
jservice.take().get()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue