python/ovs: socket_util uses select.poll
[sliver-openvswitch.git] / python / ovs / poller.py
index aea3546..c04c9b3 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (c) 2010 Nicira Networks
+# Copyright (c) 2010 Nicira, Inc.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # limitations under the License.
 
 import errno
-import logging
-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):
@@ -96,13 +157,13 @@ class Poller(object):
                 # XXX rate-limit
                 error, msg = e
                 if error != errno.EINTR:
-                    logging.error("poll: %s" % e[1])
+                    vlog.err("poll: %s" % e[1])
         finally:
             self.__reset()
 
     def __log_wakeup(self, events):
         if not events:
-            logging.debug("%d-ms timeout" % self.timeout)
+            vlog.dbg("%d-ms timeout" % self.timeout)
         else:
             for fd, revents in events:
                 if revents != 0:
@@ -117,8 +178,8 @@ class Poller(object):
                         s += "[POLLHUP]"
                     if revents & select.POLLNVAL:
                         s += "[POLLNVAL]"
-                    logging.debug("%s on fd %d" % (s, fd))
+                    vlog.dbg("%s on fd %d" % (s, fd))
 
     def __reset(self):
-        self.poll = select.poll()
+        self.poll = SelectPoll()
         self.timeout = -1