diff -r 62b322b82f00 Lib/selectors.py --- a/Lib/selectors.py Thu Feb 05 17:24:00 2015 +1100 +++ b/Lib/selectors.py Thu Feb 05 10:00:17 2015 +0100 @@ -241,19 +241,24 @@ class _BaseSelectorImpl(BaseSelector): raise KeyError("{!r} is not registered".format(fileobj)) from None return key + def _modify(self, fileobj, events, data): + self.unregister(fileobj) + return self.register(fileobj, events, data) + def modify(self, fileobj, events, data=None): - # TODO: Subclasses can probably optimize this even further. + fd = self._fileobj_lookup(fileobj) try: - key = self._fd_to_key[self._fileobj_lookup(fileobj)] + oldkey = self._fd_to_key[fd] except KeyError: raise KeyError("{!r} is not registered".format(fileobj)) from None - if events != key.events: - self.unregister(fileobj) - key = self.register(fileobj, events, data) - elif data != key.data: - # Use a shortcut to update the data. - key = key._replace(data=data) + if events != oldkey.events: + key = self._modify(fileobj, events, data) + elif data != oldkey.data: + key = SelectorKey(fileobj, fd, events, data) self._fd_to_key[key.fd] = key + else: + # no change + key = oldkey return key def close(self): @@ -353,6 +358,17 @@ if hasattr(select, 'poll'): self._poll.unregister(key.fd) return key + def _modify(self, fileobj, events, data): + super().unregister(fileobj) + 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.modify(key.fd, poll_events) + return key + def select(self, timeout=None): if timeout is None: timeout = None @@ -412,6 +428,17 @@ if hasattr(select, 'epoll'): pass return key + def _modify(self, fileobj, events, data): + super().unregister(fileobj) + 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.modify(key.fd, epoll_events) + return key + def select(self, timeout=None): if timeout is None: timeout = -1 @@ -476,6 +503,17 @@ if hasattr(select, 'devpoll'): self._devpoll.unregister(key.fd) return key + def _modify(self, fileobj, events, data): + super().unregister(fileobj) + 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.modify(key.fd, poll_events) + return key + def select(self, timeout=None): if timeout is None: timeout = None @@ -521,37 +559,57 @@ if hasattr(select, 'kqueue'): def register(self, fileobj, events, data=None): key = super().register(fileobj, events, data) + kevents = [] if events & EVENT_READ: - kev = select.kevent(key.fd, select.KQ_FILTER_READ, - select.KQ_EV_ADD) - self._kqueue.control([kev], 0, 0) + kevents.append(select.kevent(key.fd, select.KQ_FILTER_READ, + select.KQ_EV_ADD)) if events & EVENT_WRITE: - kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, - select.KQ_EV_ADD) - self._kqueue.control([kev], 0, 0) + kevents.append(select.kevent(key.fd, select.KQ_FILTER_WRITE, + select.KQ_EV_ADD)) + if kevents: + self._kqueue.control(kevents, 0, 0) return key def unregister(self, fileobj): key = super().unregister(fileobj) + kevents = [] if key.events & EVENT_READ: - kev = select.kevent(key.fd, select.KQ_FILTER_READ, - select.KQ_EV_DELETE) + kevents.append(select.kevent(key.fd, select.KQ_FILTER_READ, + select.KQ_EV_DELETE)) + if key.events & EVENT_WRITE: + kevents.append(select.kevent(key.fd, select.KQ_FILTER_WRITE, + select.KQ_EV_DELETE)) + if kevents: try: - self._kqueue.control([kev], 0, 0) + self._kqueue.control(kevents, 0, 0) except OSError: # This can happen if the FD was closed since it # was registered. pass - if key.events & EVENT_WRITE: - kev = select.kevent(key.fd, select.KQ_FILTER_WRITE, - select.KQ_EV_DELETE) - try: - self._kqueue.control([kev], 0, 0) - except OSError: - # See comment above. - pass return key + def _modify(self, fileobj, events, data): + oldkey = super().unregister(fileobj) + key = super().register(fileobj, events, data) + fd = key.fd + kevents = [] + if events & EVENT_READ: + kevents.append(select.kevent(fd, select.KQ_FILTER_READ, + select.KQ_EV_ADD)) + elif oldkey.events & EVENT_READ: + kevents.append(select.kevent(fd, select.KQ_FILTER_READ, + select.KQ_EV_DELETE)) + if events & EVENT_WRITE: + kevents.append(select.kevent(fd, select.KQ_FILTER_WRITE, + select.KQ_EV_ADD)) + elif oldkey.events & EVENT_WRITE: + kevents.append(select.kevent(fd, select.KQ_FILTER_WRITE, + select.KQ_EV_DELETE)) + if kevents: + self._kqueue.control(kevents, 0, 0) + return key + + def select(self, timeout=None): timeout = None if timeout is None else max(timeout, 0) max_ev = len(self._fd_to_key)