blob: b1b530afcb43e4d23562e42abda6ca66cc27ffac [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 Stinner635fca92014-01-25 14:56:48 +01008from abc import ABCMeta, abstractmethod, abstractproperty
Charles-François Natali4574b492013-10-30 20:31:04 +01009from collections import namedtuple, Mapping
Charles-François Natali243d8d82013-09-04 19:02:49 +020010import functools
11import 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
82 performant implementation on the current platform.
83 """
84
Victor Stinner635fca92014-01-25 14:56:48 +010085 @abstractproperty
86 def resolution(self):
87 """Resolution of the selector in seconds"""
88 return None
89
Charles-François Natalib3330a0a2013-12-01 11:04:17 +010090 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +020091 def register(self, fileobj, events, data=None):
92 """Register a file object.
93
94 Parameters:
95 fileobj -- file object or file descriptor
96 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
97 data -- attached data
98
99 Returns:
100 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800101
102 Raises:
103 ValueError if events is invalid
104 KeyError if fileobj is already registered
105 OSError if fileobj is closed or otherwise is unacceptable to
106 the underlying system call (if a system call is made)
107
108 Note:
109 OSError may or may not be raised
Charles-François Natali243d8d82013-09-04 19:02:49 +0200110 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100111 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200112
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100113 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +0200114 def unregister(self, fileobj):
115 """Unregister a file object.
116
117 Parameters:
118 fileobj -- file object or file descriptor
119
120 Returns:
121 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800122
123 Raises:
124 KeyError if fileobj is not registered
125
126 Note:
127 If fileobj is registered but has since been closed this does
128 *not* raise OSError (even if the wrapped syscall does)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200129 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100130 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200131
132 def modify(self, fileobj, events, data=None):
133 """Change a registered file object monitored events or attached data.
134
135 Parameters:
136 fileobj -- file object or file descriptor
137 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
138 data -- attached data
139
140 Returns:
141 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800142
143 Raises:
144 Anything that unregister() or register() raises
Charles-François Natali243d8d82013-09-04 19:02:49 +0200145 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100146 self.unregister(fileobj)
147 return self.register(fileobj, events, data)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200148
149 @abstractmethod
150 def select(self, timeout=None):
151 """Perform the actual selection, until some monitored file objects are
152 ready or a timeout expires.
153
154 Parameters:
155 timeout -- if timeout > 0, this specifies the maximum wait time, in
156 seconds
157 if timeout <= 0, the select() call won't block, and will
158 report the currently ready file objects
159 if timeout is None, select() will block until a monitored
160 file object becomes ready
161
162 Returns:
163 list of (key, events) for ready file objects
164 `events` is a bitwise mask of EVENT_READ|EVENT_WRITE
165 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100166 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200167
168 def close(self):
169 """Close the selector.
170
171 This must be called to make sure that any underlying resource is freed.
172 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100173 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200174
175 def get_key(self, fileobj):
176 """Return the key associated to a registered file object.
177
178 Returns:
179 SelectorKey for this file object
180 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100181 mapping = self.get_map()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200182 try:
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100183 return mapping[fileobj]
Charles-François Natali243d8d82013-09-04 19:02:49 +0200184 except KeyError:
185 raise KeyError("{!r} is not registered".format(fileobj)) from None
186
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100187 @abstractmethod
Charles-François Natali4574b492013-10-30 20:31:04 +0100188 def get_map(self):
189 """Return a mapping of file objects to selector keys."""
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100190 raise NotImplementedError
Charles-François Natali4574b492013-10-30 20:31:04 +0100191
Charles-François Natali243d8d82013-09-04 19:02:49 +0200192 def __enter__(self):
193 return self
194
195 def __exit__(self, *args):
196 self.close()
197
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100198
199class _BaseSelectorImpl(BaseSelector):
200 """Base selector implementation."""
201
202 def __init__(self):
203 # this maps file descriptors to keys
204 self._fd_to_key = {}
205 # read-only mapping returned by get_map()
206 self._map = _SelectorMapping(self)
207
Guido van Rossum9710ff02013-12-07 15:57:01 -0800208 def _fileobj_lookup(self, fileobj):
209 """Return a file descriptor from a file object.
210
211 This wraps _fileobj_to_fd() to do an exhaustive search in case
212 the object is invalid but we still have it in our map. This
213 is used by unregister() so we can unregister an object that
214 was previously registered even if it is closed. It is also
215 used by _SelectorMapping.
216 """
217 try:
218 return _fileobj_to_fd(fileobj)
219 except ValueError:
220 # Do an exhaustive search.
221 for key in self._fd_to_key.values():
222 if key.fileobj is fileobj:
223 return key.fd
224 # Raise ValueError after all.
225 raise
226
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100227 def register(self, fileobj, events, data=None):
228 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
229 raise ValueError("Invalid events: {!r}".format(events))
230
Guido van Rossum9710ff02013-12-07 15:57:01 -0800231 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100232
233 if key.fd in self._fd_to_key:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800234 raise KeyError("{!r} (FD {}) is already registered"
235 .format(fileobj, key.fd))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100236
237 self._fd_to_key[key.fd] = key
238 return key
239
240 def unregister(self, fileobj):
241 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800242 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100243 except KeyError:
244 raise KeyError("{!r} is not registered".format(fileobj)) from None
245 return key
246
247 def modify(self, fileobj, events, data=None):
248 # TODO: Subclasses can probably optimize this even further.
249 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800250 key = self._fd_to_key[self._fileobj_lookup(fileobj)]
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100251 except KeyError:
252 raise KeyError("{!r} is not registered".format(fileobj)) from None
253 if events != key.events:
254 self.unregister(fileobj)
255 key = self.register(fileobj, events, data)
256 elif data != key.data:
257 # Use a shortcut to update the data.
258 key = key._replace(data=data)
259 self._fd_to_key[key.fd] = key
260 return key
261
262 def close(self):
263 self._fd_to_key.clear()
264
265 def get_map(self):
266 return self._map
267
Charles-François Natali243d8d82013-09-04 19:02:49 +0200268 def _key_from_fd(self, fd):
269 """Return the key associated to a given file descriptor.
270
271 Parameters:
272 fd -- file descriptor
273
274 Returns:
275 corresponding key, or None if not found
276 """
277 try:
278 return self._fd_to_key[fd]
279 except KeyError:
280 return None
281
282
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100283class SelectSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200284 """Select-based selector."""
285
286 def __init__(self):
287 super().__init__()
288 self._readers = set()
289 self._writers = set()
290
Victor Stinner635fca92014-01-25 14:56:48 +0100291 @property
292 def resolution(self):
293 return 1e-6
294
Charles-François Natali243d8d82013-09-04 19:02:49 +0200295 def register(self, fileobj, events, data=None):
296 key = super().register(fileobj, events, data)
297 if events & EVENT_READ:
298 self._readers.add(key.fd)
299 if events & EVENT_WRITE:
300 self._writers.add(key.fd)
301 return key
302
303 def unregister(self, fileobj):
304 key = super().unregister(fileobj)
305 self._readers.discard(key.fd)
306 self._writers.discard(key.fd)
307 return key
308
309 if sys.platform == 'win32':
310 def _select(self, r, w, _, timeout=None):
311 r, w, x = select.select(r, w, w, timeout)
312 return r, w + x, []
313 else:
314 _select = select.select
315
316 def select(self, timeout=None):
317 timeout = None if timeout is None else max(timeout, 0)
318 ready = []
319 try:
320 r, w, _ = self._select(self._readers, self._writers, [], timeout)
321 except InterruptedError:
322 return ready
323 r = set(r)
324 w = set(w)
325 for fd in r | w:
326 events = 0
327 if fd in r:
328 events |= EVENT_READ
329 if fd in w:
330 events |= EVENT_WRITE
331
332 key = self._key_from_fd(fd)
333 if key:
334 ready.append((key, events & key.events))
335 return ready
336
337
338if hasattr(select, 'poll'):
339
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100340 class PollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200341 """Poll-based selector."""
342
343 def __init__(self):
344 super().__init__()
345 self._poll = select.poll()
346
Victor Stinner635fca92014-01-25 14:56:48 +0100347 @property
348 def resolution(self):
349 return 1e-3
350
Charles-François Natali243d8d82013-09-04 19:02:49 +0200351 def register(self, fileobj, events, data=None):
352 key = super().register(fileobj, events, data)
353 poll_events = 0
354 if events & EVENT_READ:
355 poll_events |= select.POLLIN
356 if events & EVENT_WRITE:
357 poll_events |= select.POLLOUT
358 self._poll.register(key.fd, poll_events)
359 return key
360
361 def unregister(self, fileobj):
362 key = super().unregister(fileobj)
363 self._poll.unregister(key.fd)
364 return key
365
366 def select(self, timeout=None):
Victor Stinner11da8e22014-01-21 01:48:28 +0100367 if timeout is None:
368 timeout = None
Victor Stinner7067b5d2014-01-21 17:49:41 +0100369 elif timeout <= 0:
Victor Stinner11da8e22014-01-21 01:48:28 +0100370 timeout = 0
371 else:
Victor Stinner20418592014-01-25 14:43:45 +0100372 # Round towards zero
373 timeout = int(timeout * 1000)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200374 ready = []
375 try:
376 fd_event_list = self._poll.poll(timeout)
377 except InterruptedError:
378 return ready
379 for fd, event in fd_event_list:
380 events = 0
381 if event & ~select.POLLIN:
382 events |= EVENT_WRITE
383 if event & ~select.POLLOUT:
384 events |= EVENT_READ
385
386 key = self._key_from_fd(fd)
387 if key:
388 ready.append((key, events & key.events))
389 return ready
390
391
392if hasattr(select, 'epoll'):
393
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100394 class EpollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200395 """Epoll-based selector."""
396
397 def __init__(self):
398 super().__init__()
399 self._epoll = select.epoll()
400
Victor Stinner635fca92014-01-25 14:56:48 +0100401 @property
402 def resolution(self):
403 return 1e-3
404
Charles-François Natali243d8d82013-09-04 19:02:49 +0200405 def fileno(self):
406 return self._epoll.fileno()
407
408 def register(self, fileobj, events, data=None):
409 key = super().register(fileobj, events, data)
410 epoll_events = 0
411 if events & EVENT_READ:
412 epoll_events |= select.EPOLLIN
413 if events & EVENT_WRITE:
414 epoll_events |= select.EPOLLOUT
415 self._epoll.register(key.fd, epoll_events)
416 return key
417
418 def unregister(self, fileobj):
419 key = super().unregister(fileobj)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800420 try:
421 self._epoll.unregister(key.fd)
422 except OSError:
423 # This can happen if the FD was closed since it
424 # was registered.
425 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200426 return key
427
428 def select(self, timeout=None):
Victor Stinner567b26e2014-01-21 21:00:47 +0100429 if timeout is None:
430 timeout = -1
431 elif timeout <= 0:
432 timeout = 0
Charles-François Natali243d8d82013-09-04 19:02:49 +0200433 max_ev = len(self._fd_to_key)
434 ready = []
435 try:
436 fd_event_list = self._epoll.poll(timeout, max_ev)
437 except InterruptedError:
438 return ready
439 for fd, event in fd_event_list:
440 events = 0
441 if event & ~select.EPOLLIN:
442 events |= EVENT_WRITE
443 if event & ~select.EPOLLOUT:
444 events |= EVENT_READ
445
446 key = self._key_from_fd(fd)
447 if key:
448 ready.append((key, events & key.events))
449 return ready
450
451 def close(self):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200452 self._epoll.close()
Guido van Rossum61a2ced2013-10-31 11:01:40 -0700453 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200454
455
456if hasattr(select, 'kqueue'):
457
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100458 class KqueueSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200459 """Kqueue-based selector."""
460
461 def __init__(self):
462 super().__init__()
463 self._kqueue = select.kqueue()
464
Victor Stinner635fca92014-01-25 14:56:48 +0100465 @property
466 def resolution(self):
467 return 1e-9
468
Charles-François Natali243d8d82013-09-04 19:02:49 +0200469 def fileno(self):
470 return self._kqueue.fileno()
471
472 def register(self, fileobj, events, data=None):
473 key = super().register(fileobj, events, data)
474 if events & EVENT_READ:
475 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
476 select.KQ_EV_ADD)
477 self._kqueue.control([kev], 0, 0)
478 if events & EVENT_WRITE:
479 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
480 select.KQ_EV_ADD)
481 self._kqueue.control([kev], 0, 0)
482 return key
483
484 def unregister(self, fileobj):
485 key = super().unregister(fileobj)
486 if key.events & EVENT_READ:
487 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
488 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800489 try:
490 self._kqueue.control([kev], 0, 0)
491 except OSError:
492 # This can happen if the FD was closed since it
493 # was registered.
494 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200495 if key.events & EVENT_WRITE:
496 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
497 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800498 try:
499 self._kqueue.control([kev], 0, 0)
500 except OSError:
501 # See comment above.
502 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200503 return key
504
505 def select(self, timeout=None):
506 timeout = None if timeout is None else max(timeout, 0)
507 max_ev = len(self._fd_to_key)
508 ready = []
509 try:
510 kev_list = self._kqueue.control(None, max_ev, timeout)
511 except InterruptedError:
512 return ready
513 for kev in kev_list:
514 fd = kev.ident
515 flag = kev.filter
516 events = 0
517 if flag == select.KQ_FILTER_READ:
518 events |= EVENT_READ
519 if flag == select.KQ_FILTER_WRITE:
520 events |= EVENT_WRITE
521
522 key = self._key_from_fd(fd)
523 if key:
524 ready.append((key, events & key.events))
525 return ready
526
527 def close(self):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200528 self._kqueue.close()
Guido van Rossum61a2ced2013-10-31 11:01:40 -0700529 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200530
531
532# Choose the best implementation: roughly, epoll|kqueue > poll > select.
533# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
534if 'KqueueSelector' in globals():
535 DefaultSelector = KqueueSelector
536elif 'EpollSelector' in globals():
537 DefaultSelector = EpollSelector
538elif 'PollSelector' in globals():
539 DefaultSelector = PollSelector
540else:
541 DefaultSelector = SelectSelector