summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGiampaolo Rodola' <g.rodola@gmail.com>2014-03-20 20:43:41 (GMT)
committerGiampaolo Rodola' <g.rodola@gmail.com>2014-03-20 20:43:41 (GMT)
commitf97e82937f8a4e14df939007abacfa252ad09fc8 (patch)
treed771b2bbbcbaffcebbdc8988e572bdb7e2fdbcd5
parent5782e25dfe401dddfde091417c977b44e4442cb6 (diff)
downloadcpython-f97e82937f8a4e14df939007abacfa252ad09fc8.zip
cpython-f97e82937f8a4e14df939007abacfa252ad09fc8.tar.gz
cpython-f97e82937f8a4e14df939007abacfa252ad09fc8.tar.bz2
Fix issue 18931: selectors module now supports /dev/poll on Solaris.
-rw-r--r--Doc/library/selectors.rst11
-rw-r--r--Lib/selectors.py62
-rw-r--r--Lib/test/test_selectors.py10
-rw-r--r--Misc/NEWS3
4 files changed, 84 insertions, 2 deletions
diff --git a/Doc/library/selectors.rst b/Doc/library/selectors.rst
index 98377c8..980a398 100644
--- a/Doc/library/selectors.rst
+++ b/Doc/library/selectors.rst
@@ -45,6 +45,7 @@ Classes hierarchy::
+-- SelectSelector
+-- PollSelector
+-- EpollSelector
+ +-- DevpollSelector
+-- KqueueSelector
@@ -207,6 +208,16 @@ below:
This returns the file descriptor used by the underlying
:func:`select.epoll` object.
+.. class:: DevpollSelector()
+
+ :func:`select.devpoll`-based selector.
+
+ .. method:: fileno()
+
+ This returns the file descriptor used by the underlying
+ :func:`select.devpoll` object.
+
+.. versionadded:: 3.5
.. class:: KqueueSelector()
diff --git a/Lib/selectors.py b/Lib/selectors.py
index 9be9225..4e9ae6e 100644
--- a/Lib/selectors.py
+++ b/Lib/selectors.py
@@ -441,6 +441,64 @@ if hasattr(select, 'epoll'):
super().close()
+if hasattr(select, 'devpoll'):
+
+ class DevpollSelector(_BaseSelectorImpl):
+ """Solaris /dev/poll selector."""
+
+ def __init__(self):
+ super().__init__()
+ self._devpoll = select.devpoll()
+
+ def fileno(self):
+ return self._devpoll.fileno()
+
+ def register(self, fileobj, events, data=None):
+ key = super().register(fileobj, events, data)
+ poll_events = 0
+ if events & EVENT_READ:
+ poll_events |= select.POLLIN
+ if events & EVENT_WRITE:
+ poll_events |= select.POLLOUT
+ self._devpoll.register(key.fd, poll_events)
+ return key
+
+ def unregister(self, fileobj):
+ key = super().unregister(fileobj)
+ self._devpoll.unregister(key.fd)
+ return key
+
+ def select(self, timeout=None):
+ if timeout is None:
+ timeout = None
+ elif timeout <= 0:
+ timeout = 0
+ else:
+ # devpoll() has a resolution of 1 millisecond, round away from
+ # zero to wait *at least* timeout seconds.
+ timeout = math.ceil(timeout * 1e3)
+ ready = []
+ try:
+ fd_event_list = self._devpoll.poll(timeout)
+ except InterruptedError:
+ return ready
+ for fd, event in fd_event_list:
+ events = 0
+ if event & ~select.POLLIN:
+ events |= EVENT_WRITE
+ if event & ~select.POLLOUT:
+ events |= EVENT_READ
+
+ key = self._key_from_fd(fd)
+ if key:
+ ready.append((key, events & key.events))
+ return ready
+
+ def close(self):
+ self._devpoll.close()
+ super().close()
+
+
if hasattr(select, 'kqueue'):
class KqueueSelector(_BaseSelectorImpl):
@@ -513,12 +571,14 @@ if hasattr(select, 'kqueue'):
super().close()
-# Choose the best implementation: roughly, epoll|kqueue > poll > select.
+# Choose the best implementation: roughly, epoll|kqueue|devpoll > poll > select.
# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
if 'KqueueSelector' in globals():
DefaultSelector = KqueueSelector
elif 'EpollSelector' in globals():
DefaultSelector = EpollSelector
+elif 'DevpollSelector' in globals():
+ DefaultSelector = DevpollSelector
elif 'PollSelector' in globals():
DefaultSelector = PollSelector
else:
diff --git a/Lib/test/test_selectors.py b/Lib/test/test_selectors.py
index 34edd76..8f83c90 100644
--- a/Lib/test/test_selectors.py
+++ b/Lib/test/test_selectors.py
@@ -441,10 +441,18 @@ class KqueueSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
SELECTOR = getattr(selectors, 'KqueueSelector', None)
+@unittest.skipUnless(hasattr(selectors, 'DevpollSelector'),
+ "Test needs selectors.DevpollSelector")
+class DevpollSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):
+
+ SELECTOR = getattr(selectors, 'DevpollSelector', None)
+
+
+
def test_main():
tests = [DefaultSelectorTestCase, SelectSelectorTestCase,
PollSelectorTestCase, EpollSelectorTestCase,
- KqueueSelectorTestCase]
+ KqueueSelectorTestCase, DevpollSelectorTestCase]
support.run_unittest(*tests)
support.reap_children()
diff --git a/Misc/NEWS b/Misc/NEWS
index 479102f..7d1a9d8 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -23,6 +23,9 @@ Core and Builtins
Library
-------
+- Issue 18931: selectors module now supports /dev/poll on Solaris.
+ Patch by Giampaolo Rodola'.
+
- Issue #19977: When the ``LC_TYPE`` locale is the POSIX locale (``C`` locale),
:py:data:`sys.stdin` and :py:data:`sys.stdout` are now using the
``surrogateescape`` error handler, instead of the ``strict`` error handler.