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 = {
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. */
/* 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); }
/* 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; }
}
}
}
+/*----- 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); }
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;
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;