summaryrefslogtreecommitdiff
path: root/Lib/selectors.py
diff options
context:
space:
mode:
authorGiampaolo Rodola <g.rodola@gmail.com>2017-05-20 11:34:44 +0200
committerGitHub <noreply@github.com>2017-05-20 11:34:44 +0200
commit62c7d90b6446288be1a7906581befe3c211fad5f (patch)
tree701546036e3303958a99485daa6d8ea436819e34 /Lib/selectors.py
parent753bca3934a7618a4fa96e107ad1c5c18633a683 (diff)
downloadcpython-git-62c7d90b6446288be1a7906581befe3c211fad5f.tar.gz
#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.py216
1 files changed, 84 insertions, 132 deletions
diff --git a/Lib/selectors.py b/Lib/selectors.py
index e7bc517730..f29d11fc6a 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()