More work in progress.
[tripe-android] / sys.scala
index cf0a72d..51ac170 100644 (file)
--- 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("<unknown>", code, code);
+         extends Val("<unknown>", 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;