-# 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
+
+try:
+ import eventlet.patcher
+
+ def _using_eventlet_green_select():
+ return eventlet.patcher.is_monkey_patched(select)
+except:
+ def _using_eventlet_green_select():
+ return False
+
+vlog = ovs.vlog.Vlog("poller")
+
+POLLIN = 0x001
+POLLOUT = 0x004
+POLLERR = 0x008
+POLLHUP = 0x010
+POLLNVAL = 0x020
+
+# 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 & POLLIN:
+ self.rlist.append(fd)
+ events &= ~POLLIN
+ if events & POLLOUT:
+ self.wlist.append(fd)
+ events &= ~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
+ # XXX workaround a bug in eventlet
+ # see https://github.com/eventlet/eventlet/pull/25
+ if timeout == 0 and _using_eventlet_green_select():
+ timeout = 0.1
+
+ 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) | POLLIN
+ for fd in wlist:
+ events_dict[fd] = events_dict.get(fd, 0) | POLLOUT
+ for fd in xlist:
+ events_dict[fd] = events_dict.get(fd, 0) | (POLLERR |
+ POLLHUP |
+ 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.
be select.POLLIN or select.POLLOUT or their bitwise-OR). The following
call to self.block() will wake up when 'fd' becomes ready for one or
more of the requested events.
-
+
The event registration is one-shot: only the following call to
self.block() is affected. The event will need to be re-registered
after self.block() is called if it is to persist.
self.__timer_wait(msec)
def timer_wait_until(self, msec):
- """Causes the following call to self.block() to wake up when the current
- time, as returned by ovs.timeval.msec(), reaches 'msec' or later. If
- 'msec' is earlier than the current time, the following call to
- self.block() will not block at all.
+ """Causes the following call to self.block() to wake up when the
+ current time, as returned by ovs.timeval.msec(), reaches 'msec' or
+ later. If 'msec' is earlier than the current time, the following call
+ to self.block() will not block at all.
The timer registration is one-shot: only the following call to
self.block() is affected. The timer will need to be re-registered
# 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:
s = ""
- if revents & select.POLLIN:
+ if revents & POLLIN:
s += "[POLLIN]"
- if revents & select.POLLOUT:
+ if revents & POLLOUT:
s += "[POLLOUT]"
- if revents & select.POLLERR:
+ if revents & POLLERR:
s += "[POLLERR]"
- if revents & select.POLLHUP:
+ if revents & POLLHUP:
s += "[POLLHUP]"
- if revents & select.POLLNVAL:
+ if revents & 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.timeout = -1
-
+ self.poll = SelectPoll()
+ self.timeout = -1