python/ovs/poller: use select.select instead of select.poll.
authorIsaku Yamahata <yamahata@valinux.co.jp>
Wed, 5 Sep 2012 10:38:26 +0000 (19:38 +0900)
committerBen Pfaff <blp@nicira.com>
Wed, 5 Sep 2012 16:10:44 +0000 (09:10 -0700)
eventlet/gevent doesn't work well with select.poll because select.poll blocks
python interpreter as a whole instead of switching from the current thread
which is about to block to other runnable thread.
So ovsdb python binding can't be used with eventlet/gevent.
Emulate select.poll with select.select because using python means that
performance isn't so important.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
Signed-off-by: Ben Pfaff <blp@nicira.com>
python/ovs/poller.py

index e459c58..5c89f23 100644 (file)
 # limitations under the License.
 
 import errno
-import select
 import ovs.timeval
 import ovs.vlog
+import select
+import socket
 
 vlog = ovs.vlog.Vlog("poller")
 
 
+# eventlet/gevent doesn't support select.poll. If select.poll is used,
+# python interpreter is blocked as a whole instead of switching from the
+# current thread that is about to block to other runnable thread.
+# So emulate select.poll by select.select because using python means that
+# performance isn't so important.
+class _SelectSelect(object):
+    """ select.poll emulation by using select.select.
+    Only register and poll are needed at the moment.
+    """
+    def __init__(self):
+        self.rlist = []
+        self.wlist = []
+        self.xlist = []
+
+    def register(self, fd, events):
+        if isinstance(fd, socket.socket):
+            fd = fd.fileno()
+        assert isinstance(fd, int)
+        if events & select.POLLIN:
+            self.rlist.append(fd)
+            events &= ~select.POLLIN
+        if events & select.POLLOUT:
+            self.wlist.append(fd)
+            events &= ~select.POLLOUT
+        if events:
+            self.xlist.append(fd)
+
+    def poll(self, timeout):
+        if timeout == -1:
+            # epoll uses -1 for infinite timeout, select uses None.
+            timeout = None
+        else:
+            timeout = float(timeout) / 1000
+
+        rlist, wlist, xlist = select.select(self.rlist, self.wlist, self.xlist,
+                                            timeout)
+        # collections.defaultdict is introduced by python 2.5 and
+        # XenServer uses python 2.4. We don't use it for XenServer.
+        # events_dict = collections.defaultdict(int)
+        # events_dict[fd] |= event
+        events_dict = {}
+        for fd in rlist:
+            events_dict[fd] = events_dict.get(fd, 0) | select.POLLIN
+        for fd in wlist:
+            events_dict[fd] = events_dict.get(fd, 0) | select.POLLOUT
+        for fd in xlist:
+            events_dict[fd] = events_dict.get(fd, 0) | (select.POLLERR |
+                                                        select.POLLHUP |
+                                                        select.POLLNVAL)
+        return events_dict.items()
+
+
+_SelectPoll = _SelectSelect
+# If eventlet/gevent isn't used, we can use select.poll by replacing
+# _SelectPoll with select.poll class
+# _SelectPoll = select.poll
+
+
 class Poller(object):
     """High-level wrapper around the "poll" system call.
 
@@ -122,5 +181,5 @@ class Poller(object):
                     vlog.dbg("%s on fd %d" % (s, fd))
 
     def __reset(self):
-        self.poll = select.poll()
+        self.poll = _SelectPoll()
         self.timeout = -1