diff options
author | Giampaolo Rodola <g.rodola@gmail.com> | 2017-05-20 09:34:44 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-20 09:34:44 (GMT) |
commit | 62c7d90b6446288be1a7906581befe3c211fad5f (patch) | |
tree | 701546036e3303958a99485daa6d8ea436819e34 /Lib/selectors.py | |
parent | 753bca3934a7618a4fa96e107ad1c5c18633a683 (diff) | |
download | cpython-62c7d90b6446288be1a7906581befe3c211fad5f.zip cpython-62c7d90b6446288be1a7906581befe3c211fad5f.tar.gz cpython-62c7d90b6446288be1a7906581befe3c211fad5f.tar.bz2 |
#30014: refactor poll-related classes (#1035)
* #30014: refactor poll-related classes so that poll(), epoll() and devpoll() share the same methods for register(), unregister(), close() and select()
* remove unused attribute
* use specific class attributes instead of select.* constants
* have all classes except SelectSelector a _selector attribute
* BaseException -> Exception
* be explicit in defining a close() method only for selectors which have it
* fix AttributeError
Diffstat (limited to 'Lib/selectors.py')
-rw-r--r-- | Lib/selectors.py | 216 |
1 files changed, 84 insertions, 132 deletions
diff --git a/Lib/selectors.py b/Lib/selectors.py index e7bc517..f29d11f 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -339,92 +339,86 @@ class SelectSelector(_BaseSelectorImpl): return ready -if hasattr(select, 'poll'): +class _PollLikeSelector(_BaseSelectorImpl): + """Base class shared between poll, epoll and devpoll selectors.""" + _selector_cls = None - class PollSelector(_BaseSelectorImpl): - """Poll-based selector.""" + def __init__(self): + super().__init__() + self._selector = self._selector_cls() - def __init__(self): - super().__init__() - self._poll = select.poll() + def register(self, fileobj, events, data=None): + key = super().register(fileobj, events, data) + poller_events = 0 + if events & EVENT_READ: + poller_events |= self._EVENT_READ + if events & EVENT_WRITE: + poller_events |= self._EVENT_WRITE + try: + self._selector.register(key.fd, poller_events) + except Exception: + super().unregister(fileobj) + raise + return key - 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._poll.register(key.fd, poll_events) - return key + def unregister(self, fileobj): + key = super().unregister(fileobj) + try: + self._selector.unregister(key.fd) + except OSError: + # This can happen if the FD was closed since it + # was registered. + pass + return key - def unregister(self, fileobj): - key = super().unregister(fileobj) - self._poll.unregister(key.fd) - return key + def select(self, timeout=None): + # This is shared between poll() and epoll(). + # epoll() has a different signature and handling of timeout parameter. + if timeout is None: + timeout = None + elif timeout <= 0: + timeout = 0 + else: + # poll() 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._selector.poll(timeout) + except InterruptedError: + return ready + for fd, event in fd_event_list: + events = 0 + if event & ~self._EVENT_READ: + events |= EVENT_WRITE + if event & ~self._EVENT_WRITE: + events |= EVENT_READ - def select(self, timeout=None): - if timeout is None: - timeout = None - elif timeout <= 0: - timeout = 0 - else: - # poll() 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._poll.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 - key = self._key_from_fd(fd) - if key: - ready.append((key, events & key.events)) - return ready + +if hasattr(select, 'poll'): + + class PollSelector(_PollLikeSelector): + """Poll-based selector.""" + _selector_cls = select.poll + _EVENT_READ = select.POLLIN + _EVENT_WRITE = select.POLLOUT if hasattr(select, 'epoll'): - class EpollSelector(_BaseSelectorImpl): + class EpollSelector(_PollLikeSelector): """Epoll-based selector.""" - - def __init__(self): - super().__init__() - self._epoll = select.epoll() + _selector_cls = select.epoll + _EVENT_READ = select.EPOLLIN + _EVENT_WRITE = select.EPOLLOUT 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 - try: - self._epoll.register(key.fd, epoll_events) - except BaseException: - super().unregister(fileobj) - raise - return key - - def unregister(self, fileobj): - key = super().unregister(fileobj) - try: - self._epoll.unregister(key.fd) - except OSError: - # This can happen if the FD was closed since it - # was registered. - pass - return key + return self._selector.fileno() def select(self, timeout=None): if timeout is None: @@ -443,7 +437,7 @@ if hasattr(select, 'epoll'): ready = [] try: - fd_event_list = self._epoll.poll(timeout, max_ev) + fd_event_list = self._selector.poll(timeout, max_ev) except InterruptedError: return ready for fd, event in fd_event_list: @@ -459,65 +453,23 @@ if hasattr(select, 'epoll'): return ready def close(self): - self._epoll.close() + self._selector.close() super().close() if hasattr(select, 'devpoll'): - class DevpollSelector(_BaseSelectorImpl): + class DevpollSelector(_PollLikeSelector): """Solaris /dev/poll selector.""" - - def __init__(self): - super().__init__() - self._devpoll = select.devpoll() + _selector_cls = select.devpoll + _EVENT_READ = select.POLLIN + _EVENT_WRITE = select.POLLOUT 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 + return self._selector.fileno() def close(self): - self._devpoll.close() + self._selector.close() super().close() @@ -528,10 +480,10 @@ if hasattr(select, 'kqueue'): def __init__(self): super().__init__() - self._kqueue = select.kqueue() + self._selector = select.kqueue() def fileno(self): - return self._kqueue.fileno() + return self._selector.fileno() def register(self, fileobj, events, data=None): key = super().register(fileobj, events, data) @@ -539,12 +491,12 @@ if hasattr(select, 'kqueue'): if events & EVENT_READ: kev = select.kevent(key.fd, select.KQ_FILTER_READ, select.KQ_EV_ADD) - self._kqueue.control([kev], 0, 0) + self._selector.control([kev], 0, 0) if events & EVENT_WRITE: kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, select.KQ_EV_ADD) - self._kqueue.control([kev], 0, 0) - except BaseException: + self._selector.control([kev], 0, 0) + except Exception: super().unregister(fileobj) raise return key @@ -555,7 +507,7 @@ if hasattr(select, 'kqueue'): kev = select.kevent(key.fd, select.KQ_FILTER_READ, select.KQ_EV_DELETE) try: - self._kqueue.control([kev], 0, 0) + self._selector.control([kev], 0, 0) except OSError: # This can happen if the FD was closed since it # was registered. @@ -564,7 +516,7 @@ if hasattr(select, 'kqueue'): kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, select.KQ_EV_DELETE) try: - self._kqueue.control([kev], 0, 0) + self._selector.control([kev], 0, 0) except OSError: # See comment above. pass @@ -575,7 +527,7 @@ if hasattr(select, 'kqueue'): max_ev = len(self._fd_to_key) ready = [] try: - kev_list = self._kqueue.control(None, max_ev, timeout) + kev_list = self._selector.control(None, max_ev, timeout) except InterruptedError: return ready for kev in kev_list: @@ -593,7 +545,7 @@ if hasattr(select, 'kqueue'): return ready def close(self): - self._kqueue.close() + self._selector.close() super().close() |