]> granicus.if.org Git - python/commitdiff
Fix issue 18931: selectors module now supports /dev/poll on Solaris.
authorGiampaolo Rodola' <g.rodola@gmail.com>
Thu, 20 Mar 2014 20:43:41 +0000 (21:43 +0100)
committerGiampaolo Rodola' <g.rodola@gmail.com>
Thu, 20 Mar 2014 20:43:41 +0000 (21:43 +0100)
Doc/library/selectors.rst
Lib/selectors.py
Lib/test/test_selectors.py
Misc/NEWS

index 98377c890f024220b4e652608cd56e21de6b86ac..980a398c28936787267ba4fdd2c82b8c7d384de4 100644 (file)
@@ -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()
 
index 9be9225537f0baf5383f96f202366eecf0e1e232..4e9ae6ec3f48bb36ccc27e70cf85c6ade7a11859 100644 (file)
@@ -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:
index 34edd7630ddd89ac68eee60f7ea50f45894597e0..8f83c90a7ad169e7b562183c7a3a0b03f5e6df9d 100644 (file)
@@ -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()
 
index 479102f31cb037e1f3606cb3254c1a45e0b92db9..7d1a9d804ffdc03b53d69ccaf61493940c283b50 100644 (file)
--- 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.