diff --git a/Doc/library/selectors.rst b/Doc/library/selectors.rst --- a/Doc/library/selectors.rst +++ b/Doc/library/selectors.rst @@ -44,6 +44,7 @@ BaseSelector +-- SelectSelector +-- PollSelector + +-- DevpollSelector +-- EpollSelector +-- KqueueSelector @@ -182,6 +183,11 @@ :func:`select.poll`-based selector. +.. class:: DevpollSelector() + + :func:`select.devpoll`-based selector. + + .. class:: EpollSelector() :func:`select.epoll`-based selector. diff --git a/Lib/selectors.py b/Lib/selectors.py --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -234,14 +234,16 @@ return ready -if hasattr(select, 'poll'): +if hasattr(select, 'poll') or hasattr(select, 'epoll') \ + or hasattr(select, 'devpoll'): - class PollSelector(BaseSelector): - """Poll-based selector.""" + class _BasePollSelector(BaseSelector): + _POLLIN = select.POLLIN + _POLLOUT = select.POLLOUT def __init__(self): super().__init__() - self._poll = select.poll() + self._poller = self._poller() def register(self, fileobj, events, data=None): key = super().register(fileobj, events, data) @@ -250,26 +252,26 @@ poll_events |= select.POLLIN if events & EVENT_WRITE: poll_events |= select.POLLOUT - self._poll.register(key.fd, poll_events) + self._poller.register(key.fd, poll_events) return key def unregister(self, fileobj): key = super().unregister(fileobj) - self._poll.unregister(key.fd) + self._poller.unregister(key.fd) return key def select(self, timeout=None): timeout = None if timeout is None else max(int(1000 * timeout), 0) ready = [] try: - fd_event_list = self._poll.poll(timeout) + fd_event_list = self._poller.poll(timeout) except InterruptedError: return ready for fd, event in fd_event_list: events = 0 - if event & ~select.POLLIN: + if event & ~self._POLLIN: events |= EVENT_WRITE - if event & ~select.POLLOUT: + if event & ~self._POLLOUT: events |= EVENT_READ key = self._key_from_fd(fd) @@ -278,46 +280,44 @@ return ready +if hasattr(select, 'poll'): + + class PollSelector(_BasePollSelector): + """Poll-based selector.""" + _poller = select.poll + + +if hasattr(select, 'devpoll'): + + class DevpollSelector(_BasePollSelector): + """Devpoll-based selector.""" + _poller = select.devpoll + + if hasattr(select, 'epoll'): - class EpollSelector(BaseSelector): + class EpollSelector(_BasePollSelector): """Epoll-based selector.""" - - def __init__(self): - super().__init__() - self._epoll = select.epoll() + _POLLIN = select.EPOLLIN + _POLLOUT = select.EPOLLOUT + _poller = select.epoll def fileno(self): - return self._epoll.fileno() - - def register(self, fileobj, events, data=None): - key = super().register(fileobj, events, data) - epoll_events = 0 - if events & EVENT_READ: - epoll_events |= select.EPOLLIN - if events & EVENT_WRITE: - epoll_events |= select.EPOLLOUT - self._epoll.register(key.fd, epoll_events) - return key - - def unregister(self, fileobj): - key = super().unregister(fileobj) - self._epoll.unregister(key.fd) - return key + return self._poller.fileno() def select(self, timeout=None): timeout = -1 if timeout is None else max(timeout, 0) max_ev = len(self._fd_to_key) ready = [] try: - fd_event_list = self._epoll.poll(timeout, max_ev) + fd_event_list = self._poller.poll(timeout, max_ev) except InterruptedError: return ready for fd, event in fd_event_list: events = 0 - if event & ~select.EPOLLIN: + if event & ~self._POLLIN: events |= EVENT_WRITE - if event & ~select.EPOLLOUT: + if event & ~self._POLLOUT: events |= EVENT_READ key = self._key_from_fd(fd) @@ -327,7 +327,7 @@ def close(self): super().close() - self._epoll.close() + self._poller.close() if hasattr(select, 'kqueue'): @@ -399,6 +399,8 @@ 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 --- a/Lib/test/test_selectors.py +++ b/Lib/test/test_selectors.py @@ -364,6 +364,13 @@ SELECTOR = getattr(selectors, 'PollSelector', None) +@unittest.skipUnless(hasattr(selectors, 'DevpollSelector'), + "Test needs selectors.DevpollSelector") +class DevpollSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn): + + SELECTOR = getattr(selectors, 'DevpollSelector', None) + + @unittest.skipUnless(hasattr(selectors, 'EpollSelector'), "Test needs selectors.EpollSelector") class EpollSelectorTestCase(BaseSelectorTestCase, ScalableSelectorMixIn):