|
| 1 | +/* NSC -- new Scala compiler |
| 2 | + * Copyright 2005-2010 LAMP/EPFL |
| 3 | + * @author Paul Phillips |
| 4 | + */ |
| 5 | + |
| 6 | +package scala.tools |
| 7 | +package util |
| 8 | + |
| 9 | +import sun.misc.{ Signal, SignalHandler } |
| 10 | +import SignalHandler._ |
| 11 | +import nsc.io.timer |
| 12 | + |
| 13 | +/** Unofficial signal handling code. According to sun it's unsupported, |
| 14 | + * but it's too useful not to take advantage of. Degrade gracefully. |
| 15 | + */ |
| 16 | +class SignalManager { |
| 17 | + def apply(name: String): SignalWrapper = |
| 18 | + try { new SignalWrapper(new Signal(name)) } |
| 19 | + catch { case x: IllegalArgumentException => new SignalError(x.getMessage) } |
| 20 | + |
| 21 | + class ChainedHandler(prev: SignalHandler, current: SignalHandler) extends SignalHandler { |
| 22 | + def handle(sig: Signal): Unit = { |
| 23 | + current handle sig |
| 24 | + if (prev != SIG_DFL && prev != SIG_IGN) |
| 25 | + prev handle sig |
| 26 | + } |
| 27 | + } |
| 28 | + class SignalWrapper(val signal: Signal) { |
| 29 | + def name = signal.getName |
| 30 | + def add(body: => Unit) = { |
| 31 | + val handler = new SignalHandler { def handle(sig: Signal) = body } |
| 32 | + val prev = Signal.handle(signal, handler) |
| 33 | + |
| 34 | + new ChainedHandler(prev, handler) |
| 35 | + } |
| 36 | + override def toString = "SIG" + name |
| 37 | + } |
| 38 | + class SignalError(message: String) extends SignalWrapper(null) { |
| 39 | + override def toString = message |
| 40 | + } |
| 41 | +} |
| 42 | + |
| 43 | +object SignalManager extends SignalManager { |
| 44 | + private implicit def mkSignalWrapper(name: String): SignalWrapper = this(name) |
| 45 | + |
| 46 | + def HUP: SignalWrapper = "HUP" |
| 47 | + def INT: SignalWrapper = "INT" |
| 48 | + def QUIT: SignalWrapper = "QUIT" |
| 49 | + def ILL: SignalWrapper = "ILL" |
| 50 | + def TRAP: SignalWrapper = "TRAP" |
| 51 | + def ABRT: SignalWrapper = "ABRT" |
| 52 | + def EMT: SignalWrapper = "EMT" |
| 53 | + def FPE: SignalWrapper = "FPE" |
| 54 | + def KILL: SignalWrapper = "KILL" |
| 55 | + def BUS: SignalWrapper = "BUS" |
| 56 | + def SEGV: SignalWrapper = "SEGV" |
| 57 | + def SYS: SignalWrapper = "SYS" |
| 58 | + def PIPE: SignalWrapper = "PIPE" |
| 59 | + def ALRM: SignalWrapper = "ALRM" |
| 60 | + def TERM: SignalWrapper = "TERM" |
| 61 | + def URG: SignalWrapper = "URG" |
| 62 | + def STOP: SignalWrapper = "STOP" |
| 63 | + def TSTP: SignalWrapper = "TSTP" |
| 64 | + def CONT: SignalWrapper = "CONT" |
| 65 | + def CHLD: SignalWrapper = "CHLD" |
| 66 | + def TTIN: SignalWrapper = "TTIN" |
| 67 | + def TTOU: SignalWrapper = "TTOU" |
| 68 | + def IO: SignalWrapper = "IO" |
| 69 | + def XCPU: SignalWrapper = "XCPU" |
| 70 | + def XFSZ: SignalWrapper = "XFSZ" |
| 71 | + def VTALRM: SignalWrapper = "VTALRM" |
| 72 | + def PROF: SignalWrapper = "PROF" |
| 73 | + def WINCH: SignalWrapper = "WINCH" |
| 74 | + def INFO: SignalWrapper = "INFO" |
| 75 | + def USR1: SignalWrapper = "USR1" |
| 76 | + def USR2: SignalWrapper = "USR2" |
| 77 | + |
| 78 | + /** Given a number of seconds, a signal, and a function: sets up a handler which upon |
| 79 | + * receiving the signal once, calls the function with argument true, and if the |
| 80 | + * signal is received again within the allowed time, calls it with argument false. |
| 81 | + * (Otherwise it calls it with true and starts the timer over again.) |
| 82 | + */ |
| 83 | + def requireInterval(seconds: Int, wrapper: SignalWrapper)(fn: Boolean => Unit) = { |
| 84 | + var received = false |
| 85 | + wrapper add { |
| 86 | + if (received) fn(false) |
| 87 | + else { |
| 88 | + received = true |
| 89 | + fn(true) |
| 90 | + timer(seconds)(received = false) |
| 91 | + } |
| 92 | + } |
| 93 | + } |
| 94 | +} |
| 95 | + |
| 96 | + |
| 97 | + |
0 commit comments