blob: b2f4c2bad22707ad66152c3868413af0073cff3d [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 Stinnerb4c93882014-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 Selivanovdec1a452014-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()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200177 try:
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100178 return mapping[fileobj]
Charles-François Natali243d8d82013-09-04 19:02:49 +0200179 except KeyError:
180 raise KeyError("{!r} is not registered".format(fileobj)) from None
181
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100182 @abstractmethod
Charles-François Natali4574b492013-10-30 20:31:04 +0100183 def get_map(self):
184 """Return a mapping of file objects to selector keys."""
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100185 raise NotImplementedError
Charles-François Natali4574b492013-10-30 20:31:04 +0100186
Charles-François Natali243d8d82013-09-04 19:02:49 +0200187 def __enter__(self):
188 return self
189
190 def __exit__(self, *args):
191 self.close()
192
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100193
194class _BaseSelectorImpl(BaseSelector):
195 """Base selector implementation."""
196
197 def __init__(self):
198 # this maps file descriptors to keys
199 self._fd_to_key = {}
200 # read-only mapping returned by get_map()
201 self._map = _SelectorMapping(self)
202
Guido van Rossum9710ff02013-12-07 15:57:01 -0800203 def _fileobj_lookup(self, fileobj):
204 """Return a file descriptor from a file object.
205
206 This wraps _fileobj_to_fd() to do an exhaustive search in case
207 the object is invalid but we still have it in our map. This
208 is used by unregister() so we can unregister an object that
209 was previously registered even if it is closed. It is also
210 used by _SelectorMapping.
211 """
212 try:
213 return _fileobj_to_fd(fileobj)
214 except ValueError:
215 # Do an exhaustive search.
216 for key in self._fd_to_key.values():
217 if key.fileobj is fileobj:
218 return key.fd
219 # Raise ValueError after all.
220 raise
221
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100222 def register(self, fileobj, events, data=None):
223 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
224 raise ValueError("Invalid events: {!r}".format(events))
225
Guido van Rossum9710ff02013-12-07 15:57:01 -0800226 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100227
228 if key.fd in self._fd_to_key:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800229 raise KeyError("{!r} (FD {}) is already registered"
230 .format(fileobj, key.fd))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100231
232 self._fd_to_key[key.fd] = key
233 return key
234
235 def unregister(self, fileobj):
236 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800237 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100238 except KeyError:
239 raise KeyError("{!r} is not registered".format(fileobj)) from None
240 return key
241
242 def modify(self, fileobj, events, data=None):
243 # TODO: Subclasses can probably optimize this even further.
244 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800245 key = self._fd_to_key[self._fileobj_lookup(fileobj)]
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100246 except KeyError:
247 raise KeyError("{!r} is not registered".format(fileobj)) from None
248 if events != key.events:
249 self.unregister(fileobj)
250 key = self.register(fileobj, events, data)
251 elif data != key.data:
252 # Use a shortcut to update the data.
253 key = key._replace(data=data)
254 self._fd_to_key[key.fd] = key
255 return key
256
257 def close(self):
258 self._fd_to_key.clear()
Victor Stinner587feb12015-01-09 21:34:27 +0100259 self._map = None
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100260
261 def get_map(self):
262 return self._map
263
Charles-François Natali243d8d82013-09-04 19:02:49 +0200264 def _key_from_fd(self, fd):
265 """Return the key associated to a given file descriptor.
266
267 Parameters:
268 fd -- file descriptor
269
270 Returns:
271 corresponding key, or None if not found
272 """
273 try:
274 return self._fd_to_key[fd]
275 except KeyError:
276 return None
277
278
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100279class SelectSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200280 """Select-based selector."""
281
282 def __init__(self):
283 super().__init__()
284 self._readers = set()
285 self._writers = set()
286
287 def register(self, fileobj, events, data=None):
288 key = super().register(fileobj, events, data)
289 if events & EVENT_READ:
290 self._readers.add(key.fd)
291 if events & EVENT_WRITE:
292 self._writers.add(key.fd)
293 return key
294
295 def unregister(self, fileobj):
296 key = super().unregister(fileobj)
297 self._readers.discard(key.fd)
298 self._writers.discard(key.fd)
299 return key
300
301 if sys.platform == 'win32':
302 def _select(self, r, w, _, timeout=None):
303 r, w, x = select.select(r, w, w, timeout)
304 return r, w + x, []
305 else:
306 _select = select.select
307
308 def select(self, timeout=None):
309 timeout = None if timeout is None else max(timeout, 0)
310 ready = []
311 try:
312 r, w, _ = self._select(self._readers, self._writers, [], timeout)
313 except InterruptedError:
314 return ready
315 r = set(r)
316 w = set(w)
317 for fd in r | w:
318 events = 0
319 if fd in r:
320 events |= EVENT_READ
321 if fd in w:
322 events |= EVENT_WRITE
323
324 key = self._key_from_fd(fd)
325 if key:
326 ready.append((key, events & key.events))
327 return ready
328
329
330if hasattr(select, 'poll'):
331
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100332 class PollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200333 """Poll-based selector."""
334
335 def __init__(self):
336 super().__init__()
337 self._poll = select.poll()
338
339 def register(self, fileobj, events, data=None):
340 key = super().register(fileobj, events, data)
341 poll_events = 0
342 if events & EVENT_READ:
343 poll_events |= select.POLLIN
344 if events & EVENT_WRITE:
345 poll_events |= select.POLLOUT
346 self._poll.register(key.fd, poll_events)
347 return key
348
349 def unregister(self, fileobj):
350 key = super().unregister(fileobj)
351 self._poll.unregister(key.fd)
352 return key
353
354 def select(self, timeout=None):
Victor Stinner11da8e22014-01-21 01:48:28 +0100355 if timeout is None:
356 timeout = None
Victor Stinner7067b5d2014-01-21 17:49:41 +0100357 elif timeout <= 0:
Victor Stinner11da8e22014-01-21 01:48:28 +0100358 timeout = 0
359 else:
Victor Stinnerdcd97402014-01-31 12:12:53 +0100360 # poll() has a resolution of 1 millisecond, round away from
361 # zero to wait *at least* timeout seconds.
Victor Stinner665758f2014-01-31 16:24:21 +0100362 timeout = math.ceil(timeout * 1e3)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200363 ready = []
364 try:
365 fd_event_list = self._poll.poll(timeout)
366 except InterruptedError:
367 return ready
368 for fd, event in fd_event_list:
369 events = 0
370 if event & ~select.POLLIN:
371 events |= EVENT_WRITE
372 if event & ~select.POLLOUT:
373 events |= EVENT_READ
374
375 key = self._key_from_fd(fd)
376 if key:
377 ready.append((key, events & key.events))
378 return ready
379
380
381if hasattr(select, 'epoll'):
382
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100383 class EpollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200384 """Epoll-based selector."""
385
386 def __init__(self):
387 super().__init__()
388 self._epoll = select.epoll()
389
390 def fileno(self):
391 return self._epoll.fileno()
392
393 def register(self, fileobj, events, data=None):
394 key = super().register(fileobj, events, data)
395 epoll_events = 0
396 if events & EVENT_READ:
397 epoll_events |= select.EPOLLIN
398 if events & EVENT_WRITE:
399 epoll_events |= select.EPOLLOUT
400 self._epoll.register(key.fd, epoll_events)
401 return key
402
403 def unregister(self, fileobj):
404 key = super().unregister(fileobj)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800405 try:
406 self._epoll.unregister(key.fd)
407 except OSError:
408 # This can happen if the FD was closed since it
409 # was registered.
410 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200411 return key
412
413 def select(self, timeout=None):
Victor Stinner567b26e2014-01-21 21:00:47 +0100414 if timeout is None:
415 timeout = -1
416 elif timeout <= 0:
417 timeout = 0
Victor Stinnerdcd97402014-01-31 12:12:53 +0100418 else:
419 # epoll_wait() has a resolution of 1 millisecond, round away
420 # from zero to wait *at least* timeout seconds.
421 timeout = math.ceil(timeout * 1e3) * 1e-3
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500422
Yury Selivanovdfc44e02014-12-08 12:30:10 -0500423 # epoll_wait() expects `maxevents` to be greater than zero;
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500424 # we want to make sure that `select()` can be called when no
425 # FD is registered.
426 max_ev = max(len(self._fd_to_key), 1)
427
Charles-François Natali243d8d82013-09-04 19:02:49 +0200428 ready = []
429 try:
430 fd_event_list = self._epoll.poll(timeout, max_ev)
431 except InterruptedError:
432 return ready
433 for fd, event in fd_event_list:
434 events = 0
435 if event & ~select.EPOLLIN:
436 events |= EVENT_WRITE
437 if event & ~select.EPOLLOUT:
438 events |= EVENT_READ
439
440 key = self._key_from_fd(fd)
441 if key:
442 ready.append((key, events & key.events))
443 return ready
444
445 def close(self):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200446 self._epoll.close()
Guido van Rossum61a2ced2013-10-31 11:01:40 -0700447 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200448
449
450if hasattr(select, 'kqueue'):
451
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100452 class KqueueSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200453 """Kqueue-based selector."""
454
455 def __init__(self):
456 super().__init__()
457 self._kqueue = select.kqueue()
458
459 def fileno(self):
460 return self._kqueue.fileno()
461
462 def register(self, fileobj, events, data=None):
463 key = super().register(fileobj, events, data)
464 if events & EVENT_READ:
465 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
466 select.KQ_EV_ADD)
467 self._kqueue.control([kev], 0, 0)
468 if events & EVENT_WRITE:
469 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
470 select.KQ_EV_ADD)
471 self._kqueue.control([kev], 0, 0)
472 return key
473
474 def unregister(self, fileobj):
475 key = super().unregister(fileobj)
476 if key.events & EVENT_READ:
477 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
478 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800479 try:
480 self._kqueue.control([kev], 0, 0)
481 except OSError:
482 # This can happen if the FD was closed since it
483 # was registered.
484 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200485 if key.events & EVENT_WRITE:
486 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
487 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800488 try:
489 self._kqueue.control([kev], 0, 0)
490 except OSError:
491 # See comment above.
492 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200493 return key
494
495 def select(self, timeout=None):
496 timeout = None if timeout is None else max(timeout, 0)
497 max_ev = len(self._fd_to_key)
498 ready = []
499 try:
500 kev_list = self._kqueue.control(None, max_ev, timeout)
501 except InterruptedError:
502 return ready
503 for kev in kev_list:
504 fd = kev.ident
505 flag = kev.filter
506 events = 0
507 if flag == select.KQ_FILTER_READ:
508 events |= EVENT_READ
509 if flag == select.KQ_FILTER_WRITE:
510 events |= EVENT_WRITE
511
512 key = self._key_from_fd(fd)
513 if key:
514 ready.append((key, events & key.events))
515 return ready
516
517 def close(self):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200518 self._kqueue.close()
Guido van Rossum61a2ced2013-10-31 11:01:40 -0700519 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200520
521
522# Choose the best implementation: roughly, epoll|kqueue > poll > select.
523# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
524if 'KqueueSelector' in globals():
525 DefaultSelector = KqueueSelector
526elif 'EpollSelector' in globals():
527 DefaultSelector = EpollSelector
528elif 'PollSelector' in globals():
529 DefaultSelector = PollSelector
530else:
531 DefaultSelector = SelectSelector