diff options
Diffstat (limited to 'Lib/selectors.py')
| -rw-r--r-- | Lib/selectors.py | 92 |
1 files changed, 73 insertions, 19 deletions
diff --git a/Lib/selectors.py b/Lib/selectors.py index 7b6da29863..e17ea363c8 100644 --- a/Lib/selectors.py +++ b/Lib/selectors.py @@ -174,9 +174,9 @@ class BaseSelector(metaclass=ABCMeta): SelectorKey for this file object """ mapping = self.get_map() + if mapping is None: + raise RuntimeError('Selector is closed') try: - if mapping is None: - raise KeyError return mapping[fileobj] except KeyError: raise KeyError("{!r} is not registered".format(fileobj)) from None @@ -310,10 +310,7 @@ class SelectSelector(_BaseSelectorImpl): def select(self, timeout=None): timeout = None if timeout is None else max(timeout, 0) ready = [] - try: - r, w, _ = self._select(self._readers, self._writers, [], timeout) - except InterruptedError: - return ready + r, w, _ = self._select(self._readers, self._writers, [], timeout) r = set(r) w = set(w) for fd in r | w: @@ -362,11 +359,10 @@ if hasattr(select, 'poll'): # poll() has a resolution of 1 millisecond, round away from # zero to wait *at least* timeout seconds. timeout = math.ceil(timeout * 1e3) + + fd_event_list = self._poll.poll(timeout) + 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: @@ -427,11 +423,9 @@ if hasattr(select, 'epoll'): # FD is registered. max_ev = max(len(self._fd_to_key), 1) + fd_event_list = self._epoll.poll(timeout, max_ev) + ready = [] - try: - fd_event_list = self._epoll.poll(timeout, max_ev) - except InterruptedError: - return ready for fd, event in fd_event_list: events = 0 if event & ~select.EPOLLIN: @@ -451,6 +445,65 @@ 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) + + fd_event_list = self._devpoll.poll(timeout) + + 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): + try: + self._devpoll.close() + finally: + super().close() + + if hasattr(select, 'kqueue'): class KqueueSelector(_BaseSelectorImpl): @@ -499,11 +552,9 @@ if hasattr(select, 'kqueue'): def select(self, timeout=None): timeout = None if timeout is None else max(timeout, 0) max_ev = len(self._fd_to_key) + kev_list = self._kqueue.control(None, max_ev, timeout) + ready = [] - try: - kev_list = self._kqueue.control(None, max_ev, timeout) - except InterruptedError: - return ready for kev in kev_list: fd = kev.ident flag = kev.filter @@ -525,12 +576,15 @@ 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: |
