summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPaul Phillips <paulp@improving.org>2010-12-28 00:25:21 +0000
committerPaul Phillips <paulp@improving.org>2010-12-28 00:25:21 +0000
commit09d502f2860481687bcb473cdc7fd489439af478 (patch)
treec48d004a3a8773c7206b556f9cfeb0ef78af35ef /src
parent9e261754f2c8480d3b0cdb8d936e04b12c21770d (diff)
downloadscala-09d502f2860481687bcb473cdc7fd489439af478.tar.gz
scala-09d502f2860481687bcb473cdc7fd489439af478.tar.bz2
scala-09d502f2860481687bcb473cdc7fd489439af478.zip
Some additions to SignalManager to make it easy...
Some additions to SignalManager to make it easy to do things in response to a signal. Like say if you're partest and you're back to freezing a few times a day and you'd like to reveal what precisely you're up to. No review.
Diffstat (limited to 'src')
-rw-r--r--src/compiler/scala/tools/util/SignalManager.scala71
-rw-r--r--src/compiler/scala/tools/util/Signallable.scala40
2 files changed, 108 insertions, 3 deletions
diff --git a/src/compiler/scala/tools/util/SignalManager.scala b/src/compiler/scala/tools/util/SignalManager.scala
index 338a6a2d1a..26274a2ddd 100644
--- a/src/compiler/scala/tools/util/SignalManager.scala
+++ b/src/compiler/scala/tools/util/SignalManager.scala
@@ -11,6 +11,8 @@ import scala.tools.reflect._
import scala.collection.{ mutable, immutable }
import nsc.io.timer
import nsc.util.{ ScalaClassLoader, Exceptional }
+import Exceptional.unwrap
+import scala.util.Random
/** Signal handling code. 100% clean of any references to sun.misc:
* it's all reflection and proxies and invocation handlers and lasers,
@@ -31,6 +33,10 @@ import nsc.util.{ ScalaClassLoader, Exceptional }
*/
class SignalManager(classLoader: ScalaClassLoader) {
def this() = this(ScalaClassLoader.getSystemLoader)
+ private val illegalArgHandler: PartialFunction[Throwable, Boolean] = {
+ case x if unwrap(x).isInstanceOf[IllegalArgumentException] => false
+ }
+ private def fail(msg: String) = new SignalError(msg)
object rSignalHandler extends Shield {
val className = "sun.misc.SignalHandler"
@@ -59,8 +65,14 @@ class SignalManager(classLoader: ScalaClassLoader) {
/** Create a new Signal with the given name.
*/
def apply(name: String) = constructor(classOf[String]) newInstance name
- def handle(signal: AnyRef, current: AnyRef) = handleMethod.invoke(null, signal, current)
- def raise(signal: AnyRef) = raiseMethod.invoke(null, signal)
+ def handle(signal: AnyRef, current: AnyRef) = {
+ if (signal == null || current == null) fail("Signals cannot be null")
+ else handleMethod.invoke(null, signal, current)
+ }
+ def raise(signal: AnyRef) = {
+ if (signal == null) fail("Signals cannot be null")
+ else raiseMethod.invoke(null, signal)
+ }
def number(signal: AnyRef): Int = numberMethod.invoke(signal).asInstanceOf[Int]
class WSignal(val name: String) {
@@ -82,16 +94,33 @@ class SignalManager(classLoader: ScalaClassLoader) {
try f(swap)
finally handle(swap)
}
+ def isDefault = try withCurrentHandler {
+ case SIG_DFL => true
+ case _ => false
+ } catch illegalArgHandler
+ def isIgnored = try withCurrentHandler {
+ case SIG_IGN => true
+ case _ => false
+ } catch illegalArgHandler
+ def isSetTo(ref: AnyRef) =
+ try withCurrentHandler { _ eq ref }
+ catch illegalArgHandler
def handlerString() = withCurrentHandler {
case SIG_DFL => "Default"
case SIG_IGN => "Ignore"
case x => "" + x
}
+
override def toString = "%10s %s".format("SIG" + name,
try handlerString()
- catch { case x: Exception => "VM threw " + Exceptional.unwrap(x) }
+ catch { case x: Exception => "VM threw " + unwrap(x) }
)
+ override def equals(other: Any) = other match {
+ case x: WSignal => name == x.name
+ case _ => false
+ }
+ override def hashCode = name.##
}
}
type WSignal = rSignal.WSignal
@@ -132,6 +161,32 @@ class SignalManager(classLoader: ScalaClassLoader) {
class SignalError(message: String) extends WSignal(null) {
override def toString = message
}
+
+ def public(name: String, description: String)(body: => Unit): Unit = {
+ val wsig = apply(name)
+ wsig setTo body
+ registerInfoHandler()
+ addPublicHandler((wsig, description))
+ }
+ /** Makes sure the info handler is registered if we see activity. */
+ private def registerInfoHandler() = {
+ val INFO = apply("INFO")
+ if (publicHandlers.isEmpty && INFO.isDefault) {
+ INFO setTo Console.println(info())
+ addPublicHandler((INFO, "Dump list of well known signal handler to console."))
+ }
+ }
+ private def addPublicHandler(kv: (WSignal, String)) = {
+ if (publicHandlers exists (_._1 == kv._1)) ()
+ else publicHandlers = (kv :: publicHandlers) sortBy (_._1.number)
+ }
+ private var publicHandlers: List[(WSignal, String)] = Nil
+ def info(): String = {
+ registerInfoHandler()
+ "\nOutward facing signal handler registry:\n" + (
+ publicHandlers map { case (wsig, descr) => " %2d %5s %s\n".format(wsig.number, wsig.name, descr) } mkString ""
+ )
+ }
}
object SignalManager extends SignalManager {
@@ -144,6 +199,16 @@ object SignalManager extends SignalManager {
STOP, TSTP, CONT, CHLD, TTIN, TTOU, IO, XCPU, // 16-23
XFSZ, VTALRM, PROF, WINCH, INFO, USR1, USR2 // 24-31
)
+ /** Signals which seem like particularly bad choices
+ * when looking for an open one.
+ */
+ def reserved = Set(QUIT, TRAP, ABRT, KILL, BUS, SEGV, ALRM, STOP, INT)
+ def unreserved = all filterNot reserved
+
+ def defaultSignals() = unreserved filter (_.isDefault)
+ def ignoredSignals() = unreserved filter (_.isIgnored)
+ def findOpenSignal() = Random.shuffle(defaultSignals()).head
+
def dump() = all foreach (x => println("%2s %s".format(x.number, x)))
def apply(sigNumber: Int): WSignal = signalNumberMap(sigNumber)
diff --git a/src/compiler/scala/tools/util/Signallable.scala b/src/compiler/scala/tools/util/Signallable.scala
new file mode 100644
index 0000000000..0ad14fe02e
--- /dev/null
+++ b/src/compiler/scala/tools/util/Signallable.scala
@@ -0,0 +1,40 @@
+/* NSC -- new Scala compiler
+ * Copyright 2005-2010 LAMP/EPFL
+ * @author Paul Phillips
+ */
+
+package scala.tools
+package util
+
+/** A class for things which are signallable.
+ */
+abstract class Signallable[T] private (val signal: String, val description: String) {
+ private var last: Option[T] = None
+ private def lastString = last filterNot (_ == ()) map (_.toString) getOrElse ""
+ def lastResult: Option[T] = last
+
+ /** Method to be executed when the associated signal is received. */
+ def onSignal(): T
+
+ override def toString = " SIG(%s) => %s%s".format(
+ signal, description, if (lastString == "") "" else " (" + lastString + ")"
+ )
+}
+
+object Signallable {
+ def apply[T](description: String)(body: => T): Signallable[T] =
+ apply(SignalManager.findOpenSignal().name, description)(body)
+
+ def apply[T](signal: String, description: String)(body: => T): Signallable[T] = {
+ val result = new Signallable[T](signal, description) {
+ def onSignal(): T = {
+ val result = body
+ last = Some(result)
+ result
+ }
+ }
+ SignalManager.public(signal, description)(result.onSignal())
+ result
+ }
+}
+