blob: 6d569c30adff871c2346fb05d6ef0359432f7c54 [file] [log] [blame]
Charles-François Natali243d8d82013-09-04 19:02:49 +02001"""Selectors module.
2
3This module allows high-level and efficient I/O multiplexing, built upon the
4`select` module primitives.
5"""
6
7
Victor Stinnerda492a82014-02-20 10:37:27 +01008from abc import ABCMeta, abstractmethod
Charles-François Natali4574b492013-10-30 20:31:04 +01009from collections import namedtuple, Mapping
Victor Stinnerdcd97402014-01-31 12:12:53 +010010import math
Charles-François Natali243d8d82013-09-04 19:02:49 +020011import select
12import sys
13
14
15# generic events, that must be mapped to implementation-specific ones
16EVENT_READ = (1 << 0)
17EVENT_WRITE = (1 << 1)
18
19
20def _fileobj_to_fd(fileobj):
21 """Return a file descriptor from a file object.
22
23 Parameters:
24 fileobj -- file object or file descriptor
25
26 Returns:
27 corresponding file descriptor
Guido van Rossum9710ff02013-12-07 15:57:01 -080028
29 Raises:
30 ValueError if the object is invalid
Charles-François Natali243d8d82013-09-04 19:02:49 +020031 """
32 if isinstance(fileobj, int):
33 fd = fileobj
34 else:
35 try:
36 fd = int(fileobj.fileno())
37 except (AttributeError, TypeError, ValueError):
38 raise ValueError("Invalid file object: "
39 "{!r}".format(fileobj)) from None
40 if fd < 0:
41 raise ValueError("Invalid file descriptor: {}".format(fd))
42 return fd
43
44
45SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
46"""Object used to associate a file object to its backing file descriptor,
47selected event mask and attached data."""
48
49
Charles-François Natali4574b492013-10-30 20:31:04 +010050class _SelectorMapping(Mapping):
51 """Mapping of file objects to selector keys."""
52
53 def __init__(self, selector):
54 self._selector = selector
55
56 def __len__(self):
57 return len(self._selector._fd_to_key)
58
59 def __getitem__(self, fileobj):
60 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -080061 fd = self._selector._fileobj_lookup(fileobj)
62 return self._selector._fd_to_key[fd]
Charles-François Natali4574b492013-10-30 20:31:04 +010063 except KeyError:
64 raise KeyError("{!r} is not registered".format(fileobj)) from None
65
66 def __iter__(self):
67 return iter(self._selector._fd_to_key)
68
69
Charles-François Natali243d8d82013-09-04 19:02:49 +020070class BaseSelector(metaclass=ABCMeta):
Charles-François Natalib3330a0a2013-12-01 11:04:17 +010071 """Selector abstract base class.
Charles-François Natali243d8d82013-09-04 19:02:49 +020072
73 A selector supports registering file objects to be monitored for specific
74 I/O events.
75
76 A file object is a file descriptor or any object with a `fileno()` method.
77 An arbitrary object can be attached to the file object, which can be used
78 for example to store context information, a callback, etc.
79
80 A selector can use various implementations (select(), poll(), epoll()...)
81 depending on the platform. The default `Selector` class uses the most
Yury Selivanovb0b0e622014-02-18 22:27:48 -050082 efficient implementation on the current platform.
Charles-François Natali243d8d82013-09-04 19:02:49 +020083 """
84
Charles-François Natalib3330a0a2013-12-01 11:04:17 +010085 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +020086 def register(self, fileobj, events, data=None):
87 """Register a file object.
88
89 Parameters:
90 fileobj -- file object or file descriptor
91 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
92 data -- attached data
93
94 Returns:
95 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -080096
97 Raises:
98 ValueError if events is invalid
99 KeyError if fileobj is already registered
100 OSError if fileobj is closed or otherwise is unacceptable to
101 the underlying system call (if a system call is made)
102
103 Note:
104 OSError may or may not be raised
Charles-François Natali243d8d82013-09-04 19:02:49 +0200105 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100106 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200107
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100108 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +0200109 def unregister(self, fileobj):
110 """Unregister a file object.
111
112 Parameters:
113 fileobj -- file object or file descriptor
114
115 Returns:
116 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800117
118 Raises:
119 KeyError if fileobj is not registered
120
121 Note:
122 If fileobj is registered but has since been closed this does
123 *not* raise OSError (even if the wrapped syscall does)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200124 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100125 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200126
127 def modify(self, fileobj, events, data=None):
128 """Change a registered file object monitored events or attached data.
129
130 Parameters:
131 fileobj -- file object or file descriptor
132 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
133 data -- attached data
134
135 Returns:
136 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800137
138 Raises:
139 Anything that unregister() or register() raises
Charles-François Natali243d8d82013-09-04 19:02:49 +0200140 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100141 self.unregister(fileobj)
142 return self.register(fileobj, events, data)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200143
144 @abstractmethod
145 def select(self, timeout=None):
146 """Perform the actual selection, until some monitored file objects are
147 ready or a timeout expires.
148
149 Parameters:
150 timeout -- if timeout > 0, this specifies the maximum wait time, in
151 seconds
152 if timeout <= 0, the select() call won't block, and will
153 report the currently ready file objects
154 if timeout is None, select() will block until a monitored
155 file object becomes ready
156
157 Returns:
158 list of (key, events) for ready file objects
159 `events` is a bitwise mask of EVENT_READ|EVENT_WRITE
160 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100161 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200162
163 def close(self):
164 """Close the selector.
165
166 This must be called to make sure that any underlying resource is freed.
167 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100168 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200169
170 def get_key(self, fileobj):
171 """Return the key associated to a registered file object.
172
173 Returns:
174 SelectorKey for this file object
175 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100176 mapping = self.get_map()
Victor Stinner458fc6f2015-01-13 10:00:55 +0100177 if mapping is None:
178 raise RuntimeError('Selector is closed')
Charles-François Natali243d8d82013-09-04 19:02:49 +0200179 try:
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100180 return mapping[fileobj]
Charles-François Natali243d8d82013-09-04 19:02:49 +0200181 except KeyError:
182 raise KeyError("{!r} is not registered".format(fileobj)) from None
183
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100184 @abstractmethod
Charles-François Natali4574b492013-10-30 20:31:04 +0100185 def get_map(self):
186 """Return a mapping of file objects to selector keys."""
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100187 raise NotImplementedError
Charles-François Natali4574b492013-10-30 20:31:04 +0100188
Charles-François Natali243d8d82013-09-04 19:02:49 +0200189 def __enter__(self):
190 return self
191
192 def __exit__(self, *args):
193 self.close()
194
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100195
196class _BaseSelectorImpl(BaseSelector):
197 """Base selector implementation."""
198
199 def __init__(self):
200 # this maps file descriptors to keys
201 self._fd_to_key = {}
202 # read-only mapping returned by get_map()
203 self._map = _SelectorMapping(self)
204
Guido van Rossum9710ff02013-12-07 15:57:01 -0800205 def _fileobj_lookup(self, fileobj):
206 """Return a file descriptor from a file object.
207
208 This wraps _fileobj_to_fd() to do an exhaustive search in case
209 the object is invalid but we still have it in our map. This
210 is used by unregister() so we can unregister an object that
211 was previously registered even if it is closed. It is also
212 used by _SelectorMapping.
213 """
214 try:
215 return _fileobj_to_fd(fileobj)
216 except ValueError:
217 # Do an exhaustive search.
218 for key in self._fd_to_key.values():
219 if key.fileobj is fileobj:
220 return key.fd
221 # Raise ValueError after all.
222 raise
223
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100224 def register(self, fileobj, events, data=None):
225 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
226 raise ValueError("Invalid events: {!r}".format(events))
227
Guido van Rossum9710ff02013-12-07 15:57:01 -0800228 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100229
230 if key.fd in self._fd_to_key:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800231 raise KeyError("{!r} (FD {}) is already registered"
232 .format(fileobj, key.fd))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100233
234 self._fd_to_key[key.fd] = key
235 return key
236
237 def unregister(self, fileobj):
238 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800239 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100240 except KeyError:
241 raise KeyError("{!r} is not registered".format(fileobj)) from None
242 return key
243
244 def modify(self, fileobj, events, data=None):
245 # TODO: Subclasses can probably optimize this even further.
246 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800247 key = self._fd_to_key[self._fileobj_lookup(fileobj)]
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100248 except KeyError:
249 raise KeyError("{!r} is not registered".format(fileobj)) from None
250 if events != key.events:
251 self.unregister(fileobj)
252 key = self.register(fileobj, events, data)
253 elif data != key.data:
254 # Use a shortcut to update the data.
255 key = key._replace(data=data)
256 self._fd_to_key[key.fd] = key
257 return key
258
259 def close(self):
260 self._fd_to_key.clear()
Victor Stinner38dc2502015-01-13 09:58:33 +0100261 self._map = None
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100262
263 def get_map(self):
264 return self._map
265
Charles-François Natali243d8d82013-09-04 19:02:49 +0200266 def _key_from_fd(self, fd):
267 """Return the key associated to a given file descriptor.
268
269 Parameters:
270 fd -- file descriptor
271
272 Returns:
273 corresponding key, or None if not found
274 """
275 try:
276 return self._fd_to_key[fd]
277 except KeyError:
278 return None
279
280
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100281class SelectSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200282 """Select-based selector."""
283
284 def __init__(self):
285 super().__init__()
286 self._readers = set()
287 self._writers = set()
288
289 def register(self, fileobj, events, data=None):
290 key = super().register(fileobj, events, data)
291 if events & EVENT_READ:
292 self._readers.add(key.fd)
293 if events & EVENT_WRITE:
294 self._writers.add(key.fd)
295 return key
296
297 def unregister(self, fileobj):
298 key = super().unregister(fileobj)
299 self._readers.discard(key.fd)
300 self._writers.discard(key.fd)
301 return key
302
303 if sys.platform == 'win32':
304 def _select(self, r, w, _, timeout=None):
305 r, w, x = select.select(r, w, w, timeout)
306 return r, w + x, []
307 else:
308 _select = select.select
309
310 def select(self, timeout=None):
311 timeout = None if timeout is None else max(timeout, 0)
312 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400313 try:
314 r, w, _ = self._select(self._readers, self._writers, [], timeout)
315 except InterruptedError:
316 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200317 r = set(r)
318 w = set(w)
319 for fd in r | w:
320 events = 0
321 if fd in r:
322 events |= EVENT_READ
323 if fd in w:
324 events |= EVENT_WRITE
325
326 key = self._key_from_fd(fd)
327 if key:
328 ready.append((key, events & key.events))
329 return ready
330
331
332if hasattr(select, 'poll'):
333
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100334 class PollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200335 """Poll-based selector."""
336
337 def __init__(self):
338 super().__init__()
339 self._poll = select.poll()
340
341 def register(self, fileobj, events, data=None):
342 key = super().register(fileobj, events, data)
343 poll_events = 0
344 if events & EVENT_READ:
345 poll_events |= select.POLLIN
346 if events & EVENT_WRITE:
347 poll_events |= select.POLLOUT
348 self._poll.register(key.fd, poll_events)
349 return key
350
351 def unregister(self, fileobj):
352 key = super().unregister(fileobj)
353 self._poll.unregister(key.fd)
354 return key
355
356 def select(self, timeout=None):
Victor Stinner11da8e22014-01-21 01:48:28 +0100357 if timeout is None:
358 timeout = None
Victor Stinner7067b5d2014-01-21 17:49:41 +0100359 elif timeout <= 0:
Victor Stinner11da8e22014-01-21 01:48:28 +0100360 timeout = 0
361 else:
Victor Stinnerdcd97402014-01-31 12:12:53 +0100362 # poll() has a resolution of 1 millisecond, round away from
363 # zero to wait *at least* timeout seconds.
Victor Stinner665758f2014-01-31 16:24:21 +0100364 timeout = math.ceil(timeout * 1e3)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200365 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400366 try:
367 fd_event_list = self._poll.poll(timeout)
368 except InterruptedError:
369 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200370 for fd, event in fd_event_list:
371 events = 0
372 if event & ~select.POLLIN:
373 events |= EVENT_WRITE
374 if event & ~select.POLLOUT:
375 events |= EVENT_READ
376
377 key = self._key_from_fd(fd)
378 if key:
379 ready.append((key, events & key.events))
380 return ready
381
382
383if hasattr(select, 'epoll'):
384
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100385 class EpollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200386 """Epoll-based selector."""
387
388 def __init__(self):
389 super().__init__()
390 self._epoll = select.epoll()
391
392 def fileno(self):
393 return self._epoll.fileno()
394
395 def register(self, fileobj, events, data=None):
396 key = super().register(fileobj, events, data)
397 epoll_events = 0
398 if events & EVENT_READ:
399 epoll_events |= select.EPOLLIN
400 if events & EVENT_WRITE:
401 epoll_events |= select.EPOLLOUT
402 self._epoll.register(key.fd, epoll_events)
403 return key
404
405 def unregister(self, fileobj):
406 key = super().unregister(fileobj)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800407 try:
408 self._epoll.unregister(key.fd)
409 except OSError:
410 # This can happen if the FD was closed since it
411 # was registered.
412 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200413 return key
414
415 def select(self, timeout=None):
Victor Stinner567b26e2014-01-21 21:00:47 +0100416 if timeout is None:
417 timeout = -1
418 elif timeout <= 0:
419 timeout = 0
Victor Stinnerdcd97402014-01-31 12:12:53 +0100420 else:
421 # epoll_wait() has a resolution of 1 millisecond, round away
422 # from zero to wait *at least* timeout seconds.
423 timeout = math.ceil(timeout * 1e3) * 1e-3
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500424
Yury Selivanovdfc44e02014-12-08 12:30:10 -0500425 # epoll_wait() expects `maxevents` to be greater than zero;
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500426 # we want to make sure that `select()` can be called when no
427 # FD is registered.
428 max_ev = max(len(self._fd_to_key), 1)
429
Charles-François Natali243d8d82013-09-04 19:02:49 +0200430 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400431 try:
432 fd_event_list = self._epoll.poll(timeout, max_ev)
433 except InterruptedError:
434 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200435 for fd, event in fd_event_list:
436 events = 0
437 if event & ~select.EPOLLIN:
438 events |= EVENT_WRITE
439 if event & ~select.EPOLLOUT:
440 events |= EVENT_READ
441
442 key = self._key_from_fd(fd)
443 if key:
444 ready.append((key, events & key.events))
445 return ready
446
447 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400448 self._epoll.close()
449 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200450
451
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100452if hasattr(select, 'devpoll'):
453
454 class DevpollSelector(_BaseSelectorImpl):
455 """Solaris /dev/poll selector."""
456
457 def __init__(self):
458 super().__init__()
459 self._devpoll = select.devpoll()
460
461 def fileno(self):
462 return self._devpoll.fileno()
463
464 def register(self, fileobj, events, data=None):
465 key = super().register(fileobj, events, data)
466 poll_events = 0
467 if events & EVENT_READ:
468 poll_events |= select.POLLIN
469 if events & EVENT_WRITE:
470 poll_events |= select.POLLOUT
471 self._devpoll.register(key.fd, poll_events)
472 return key
473
474 def unregister(self, fileobj):
475 key = super().unregister(fileobj)
476 self._devpoll.unregister(key.fd)
477 return key
478
479 def select(self, timeout=None):
480 if timeout is None:
481 timeout = None
482 elif timeout <= 0:
483 timeout = 0
484 else:
485 # devpoll() has a resolution of 1 millisecond, round away from
486 # zero to wait *at least* timeout seconds.
487 timeout = math.ceil(timeout * 1e3)
488 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400489 try:
490 fd_event_list = self._devpoll.poll(timeout)
491 except InterruptedError:
492 return ready
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100493 for fd, event in fd_event_list:
494 events = 0
495 if event & ~select.POLLIN:
496 events |= EVENT_WRITE
497 if event & ~select.POLLOUT:
498 events |= EVENT_READ
499
500 key = self._key_from_fd(fd)
501 if key:
502 ready.append((key, events & key.events))
503 return ready
504
505 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400506 self._devpoll.close()
507 super().close()
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100508
509
Charles-François Natali243d8d82013-09-04 19:02:49 +0200510if hasattr(select, 'kqueue'):
511
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100512 class KqueueSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200513 """Kqueue-based selector."""
514
515 def __init__(self):
516 super().__init__()
517 self._kqueue = select.kqueue()
518
519 def fileno(self):
520 return self._kqueue.fileno()
521
522 def register(self, fileobj, events, data=None):
523 key = super().register(fileobj, events, data)
524 if events & EVENT_READ:
525 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
526 select.KQ_EV_ADD)
527 self._kqueue.control([kev], 0, 0)
528 if events & EVENT_WRITE:
529 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
530 select.KQ_EV_ADD)
531 self._kqueue.control([kev], 0, 0)
532 return key
533
534 def unregister(self, fileobj):
535 key = super().unregister(fileobj)
536 if key.events & EVENT_READ:
537 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
538 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800539 try:
540 self._kqueue.control([kev], 0, 0)
541 except OSError:
542 # This can happen if the FD was closed since it
543 # was registered.
544 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200545 if key.events & EVENT_WRITE:
546 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
547 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800548 try:
549 self._kqueue.control([kev], 0, 0)
550 except OSError:
551 # See comment above.
552 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200553 return key
554
555 def select(self, timeout=None):
556 timeout = None if timeout is None else max(timeout, 0)
557 max_ev = len(self._fd_to_key)
558 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400559 try:
560 kev_list = self._kqueue.control(None, max_ev, timeout)
561 except InterruptedError:
562 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200563 for kev in kev_list:
564 fd = kev.ident
565 flag = kev.filter
566 events = 0
567 if flag == select.KQ_FILTER_READ:
568 events |= EVENT_READ
569 if flag == select.KQ_FILTER_WRITE:
570 events |= EVENT_WRITE
571
572 key = self._key_from_fd(fd)
573 if key:
574 ready.append((key, events & key.events))
575 return ready
576
577 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400578 self._kqueue.close()
579 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200580
581
Victor Stinner53a6d742015-01-09 00:13:39 +0100582# Choose the best implementation, roughly:
583# epoll|kqueue|devpoll > poll > select.
Charles-François Natali243d8d82013-09-04 19:02:49 +0200584# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
585if 'KqueueSelector' in globals():
586 DefaultSelector = KqueueSelector
587elif 'EpollSelector' in globals():
588 DefaultSelector = EpollSelector
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100589elif 'DevpollSelector' in globals():
590 DefaultSelector = DevpollSelector
Charles-François Natali243d8d82013-09-04 19:02:49 +0200591elif 'PollSelector' in globals():
592 DefaultSelector = PollSelector
593else:
594 DefaultSelector = SelectSelector