sbt.internal.util.Signal.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of collections_3 Show documentation
Show all versions of collections_3 Show documentation
sbt is an interactive build tool
/*
* sbt
* Copyright 2023, Scala center
* Copyright 2011 - 2022, Lightbend, Inc.
* Copyright 2008 - 2010, Mark Harrah
* Licensed under Apache License 2.0 (see LICENSE)
*/
package sbt.internal.util
import sun.misc.{ Signal, SignalHandler }
object Signals {
val CONT = "CONT"
val INT = "INT"
def withHandler[T](handler: () => Unit, signal: String = INT)(action: () => T): T = {
val result =
try {
val signals = new Signals0
signals.withHandler(signal, handler, action)
} catch { case _: LinkageError => Right(action()): Either[Throwable, T] }
result match {
case Left(e) => throw e
case Right(v) => v
}
}
/** Helper interface so we can expose internals of signal-isms to others. */
sealed trait Registration {
def remove(): Unit
}
/**
* Register a signal handler that can be removed later. NOTE: Does not stack with other signal
* handlers!!!!
*/
def register(handler: () => Unit, signal: String = INT): Registration =
// TODO - Maybe we can just ignore things if not is-supported.
if (supported(signal)) {
val intSignal = new Signal(signal)
val newHandler = new SignalHandler {
def handle(sig: Signal): Unit = { handler() }
}
val oldHandler = Signal.handle(intSignal, newHandler)
new UnregisterNewHandler(intSignal, oldHandler)
} else {
// TODO - Maybe we should just throw an exception if we don't support signals...
NullUnregisterNewHandler
}
def supported(signal: String): Boolean =
try {
val signals = new Signals0
signals.supported(signal)
} catch { case _: LinkageError => false }
}
private class UnregisterNewHandler(intSignal: Signal, oldHandler: SignalHandler)
extends Signals.Registration {
override def remove(): Unit = {
Signal.handle(intSignal, oldHandler)
()
}
}
private object NullUnregisterNewHandler extends Signals.Registration {
override def remove(): Unit = ()
}
// Must only be referenced using a
// try { } catch { case _: LinkageError => ... }
// block to
private final class Signals0 {
def supported(signal: String): Boolean = {
import sun.misc.Signal
try {
new Signal(signal); true
} catch { case _: IllegalArgumentException => false }
}
// returns a LinkageError in `action` as Left(t) in order to avoid it being
// incorrectly swallowed as missing Signal/SignalHandler
def withHandler[T](signal: String, handler: () => Unit, action: () => T): Either[Throwable, T] = {
import sun.misc.{ Signal, SignalHandler }
val intSignal = new Signal(signal)
val newHandler = new SignalHandler {
def handle(sig: Signal): Unit = { handler() }
}
val oldHandler = Signal.handle(intSignal, newHandler)
try Right(action())
catch { case e: LinkageError => Left(e) }
finally {
Signal.handle(intSignal, oldHandler); ()
}
}
}