factor out EventDescriptor from Controller
diff --git a/src/python/oftest/controller.py b/src/python/oftest/controller.py
index 2492fd2..d63519d 100644
--- a/src/python/oftest/controller.py
+++ b/src/python/oftest/controller.py
@@ -105,8 +105,8 @@
         self.connect_cv = Condition()
         self.message_cv = Condition()
 
-        # Pipe used to wake up event loop
-        self.pipe_rd, self.pipe_wr = os.pipe()
+        # Used to wake up the event loop from another thread
+        self.waker = EventDescriptor()
 
         # Counters
         self.socket_errors = 0
@@ -329,8 +329,8 @@
                 return -1
 
             self._pkt_handle(pkt)
-        elif s and s == self.pipe_rd:
-            os.read(s, 1)
+        elif s and s == self.waker:
+            self.waker.wait()
         else:
             self.logger.error("Unknown socket ready: " + str(s))
             return -1
@@ -359,13 +359,13 @@
         """
         Wake up the event loop, presumably from another thread.
         """
-        os.write(self.pipe_wr, "x")
+        self.waker.notify()
 
     def sockets(self):
         """
         Return list of sockets to select on.
         """
-        socs = [self.listen_socket, self.switch_socket, self.pipe_rd]
+        socs = [self.listen_socket, self.switch_socket, self.waker]
         return [x for x in socs if x]
 
     def run(self):
diff --git a/src/python/oftest/ofutils.py b/src/python/oftest/ofutils.py
index 219ce4f..a75d266 100644
--- a/src/python/oftest/ofutils.py
+++ b/src/python/oftest/ofutils.py
@@ -5,6 +5,7 @@
 
 import random
 import time
+import os
 
 default_timeout = None # set by oft
 
@@ -34,3 +35,25 @@
 
         if time.time() > end_time:
             return None
+
+class EventDescriptor():
+    """
+    Similar to a condition variable, but can be passed to select().
+    Only supports one waiter.
+    """
+
+    def __init__(self):
+        self.pipe_rd, self.pipe_wr = os.pipe()
+
+    def __del__(self):
+        os.close(self.pipe_rd)
+        os.close(self.pipe_wr)
+
+    def notify(self):
+        os.write(self.pipe_wr, "x")
+
+    def wait(self):
+        os.read(self.pipe_rd, 1)
+
+    def fileno(self):
+        return self.pipe_rd