+### I/O loop integration.
+
+class SelIOWatcher (object):
+ """
+ Integration with mLib's I/O event system.
+
+ You can replace this object with a different one for integration with,
+ e.g., glib's main loop, by setting `CONN.iowatcher' to a different object
+ while the CONN is disconnected.
+ """
+
+ def __init__(me, conn):
+ me._conn = conn
+ me._selfile = None
+
+ def connected(me, sock):
+ """
+ Called when a connection is made.
+
+ SOCK is the socket. The watcher must arrange to call `CONN.receive' when
+ data is available.
+ """
+ me._selfile = M.SelFile(sock.fileno(), M.SEL_READ, me._conn.receive)
+ me._selfile.enable()
+
+ def disconnected(me):
+ """
+ Called when the connection is lost.
+ """
+ me._selfile = None
+
+ def iterate(me):
+ """
+ Wait for something interesting to happen, and issue events.
+
+ That is, basically, do one iteration of a main select loop, processing
+ all of the events, and then return. This is used in the method
+ `TripeCommandDispatcher.mainloop', but that's mostly for the benefit of
+ `runservices'; if your I/O watcher has a different main loop, you can
+ drive it yourself.
+ """
+ M.select()
+
+###--------------------------------------------------------------------------
+### Inter-coroutine communication.
+
+class Queue (object):
+ """
+ A queue of things arriving asynchronously.
+
+ This is a very simple single-reader multiple-writer queue. It's useful for
+ more complex coroutines which need to cope with a variety of possible
+ incoming events.
+ """
+
+ def __init__(me):
+ """Create a new empty queue."""
+ me.contents = M.Array()
+ me.waiter = None
+
+ def _wait(me):
+ """
+ Internal: wait for an item to arrive in the queue.
+
+ Complain if someone is already waiting, because this is just a
+ single-reader queue.
+ """
+ if me.waiter:
+ raise ValueError('queue already being waited on')
+ try:
+ me.waiter = Coroutine.getcurrent()
+ while not me.contents:
+ me.waiter.parent.switch()
+ finally:
+ me.waiter = None
+
+ def get(me):
+ """
+ Remove and return the item at the head of the queue.
+
+ If the queue is empty, wait until an item arrives.
+ """
+ me._wait()
+ return me.contents.shift()
+
+ def peek(me):
+ """
+ Return the item at the head of the queue without removing it.
+
+ If the queue is empty, wait until an item arrives.
+ """
+ me._wait()
+ return me.contents[0]
+
+ def put(me, thing):
+ """
+ Write THING to the queue.
+
+ If someone is waiting on the queue, wake him up immediately; otherwise
+ just leave the item there for later.
+ """
+ me.contents.push(thing)
+ if me.waiter:
+ me.waiter.switch()
+
+###--------------------------------------------------------------------------