diff options
author | Paul Phillips <paulp@improving.org> | 2010-11-26 19:16:05 +0000 |
---|---|---|
committer | Paul Phillips <paulp@improving.org> | 2010-11-26 19:16:05 +0000 |
commit | 1fcb86507062f9923465cdf72e6b70c3a1cfe96b (patch) | |
tree | 0b9a713193a18a9dc47c054058ccba36e5fe218f /src/compiler | |
parent | 79ef52f9e374a6ef599cefebb878692b380ea755 (diff) | |
download | scala-1fcb86507062f9923465cdf72e6b70c3a1cfe96b.tar.gz scala-1fcb86507062f9923465cdf72e6b70c3a1cfe96b.tar.bz2 scala-1fcb86507062f9923465cdf72e6b70c3a1cfe96b.zip |
A new totally safe signal manager, along with a...
A new totally safe signal manager, along with all the support code
needed for that. See the classes in scala.tools.reflect.* for
interesting new weapons. Also includes inaugural handy usage:
scala> val x = 10
x: Int = 10
scala> while (true) ()
[ctrl-C]
Execution interrupted by signal.
scala> x
res1: Int = 10
No review, but feedback welcome.
Diffstat (limited to 'src/compiler')
-rw-r--r-- | src/compiler/scala/tools/cmd/FromString.scala | 2 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/Interpreter.scala | 32 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/interpreter/JLineReader.scala | 9 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/Exceptional.scala | 4 | ||||
-rw-r--r-- | src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala | 10 | ||||
-rw-r--r-- | src/compiler/scala/tools/reflect/Invoked.scala | 52 | ||||
-rw-r--r-- | src/compiler/scala/tools/reflect/Mock.scala | 59 | ||||
-rw-r--r-- | src/compiler/scala/tools/reflect/Shield.scala | 44 | ||||
-rw-r--r-- | src/compiler/scala/tools/reflect/package.scala | 30 | ||||
-rw-r--r-- | src/compiler/scala/tools/util/SignalManager.scala | 223 |
10 files changed, 385 insertions, 80 deletions
diff --git a/src/compiler/scala/tools/cmd/FromString.scala b/src/compiler/scala/tools/cmd/FromString.scala index 81454e7a30..fd6c1331b0 100644 --- a/src/compiler/scala/tools/cmd/FromString.scala +++ b/src/compiler/scala/tools/cmd/FromString.scala @@ -7,7 +7,7 @@ package scala.tools package cmd import nsc.io.{ Path, File, Directory } -import reflect.OptManifest +import scala.reflect.OptManifest /** A general mechanism for defining how a command line argument * (always a String) is transformed into an arbitrary type. A few diff --git a/src/compiler/scala/tools/nsc/Interpreter.scala b/src/compiler/scala/tools/nsc/Interpreter.scala index 3ef1a995b4..9c76fc2ff2 100644 --- a/src/compiler/scala/tools/nsc/Interpreter.scala +++ b/src/compiler/scala/tools/nsc/Interpreter.scala @@ -11,18 +11,19 @@ import File.pathSeparator import java.lang.{ Class, ClassLoader } import java.net.{ MalformedURLException, URL } import java.lang.reflect +import java.util.concurrent.Future import reflect.InvocationTargetException import scala.collection.{ mutable, immutable } import scala.PartialFunction.{ cond, condOpt } -import scala.tools.util.PathResolver +import scala.tools.util.{ PathResolver, SignalManager } import scala.reflect.Manifest import scala.collection.mutable.{ ListBuffer, HashSet, HashMap, ArrayBuffer } import scala.tools.nsc.util.{ ScalaClassLoader, Exceptional } import ScalaClassLoader.URLClassLoader import scala.util.control.Exception.{ Catcher, catching, catchingPromiscuously, ultimately, unwrapping } -import io.{ PlainFile, VirtualDirectory } +import io.{ PlainFile, VirtualDirectory, spawn } import reporters.{ ConsoleReporter, Reporter } import symtab.{ Flags, Names } import util.{ ScalaPrefs, JavaStackFrame, SourceFile, BatchSourceFile, ScriptSourceFile, ClassPath, Chars, stringFromWriter } @@ -183,6 +184,17 @@ class Interpreter(val settings: Settings, out: PrintWriter) { } } + private var currentExecution: Future[_] = null + private def sigintHandler = { + if (currentExecution == null) System.exit(1) + else currentExecution.cancel(true) + } + /** Try to install sigint handler: ignore failure. */ + locally { + try { SignalManager("INT") = sigintHandler } + catch { case _: Exception => () } + } + /** interpreter settings */ lazy val isettings = new InterpreterSettings(this) @@ -999,9 +1011,19 @@ class Interpreter(val settings: Settings, out: PrintWriter) { } } - catchingPromiscuously(onErr) { - unwrapping(wrapperExceptions: _*) { - (resultValMethod.invoke(loadedResultObject).toString, true) + /** Todo: clean this up. */ + ultimately(currentExecution = null) { + catchingPromiscuously(onErr) { + unwrapping(wrapperExceptions: _*) { + /** Running it in a separate thread so it's easy to interrupt on ctrl-C. */ + val future = spawn(resultValMethod.invoke(loadedResultObject).toString) + currentExecution = future + while (!future.isDone) + Thread.`yield` + + if (future.isCancelled) ("Execution interrupted by signal.\n", false) + else (future.get(), true) + } } } } diff --git a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala index c7289ad7e8..032da9c395 100644 --- a/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala +++ b/src/compiler/scala/tools/nsc/interpreter/JLineReader.scala @@ -8,7 +8,6 @@ package interpreter import java.io.File import jline.{ ConsoleReader, ArgumentCompletor, History => JHistory } -// import scala.tools.util.SignalManager /** Reads from the console using JLine */ class JLineReader(interpreter: Interpreter) extends InteractiveReader { @@ -18,14 +17,6 @@ class JLineReader(interpreter: Interpreter) extends InteractiveReader { override lazy val completion = Option(interpreter) map (x => new Completion(x)) override def init() = consoleReader.getTerminal().initializeTerminal() - /** Requires two interrupt signals within three seconds - * of one another to initiate exit. - */ - // SignalManager.requireInterval(3, SignalManager.INT) { - // case true => Console.println("\nPress ctrl-C again to exit.") - // case false => System.exit(1) - // } - val consoleReader = { val r = new jline.ConsoleReader() r setHistory (History().jhistory) diff --git a/src/compiler/scala/tools/nsc/util/Exceptional.scala b/src/compiler/scala/tools/nsc/util/Exceptional.scala index c5fc92443d..d0c04ae4d9 100644 --- a/src/compiler/scala/tools/nsc/util/Exceptional.scala +++ b/src/compiler/scala/tools/nsc/util/Exceptional.scala @@ -1,7 +1,7 @@ package scala.tools.nsc package util -import java.lang.reflect.InvocationTargetException +import java.lang.reflect.{ InvocationTargetException, UndeclaredThrowableException } import io.{ Sources, Fileish } import scala.tools.util.StringOps._ @@ -117,7 +117,7 @@ object Exceptional { case ex => x :: causes(ex) } def unwrap(x: Throwable): Throwable = x match { - case _: InvocationTargetException | _: ExceptionInInitializerError if x.getCause != null => unwrap(x.getCause) + case _: InvocationTargetException | _: ExceptionInInitializerError | _: UndeclaredThrowableException if x.getCause != null => unwrap(x.getCause) case _ => x } } diff --git a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala index a739caa8a4..4604e63d59 100644 --- a/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala +++ b/src/compiler/scala/tools/nsc/util/ScalaClassLoader.scala @@ -56,6 +56,9 @@ trait ScalaClassLoader extends JavaClassLoader { result } + def constructorsOf[T <: AnyRef : Manifest]: List[Constructor[T]] = + manifest[T].erasure.getConstructors.toList map (_.asInstanceOf[Constructor[T]]) + /** The actual bytes for a class file, or an empty array if it can't be found. */ def findBytesForClassName(s: String): Array[Byte] = { val name = s.replaceAll("""\.""", "/") + ".class" @@ -80,6 +83,11 @@ trait ScalaClassLoader extends JavaClassLoader { } object ScalaClassLoader { + implicit def apply(cl: JavaClassLoader): ScalaClassLoader = { + val loader = if (cl == null) JavaClassLoader.getSystemClassLoader() else cl + new JavaClassLoader(loader) with ScalaClassLoader + } + class URLClassLoader(urls: Seq[URL], parent: JavaClassLoader) extends java.net.URLClassLoader(urls.toArray, parent) with ScalaClassLoader { @@ -97,7 +105,7 @@ object ScalaClassLoader { def setContextLoader(cl: JavaClassLoader) = Thread.currentThread.setContextClassLoader(cl) def getContextLoader() = Thread.currentThread.getContextClassLoader() - def getSystemLoader(): ScalaClassLoader = new JavaClassLoader(JavaClassLoader.getSystemClassLoader()) with ScalaClassLoader + def getSystemLoader(): ScalaClassLoader = ScalaClassLoader(null) def defaultParentClassLoader() = findExtClassLoader() def fromURLs(urls: Seq[URL], parent: ClassLoader = defaultParentClassLoader()): URLClassLoader = diff --git a/src/compiler/scala/tools/reflect/Invoked.scala b/src/compiler/scala/tools/reflect/Invoked.scala new file mode 100644 index 0000000000..935d493130 --- /dev/null +++ b/src/compiler/scala/tools/reflect/Invoked.scala @@ -0,0 +1,52 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools +package reflect + +import java.lang.reflect.{ Method, Proxy } + +/** A class representing a single method call. It is primarily for use + * in tandem with Mock. If the invocation did not target an InvocationHandler, + * proxy will be null. + */ +class Invoked private (val proxy: AnyRef, val m: Method, val args: List[AnyRef]) { + def name = m.getName + def arity = m.getParameterTypes.size + def returnType = m.getReturnType + def returns[T: Manifest] = returnType == manifest[T].erasure + + def invokeOn(target: AnyRef) = m.invoke(target, args: _*) + def isObjectMethod = Set("toString", "equals", "hashCode") contains name + + override def toString = "Invoked: %s called with %s".format( + m.getName, + if (args.isEmpty) "no args" else "args '%s'".format(args mkString ", ") + ) +} + +object Invoked { + def apply(m: Method, args: Seq[Any]): Invoked = apply(null, m, args) + def apply(proxy: AnyRef, m: Method, args: Seq[Any]): Invoked = { + val fixedArgs = if (args == null) Nil else args.toList map (_.asInstanceOf[AnyRef]) + new Invoked(proxy, m, fixedArgs) + } + def unapply(x: Any) = x match { + case x: Invoked => Some(x.proxy, x.m, x.args) + case _ => None + } + object NameAndArgs { + def unapply(x: Any) = x match { + case x: Invoked => Some(x.name, x.args) + case _ => None + } + } + object NameAndArity { + def unapply(x: Any) = x match { + case x: Invoked => Some(x.name, x.arity) + case _ => None + } + } +} diff --git a/src/compiler/scala/tools/reflect/Mock.scala b/src/compiler/scala/tools/reflect/Mock.scala new file mode 100644 index 0000000000..1c5c880113 --- /dev/null +++ b/src/compiler/scala/tools/reflect/Mock.scala @@ -0,0 +1,59 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools +package reflect + +import java.lang.reflect.{ Method, Proxy, InvocationHandler } + +/** A wrapper around java dynamic proxies to make it easy to pose + * as an interface. See SignalManager for an example usage. + */ +trait Mock extends (Invoked => AnyRef) { + mock => + + def interfaces: List[Class[_]] + def classLoader: ClassLoader + def apply(invoked: Invoked): AnyRef + + def newProxyInstance(handler: InvocationHandler): AnyRef = + Proxy.newProxyInstance(classLoader, interfaces.toArray, handler) + def newProxyInstance(): AnyRef = + newProxyInstance(newInvocationHandler()) + + def newInvocationHandler() = new InvocationHandler { + def invoke(proxy: AnyRef, method: Method, args: Array[AnyRef]) = + mock(Invoked(proxy, method, args)) + } +} + +/** The methods in Mock create the actual proxy instance which can be used + * in place of the associated interface(s). + */ +object Mock { + /** The default implementation calls the partial function if defined, and + * routes Object methods to the proxy: otherwise it throws an exception. + */ + def fromInterfaces(clazz: Class[_], clazzes: Class[_]*)(pf: PartialFunction[Invoked, AnyRef]): AnyRef = { + val ints = clazz :: clazzes.toList + require(ints forall (_.isInterface), "All class objects must represent interfaces") + + val mock = new Mock { + val interfaces = ints + def classLoader = clazz.getClassLoader + def apply(invoked: Invoked) = + if (pf.isDefinedAt(invoked)) pf(invoked) + else if (invoked.isObjectMethod) invoked invokeOn this + else throw new NoSuchMethodException("" + invoked) + } + mock.newProxyInstance() + } + /** Tries to implement all the class's interfaces. + */ + def fromClass(clazz: Class[_])(pf: PartialFunction[Invoked, AnyRef]): AnyRef = allInterfaces(clazz) match { + case Nil => Predef.error(clazz + " implements no interfaces.") + case x :: xs => fromInterfaces(x, xs: _*)(pf) + } +} diff --git a/src/compiler/scala/tools/reflect/Shield.scala b/src/compiler/scala/tools/reflect/Shield.scala new file mode 100644 index 0000000000..5abd97d517 --- /dev/null +++ b/src/compiler/scala/tools/reflect/Shield.scala @@ -0,0 +1,44 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools +package reflect + +import java.lang.reflect.Constructor +import nsc.util.ScalaClassLoader + +/** A support class for simplifying the otherwise disbelief-inspiring + * process of working with classes completely reflectively. This is + * the case with e.g. sun.misc.Signal* due to environments which are + * antagonistic to their use. See SignalManager for an example. + * + * The name "Shield" is a reference to shielding the JVM from knowledge + * of what we're doing. + */ +trait Shield { + def className: String + def classLoader: ScalaClassLoader + + // Override this if you are more ambitious about logging or throwing. + def onError[T >: Null](msg: String): T = null + + /** This is handy because all reflective calls want back an AnyRef but + * we will often be generating Units. + */ + protected implicit def boxedUnit(x: Unit): AnyRef = scala.runtime.BoxedUnit.UNIT + + lazy val clazz: Class[_] = classLoader.tryToLoadClass(className) getOrElse onError("Failed to load " + className) + lazy val methods = clazz.getMethods.toList + + def constructor(paramTypes: Class[_]*) = clazz.getConstructor(paramTypes: _*).asInstanceOf[Constructor[AnyRef]] + def method(name: String, arity: Int) = uniqueMethod(name, arity) + def field(name: String) = clazz getField name + + def matchingMethods(name: String, arity: Int) = methods filter (m => nameAndArity(m) == (name, arity)) + def uniqueMethod(name: String, arity: Int) = matchingMethods(name, arity) match { + case List(x) => x + case _ => onError("No unique match for " + name) + } +} diff --git a/src/compiler/scala/tools/reflect/package.scala b/src/compiler/scala/tools/reflect/package.scala new file mode 100644 index 0000000000..cf3d6f9ab2 --- /dev/null +++ b/src/compiler/scala/tools/reflect/package.scala @@ -0,0 +1,30 @@ +/* NSC -- new Scala compiler + * Copyright 2005-2010 LAMP/EPFL + * @author Paul Phillips + */ + +package scala.tools + +import java.lang.reflect.Method +import java.{ lang => jl } + +package object reflect { + def nameAndArity(m: Method) = (m.getName, m.getParameterTypes.size) + def allInterfaces(cl: Class[_]): List[Class[_]] = + if (cl == null) Nil + else cl.getInterfaces.toList ++ allInterfaces(cl.getSuperclass) distinct + + def zeroOfClass(clazz: Class[_]) = zeroOf(Manifest.classType(clazz)) + def zeroOf[T](implicit m: Manifest[T]): AnyRef = { + if (m == manifest[Boolean] || m == manifest[jl.Boolean]) false: jl.Boolean + else if (m == manifest[Unit] || m == manifest[jl.Void]) scala.runtime.BoxedUnit.UNIT + else if (m == manifest[Char] || m == manifest[jl.Character]) 0.toChar: jl.Character + else if (m == manifest[Byte] || m == manifest[jl.Byte]) 0.toByte: jl.Byte + else if (m == manifest[Short] || m == manifest[jl.Short]) 0.toShort: jl.Short + else if (m == manifest[Int] || m == manifest[jl.Integer]) 0: jl.Integer + else if (m == manifest[Long] || m == manifest[jl.Long]) 0l: jl.Long + else if (m == manifest[Float] || m == manifest[jl.Float]) 0f: jl.Float + else if (m == manifest[Double] || m == manifest[jl.Double]) 0d: jl.Double + else null + } +} diff --git a/src/compiler/scala/tools/util/SignalManager.scala b/src/compiler/scala/tools/util/SignalManager.scala index e44bc31081..338a6a2d1a 100644 --- a/src/compiler/scala/tools/util/SignalManager.scala +++ b/src/compiler/scala/tools/util/SignalManager.scala @@ -6,87 +6,188 @@ package scala.tools package util -class SignalManager // dummy for ant - -/** Disabled. - -import sun.misc.{ Signal, SignalHandler } -import SignalHandler._ +import java.lang.reflect.{ Method, Constructor } +import scala.tools.reflect._ +import scala.collection.{ mutable, immutable } import nsc.io.timer +import nsc.util.{ ScalaClassLoader, Exceptional } -/** Unofficial signal handling code. According to sun it's unsupported, - * but it's too useful not to take advantage of. Degrade gracefully. +/** Signal handling code. 100% clean of any references to sun.misc: + * it's all reflection and proxies and invocation handlers and lasers, + * so even the choosiest runtimes will be cool with it. + * + * Sun/Oracle says sun.misc.* is unsupported and therefore so is all + * of this. Simple examples: + * {{{ + val manager = scala.tools.util.SignalManager // or you could make your own + // Assignment clears any old handlers; += chains them. + manager("HUP") = println("HUP 1!") + manager("HUP") += println("HUP 2!") + // Use raise() to raise a signal: this will print both lines + manager("HUP").raise() + // See a report on every signal's current handler + manager.dump() + * }}} */ -class SignalManager { - def apply(name: String): SignalWrapper = - try { new SignalWrapper(new Signal(name)) } - catch { case x: IllegalArgumentException => new SignalError(x.getMessage) } +class SignalManager(classLoader: ScalaClassLoader) { + def this() = this(ScalaClassLoader.getSystemLoader) + + object rSignalHandler extends Shield { + val className = "sun.misc.SignalHandler" + val classLoader = SignalManager.this.classLoader + + lazy val SIG_DFL = field("SIG_DFL") get null + lazy val SIG_IGN = field("SIG_IGN") get null + + /** Create a new signal handler based on the function. + */ + def apply(action: Invoked => Unit) = Mock.fromInterfaces(clazz) { + case inv @ Invoked.NameAndArgs("handle", _ :: Nil) => action(inv) + } + def empty = rSignalHandler(_ => ()) + } + import rSignalHandler.{ SIG_DFL, SIG_IGN } + + object rSignal extends Shield { + val className = "sun.misc.Signal" + val classLoader = SignalManager.this.classLoader + + lazy val handleMethod = method("handle", 2) + lazy val raiseMethod = method("raise", 1) + lazy val numberMethod = method("getNumber", 0) + + /** 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 number(signal: AnyRef): Int = numberMethod.invoke(signal).asInstanceOf[Int] + + class WSignal(val name: String) { + lazy val signal = rSignal apply name + def number = rSignal number signal + def raise() = rSignal raise signal + def handle(handler: AnyRef) = rSignal.handle(signal, handler) + + def setTo(body: => Unit) = register(name, false, body) + def +=(body: => Unit) = register(name, true, body) + + /** It's hard to believe there's no way to get a signal's current + * handler without replacing it, but if there is I couldn't find + * it, so we have this swapping code. + */ + def withCurrentHandler[T](f: AnyRef => T): T = { + val swap = handle(rSignalHandler.empty) + + try f(swap) + finally handle(swap) + } - class ChainedHandler(prev: SignalHandler, current: SignalHandler) extends SignalHandler { - def handle(sig: Signal): Unit = { - current handle sig - if (prev != SIG_DFL && prev != SIG_IGN) - prev handle sig + 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) } + ) } } - class SignalWrapper(val signal: Signal) { - def name = signal.getName - def add(body: => Unit) = { - val handler = new SignalHandler { def handle(sig: Signal) = body } - val prev = Signal.handle(signal, handler) + type WSignal = rSignal.WSignal + + /** Adds a handler for the named signal. If shouldChain is true, + * the installed handler will call the previous handler after the + * new one has executed. If false, the old handler is dropped. + */ + private def register(name: String, shouldChain: Boolean, body: => Unit) = { + val signal = rSignal(name) + val current = rSignalHandler(_ => body) + val prev = rSignal.handle(signal, current) - new ChainedHandler(prev, handler) + if (shouldChain) { + val chainer = rSignalHandler { inv => + val signal = inv.args.head + + inv invokeOn current + prev match { + case SIG_IGN | SIG_DFL => () + case _ => inv invokeOn prev + } + } + rSignal.handle(signal, chainer) + chainer } - override def toString = "SIG" + name + else current } - class SignalError(message: String) extends SignalWrapper(null) { + + /** Use apply and update to get and set handlers. + */ + def apply(name: String): WSignal = + try { new WSignal(name) } + catch { case x: IllegalArgumentException => new SignalError(x.getMessage) } + + def update(name: String, body: => Unit): Unit = apply(name) setTo body + + class SignalError(message: String) extends WSignal(null) { override def toString = message } } object SignalManager extends SignalManager { - private implicit def mkSignalWrapper(name: String): SignalWrapper = this(name) - - def HUP: SignalWrapper = "HUP" - def INT: SignalWrapper = "INT" - def QUIT: SignalWrapper = "QUIT" - def ILL: SignalWrapper = "ILL" - def TRAP: SignalWrapper = "TRAP" - def ABRT: SignalWrapper = "ABRT" - def EMT: SignalWrapper = "EMT" - def FPE: SignalWrapper = "FPE" - def KILL: SignalWrapper = "KILL" - def BUS: SignalWrapper = "BUS" - def SEGV: SignalWrapper = "SEGV" - def SYS: SignalWrapper = "SYS" - def PIPE: SignalWrapper = "PIPE" - def ALRM: SignalWrapper = "ALRM" - def TERM: SignalWrapper = "TERM" - def URG: SignalWrapper = "URG" - def STOP: SignalWrapper = "STOP" - def TSTP: SignalWrapper = "TSTP" - def CONT: SignalWrapper = "CONT" - def CHLD: SignalWrapper = "CHLD" - def TTIN: SignalWrapper = "TTIN" - def TTOU: SignalWrapper = "TTOU" - def IO: SignalWrapper = "IO" - def XCPU: SignalWrapper = "XCPU" - def XFSZ: SignalWrapper = "XFSZ" - def VTALRM: SignalWrapper = "VTALRM" - def PROF: SignalWrapper = "PROF" - def WINCH: SignalWrapper = "WINCH" - def INFO: SignalWrapper = "INFO" - def USR1: SignalWrapper = "USR1" - def USR2: SignalWrapper = "USR2" + private implicit def mkWSignal(name: String): WSignal = this(name) + private lazy val signalNumberMap = all map (x => x.number -> x) toMap + + def all = List( + HUP, INT, QUIT, ILL, TRAP, ABRT, EMT, FPE, // 1-8 + KILL, BUS, SEGV, SYS, PIPE, ALRM, TERM, URG, // 9-15 + STOP, TSTP, CONT, CHLD, TTIN, TTOU, IO, XCPU, // 16-23 + XFSZ, VTALRM, PROF, WINCH, INFO, USR1, USR2 // 24-31 + ) + def dump() = all foreach (x => println("%2s %s".format(x.number, x))) + + def apply(sigNumber: Int): WSignal = signalNumberMap(sigNumber) + + def HUP: WSignal = "HUP" + def INT: WSignal = "INT" + def QUIT: WSignal = "QUIT" + def ILL: WSignal = "ILL" + def TRAP: WSignal = "TRAP" + def ABRT: WSignal = "ABRT" + def EMT: WSignal = "EMT" + def FPE: WSignal = "FPE" + def KILL: WSignal = "KILL" + def BUS: WSignal = "BUS" + def SEGV: WSignal = "SEGV" + def SYS: WSignal = "SYS" + def PIPE: WSignal = "PIPE" + def ALRM: WSignal = "ALRM" + def TERM: WSignal = "TERM" + def URG: WSignal = "URG" + def STOP: WSignal = "STOP" + def TSTP: WSignal = "TSTP" + def CONT: WSignal = "CONT" + def CHLD: WSignal = "CHLD" + def TTIN: WSignal = "TTIN" + def TTOU: WSignal = "TTOU" + def IO: WSignal = "IO" + def XCPU: WSignal = "XCPU" + def XFSZ: WSignal = "XFSZ" + def VTALRM: WSignal = "VTALRM" + def PROF: WSignal = "PROF" + def WINCH: WSignal = "WINCH" + def INFO: WSignal = "INFO" + def USR1: WSignal = "USR1" + def USR2: WSignal = "USR2" /** Given a number of seconds, a signal, and a function: sets up a handler which upon * receiving the signal once, calls the function with argument true, and if the * signal is received again within the allowed time, calls it with argument false. * (Otherwise it calls it with true and starts the timer over again.) */ - def requireInterval(seconds: Int, wrapper: SignalWrapper)(fn: Boolean => Unit) = { + def requireInterval(seconds: Int, wrapper: WSignal)(fn: Boolean => Unit) = { var received = false - wrapper add { + wrapper setTo { if (received) fn(false) else { received = true @@ -96,5 +197,3 @@ object SignalManager extends SignalManager { } } } - -*/ |