@@ -49,7 +49,8 @@ ovs_pytests = \
python/ovs/tests/test_kv.py \
python/ovs/tests/test_list.py \
python/ovs/tests/test_odp.py \
- python/ovs/tests/test_ofp.py
+ python/ovs/tests/test_ofp.py \
+ python/ovs/tests/test_poller.py
ovs_flowviz = \
python/ovs/flowviz/__init__.py \
@@ -110,9 +110,23 @@ class _SelectSelect(object):
SelectPoll = _SelectSelect
-# If eventlet/gevent isn't used, we can use select.poll by replacing
-# _SelectPoll with select.poll class
-# _SelectPoll = select.poll
+
+
+def _get_poll():
+ """Return a poll object suitable for the current environment.
+
+ Under eventlet or gevent, select.select is replaced by a green
+ implementation that multiplexes through the hub. _SelectSelect is
+ therefore both cooperative and free of the FD_SETSIZE limit there, so
+ keep using it. Everywhere else select.select is the real select(2),
+ which cannot handle a file descriptor numbered FD_SETSIZE or higher, so
+ use poll(2), which has no such limit.
+ """
+ if _using_eventlet_green_select() or (
+ gevent_monkey and
+ gevent_monkey.is_object_patched('select', 'select')):
+ return _SelectSelect()
+ return select.poll()
class Poller(object):
@@ -220,7 +234,7 @@ class Poller(object):
vlog.dbg("%s on fd %d" % (s, fd))
def __reset(self):
- self.poll = SelectPoll()
+ self.poll = _get_poll()
self.timeout = -1
new file mode 100644
@@ -0,0 +1,44 @@
+import select
+
+from unittest import mock
+
+import ovs.poller
+
+# select.poll is a builtin function, not a type, so capture the type of the
+# object it returns in order to be able to assert on it.
+POLL_TYPE = type(select.poll())
+
+
+def test_poller_uses_poll_by_default():
+ """Poller must use poll(2) when select.select is the real select(2).
+
+ select(2) raises ValueError for a file descriptor numbered FD_SETSIZE
+ (1024) or higher, poll(2) has no such limit.
+ """
+ with mock.patch.object(ovs.poller, '_using_eventlet_green_select',
+ return_value=False), \
+ mock.patch.object(ovs.poller, 'gevent_monkey', None):
+ assert isinstance(ovs.poller.Poller().poll, POLL_TYPE)
+
+
+def test_poller_uses_select_under_eventlet():
+ """Poller must keep emulating poll with select.select under eventlet.
+
+ The green select has no FD_SETSIZE limit either and, unlike the real
+ poll(2), it yields to the hub instead of blocking the interpreter.
+ """
+ with mock.patch.object(ovs.poller, '_using_eventlet_green_select',
+ return_value=True):
+ assert isinstance(ovs.poller.Poller().poll, ovs.poller._SelectSelect)
+
+
+def test_poller_uses_select_under_gevent():
+ """Same as under eventlet, for a gevent patched select.select."""
+ gevent_monkey = mock.Mock()
+ gevent_monkey.is_object_patched.return_value = True
+ with mock.patch.object(ovs.poller, '_using_eventlet_green_select',
+ return_value=False), \
+ mock.patch.object(ovs.poller, 'gevent_monkey', gevent_monkey):
+ assert isinstance(ovs.poller.Poller().poll, ovs.poller._SelectSelect)
+ gevent_monkey.is_object_patched.assert_called_once_with('select',
+ 'select')