X-Git-Url: http://www.chiark.greenend.org.uk/ucgi/~mdw/git/tripe-android/blobdiff_plain/68df6e8f5b575d7b737733339339b3b05ecc72a3..04a5abaece151705e9bd7026653f79938a7a2fbc:/sys.scala diff --git a/sys.scala b/sys.scala index cf0a72d..51ac170 100644 --- a/sys.scala +++ b/sys.scala @@ -175,23 +175,23 @@ object Errno extends Enumeration { private var wrong = -256; // next synthetic code private def nextwrong: Int = { val w = wrong; wrong -= 1; w } - class Type private[Errno](tag: String, val code: Int, id: Int) - extends Val(id, tag) { + class Val private[Errno](tag: String, val code: Int, id: Int) + extends super.Val(id, tag) { /* Our augmented error type. */ def message: String = strerror(code).toJString; } private class UnknownError(code: Int) - extends Type("", code, code); + extends Val("", code, code); - private def err(tag: String, code: Int): Type = { + private def err(tag: String, code: Int): Val = { /* Construct an error symbol given its tag string and a code number. */ - if (code < 0) new Type(tag, code, code) - else if (seen contains code) new Type(tag, code, nextwrong) - else { seen += code; new Type(tag, code, code) } + if (code < 0) new Val(tag, code, code) + else if (seen contains code) new Val(tag, code, nextwrong) + else { seen += code; new Val(tag, code, code) } } - private def err(tag: String): Type = + private def err(tag: String): Val = err(tag, tagmap.getOrElse(tag, nextwrong)); def byid(id: Int): Value = { @@ -377,7 +377,7 @@ object Errno extends Enumeration { val EHWPOISON = err("EHWPOISON"); /***end***/ } -import Errno.{Type => Errno, EEXIST, EISDIR, ENOENT, ENOTDIR}; +import Errno.{Val => Errno, EEXIST, EISDIR, ENOENT, ENOTDIR}; object SystemError { /* Pattern matching for `SystemError', below. */ @@ -596,7 +596,7 @@ object FileImplicits { /* Constructing names of files in a directory. Honestly, I'm surprised * there isn't a method for this already. */ - def +(sub: String): File = new File(file, sub); + def /(sub: String): File = new File(file, sub); /* Simple file operations. */ def unlink_!() { unlink(file.getPath); } @@ -739,7 +739,7 @@ def freshFile(d: File): File = { /* Make the filename, and try to create the file. If we succeed, we * win. */ - val f = new File(d, b.result); b.clear(); + val f = d/b.result; b.clear(); try { f.mkfile_!(); exit(f); } catch { case SystemError(EEXIST, _) => ok; } } @@ -798,23 +798,81 @@ def runCommand(cmd: String*): (String, String) = { } } +/*----- Interrupt triggers ------------------------------------------------*/ + +private val triggerLock = new Object; +private final val maxTriggers = 2; +private var nTriggers = 0; +private var triggers: List[Wrapper] = Nil; + +@native protected def makeTrigger(): Wrapper; +@native protected def destroyTrigger(trig: Wrapper); +@native protected def resetTrigger(trig: Wrapper); +@native protected def trigger(trig: Wrapper); + +private def getTrigger(): Wrapper = { + triggerLock synchronized { + if (nTriggers == 0) + makeTrigger() + else { + val trig = triggers.head; + triggers = triggers.tail; + nTriggers -= 1; + trig + } + } +} + +private def putTrigger(trig: Wrapper) { + resetTrigger(trig); + triggerLock synchronized { + if (nTriggers >= maxTriggers) + destroyTrigger(trig); + else { + triggers ::= trig; + nTriggers += 1; + } + } +} + +private def withTrigger[T](body: Wrapper => T): T = { + val trig = getTrigger(); + try { body(trig) } + finally { putTrigger(trig); } +} + +def interruptWithTrigger[T](body: Wrapper => T): T = { + /* interruptWithTrigger { TRIG => BODY } + * + * Execute BODY and return its result. If the thread receives an + * interrupt, the trigger TRIG will be pulled. See `interruptably' for the + * full semantics. + */ + + withTrigger { trig => + interruptably { body(trig) } onInterrupt { trigger(trig); } + }; +} + /*----- Connecting to a server --------------------------------------------*/ /* Primitive operations. */ final val CF_CLOSERD = 1; final val CF_CLOSEWR = 2; final val CF_CLOSEMASK = CF_CLOSERD | CF_CLOSEWR; -@native protected def connect(path: CString): Wrapper; +@native protected def connect(path: CString, trig: Wrapper): Wrapper; @native protected def send(conn: Wrapper, buf: CString, - start: Int, len: Int); + start: Int, len: Int, trig: Wrapper); @native protected def recv(conn: Wrapper, buf: CString, - start: Int, len: Int): Int; + start: Int, len: Int, trig: Wrapper): Int; @native def closeconn(conn: Wrapper, how: Int); class Connection(path: String) extends Closeable { /* The underlying primitive connection. */ - private[this] val conn = connect(path.toCString); + private[this] val conn = interruptWithTrigger { trig => + connect(path.toCString, trig); + }; /* Alternative constructors. */ def this(file: File) { this(file.getPath); } @@ -834,7 +892,7 @@ class Connection(path: String) extends Closeable { override def read(buf: Array[Byte]): Int = read(buf, 0, buf.length); override def read(buf: Array[Byte], start: Int, len: Int) = - recv(conn, buf, start, len); + interruptWithTrigger { trig => recv(conn, buf, start, len, trig); }; override def close() { closeconn(conn, CF_CLOSERD); } } lazy val input = new Input; @@ -845,7 +903,7 @@ class Connection(path: String) extends Closeable { override def write(b: Int) { write(Array[Byte](b.toByte), 0, 1); } override def write(buf: Array[Byte]) { write(buf, 0, buf.length); } override def write(buf: Array[Byte], start: Int, len: Int) - { send(conn, buf, start, len); } + { interruptWithTrigger { trig => send(conn, buf, start, len, trig); } } override def close() { closeconn(conn, CF_CLOSEWR); } } lazy val output = new Output;