blob: e7bc51773025158cb32959a50b18b885b353acee [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
Serhiy Storchaka2e576f52017-04-24 09:05:00 +03009from collections import namedtuple
10from collections.abc import Mapping
Victor Stinnerdcd97402014-01-31 12:12:53 +010011import math
Charles-François Natali243d8d82013-09-04 19:02:49 +020012import select
13import sys
14
15
16# generic events, that must be mapped to implementation-specific ones
17EVENT_READ = (1 << 0)
18EVENT_WRITE = (1 << 1)
19
20
21def _fileobj_to_fd(fileobj):
22 """Return a file descriptor from a file object.
23
24 Parameters:
25 fileobj -- file object or file descriptor
26
27 Returns:
28 corresponding file descriptor
Guido van Rossum9710ff02013-12-07 15:57:01 -080029
30 Raises:
31 ValueError if the object is invalid
Charles-François Natali243d8d82013-09-04 19:02:49 +020032 """
33 if isinstance(fileobj, int):
34 fd = fileobj
35 else:
36 try:
37 fd = int(fileobj.fileno())
38 except (AttributeError, TypeError, ValueError):
39 raise ValueError("Invalid file object: "
40 "{!r}".format(fileobj)) from None
41 if fd < 0:
42 raise ValueError("Invalid file descriptor: {}".format(fd))
43 return fd
44
45
46SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
Charles-François Natali243d8d82013-09-04 19:02:49 +020047
Yury Selivanov0c6a3442016-03-02 10:37:59 -050048SelectorKey.__doc__ = """SelectorKey(fileobj, fd, events, data)
49
50 Object used to associate a file object to its backing
51 file descriptor, selected event mask, and attached data.
52"""
53if sys.version_info >= (3, 5):
54 SelectorKey.fileobj.__doc__ = 'File object registered.'
55 SelectorKey.fd.__doc__ = 'Underlying file descriptor.'
56 SelectorKey.events.__doc__ = 'Events that must be waited for on this file object.'
57 SelectorKey.data.__doc__ = ('''Optional opaque data associated to this file object.
58 For example, this could be used to store a per-client session ID.''')
Charles-François Natali243d8d82013-09-04 19:02:49 +020059
Charles-François Natali4574b492013-10-30 20:31:04 +010060class _SelectorMapping(Mapping):
61 """Mapping of file objects to selector keys."""
62
63 def __init__(self, selector):
64 self._selector = selector
65
66 def __len__(self):
67 return len(self._selector._fd_to_key)
68
69 def __getitem__(self, fileobj):
70 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -080071 fd = self._selector._fileobj_lookup(fileobj)
72 return self._selector._fd_to_key[fd]
Charles-François Natali4574b492013-10-30 20:31:04 +010073 except KeyError:
74 raise KeyError("{!r} is not registered".format(fileobj)) from None
75
76 def __iter__(self):
77 return iter(self._selector._fd_to_key)
78
79
Charles-François Natali243d8d82013-09-04 19:02:49 +020080class BaseSelector(metaclass=ABCMeta):
Charles-François Natalib3330a0a2013-12-01 11:04:17 +010081 """Selector abstract base class.
Charles-François Natali243d8d82013-09-04 19:02:49 +020082
83 A selector supports registering file objects to be monitored for specific
84 I/O events.
85
86 A file object is a file descriptor or any object with a `fileno()` method.
87 An arbitrary object can be attached to the file object, which can be used
88 for example to store context information, a callback, etc.
89
90 A selector can use various implementations (select(), poll(), epoll()...)
91 depending on the platform. The default `Selector` class uses the most
Yury Selivanovb0b0e622014-02-18 22:27:48 -050092 efficient implementation on the current platform.
Charles-François Natali243d8d82013-09-04 19:02:49 +020093 """
94
Charles-François Natalib3330a0a2013-12-01 11:04:17 +010095 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +020096 def register(self, fileobj, events, data=None):
97 """Register a file object.
98
99 Parameters:
100 fileobj -- file object or file descriptor
101 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
102 data -- attached data
103
104 Returns:
105 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800106
107 Raises:
108 ValueError if events is invalid
109 KeyError if fileobj is already registered
110 OSError if fileobj is closed or otherwise is unacceptable to
111 the underlying system call (if a system call is made)
112
113 Note:
114 OSError may or may not be raised
Charles-François Natali243d8d82013-09-04 19:02:49 +0200115 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100116 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200117
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100118 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +0200119 def unregister(self, fileobj):
120 """Unregister a file object.
121
122 Parameters:
123 fileobj -- file object or file descriptor
124
125 Returns:
126 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800127
128 Raises:
129 KeyError if fileobj is not registered
130
131 Note:
132 If fileobj is registered but has since been closed this does
133 *not* raise OSError (even if the wrapped syscall does)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200134 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100135 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200136
137 def modify(self, fileobj, events, data=None):
138 """Change a registered file object monitored events or attached data.
139
140 Parameters:
141 fileobj -- file object or file descriptor
142 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
143 data -- attached data
144
145 Returns:
146 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800147
148 Raises:
149 Anything that unregister() or register() raises
Charles-François Natali243d8d82013-09-04 19:02:49 +0200150 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100151 self.unregister(fileobj)
152 return self.register(fileobj, events, data)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200153
154 @abstractmethod
155 def select(self, timeout=None):
156 """Perform the actual selection, until some monitored file objects are
157 ready or a timeout expires.
158
159 Parameters:
160 timeout -- if timeout > 0, this specifies the maximum wait time, in
161 seconds
162 if timeout <= 0, the select() call won't block, and will
163 report the currently ready file objects
164 if timeout is None, select() will block until a monitored
165 file object becomes ready
166
167 Returns:
168 list of (key, events) for ready file objects
169 `events` is a bitwise mask of EVENT_READ|EVENT_WRITE
170 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100171 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200172
173 def close(self):
174 """Close the selector.
175
176 This must be called to make sure that any underlying resource is freed.
177 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100178 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200179
180 def get_key(self, fileobj):
181 """Return the key associated to a registered file object.
182
183 Returns:
184 SelectorKey for this file object
185 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100186 mapping = self.get_map()
Victor Stinner458fc6f2015-01-13 10:00:55 +0100187 if mapping is None:
188 raise RuntimeError('Selector is closed')
Charles-François Natali243d8d82013-09-04 19:02:49 +0200189 try:
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100190 return mapping[fileobj]
Charles-François Natali243d8d82013-09-04 19:02:49 +0200191 except KeyError:
192 raise KeyError("{!r} is not registered".format(fileobj)) from None
193
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100194 @abstractmethod
Charles-François Natali4574b492013-10-30 20:31:04 +0100195 def get_map(self):
196 """Return a mapping of file objects to selector keys."""
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100197 raise NotImplementedError
Charles-François Natali4574b492013-10-30 20:31:04 +0100198
Charles-François Natali243d8d82013-09-04 19:02:49 +0200199 def __enter__(self):
200 return self
201
202 def __exit__(self, *args):
203 self.close()
204
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100205
206class _BaseSelectorImpl(BaseSelector):
207 """Base selector implementation."""
208
209 def __init__(self):
210 # this maps file descriptors to keys
211 self._fd_to_key = {}
212 # read-only mapping returned by get_map()
213 self._map = _SelectorMapping(self)
214
Guido van Rossum9710ff02013-12-07 15:57:01 -0800215 def _fileobj_lookup(self, fileobj):
216 """Return a file descriptor from a file object.
217
218 This wraps _fileobj_to_fd() to do an exhaustive search in case
219 the object is invalid but we still have it in our map. This
220 is used by unregister() so we can unregister an object that
221 was previously registered even if it is closed. It is also
222 used by _SelectorMapping.
223 """
224 try:
225 return _fileobj_to_fd(fileobj)
226 except ValueError:
227 # Do an exhaustive search.
228 for key in self._fd_to_key.values():
229 if key.fileobj is fileobj:
230 return key.fd
231 # Raise ValueError after all.
232 raise
233
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100234 def register(self, fileobj, events, data=None):
235 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
236 raise ValueError("Invalid events: {!r}".format(events))
237
Guido van Rossum9710ff02013-12-07 15:57:01 -0800238 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100239
240 if key.fd in self._fd_to_key:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800241 raise KeyError("{!r} (FD {}) is already registered"
242 .format(fileobj, key.fd))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100243
244 self._fd_to_key[key.fd] = key
245 return key
246
247 def unregister(self, fileobj):
248 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800249 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100250 except KeyError:
251 raise KeyError("{!r} is not registered".format(fileobj)) from None
252 return key
253
254 def modify(self, fileobj, events, data=None):
255 # TODO: Subclasses can probably optimize this even further.
256 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800257 key = self._fd_to_key[self._fileobj_lookup(fileobj)]
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100258 except KeyError:
259 raise KeyError("{!r} is not registered".format(fileobj)) from None
260 if events != key.events:
261 self.unregister(fileobj)
262 key = self.register(fileobj, events, data)
263 elif data != key.data:
264 # Use a shortcut to update the data.
265 key = key._replace(data=data)
266 self._fd_to_key[key.fd] = key
267 return key
268
269 def close(self):
270 self._fd_to_key.clear()
Victor Stinner38dc2502015-01-13 09:58:33 +0100271 self._map = None
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100272
273 def get_map(self):
274 return self._map
275
Charles-François Natali243d8d82013-09-04 19:02:49 +0200276 def _key_from_fd(self, fd):
277 """Return the key associated to a given file descriptor.
278
279 Parameters:
280 fd -- file descriptor
281
282 Returns:
283 corresponding key, or None if not found
284 """
285 try:
286 return self._fd_to_key[fd]
287 except KeyError:
288 return None
289
290
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100291class SelectSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200292 """Select-based selector."""
293
294 def __init__(self):
295 super().__init__()
296 self._readers = set()
297 self._writers = set()
298
299 def register(self, fileobj, events, data=None):
300 key = super().register(fileobj, events, data)
301 if events & EVENT_READ:
302 self._readers.add(key.fd)
303 if events & EVENT_WRITE:
304 self._writers.add(key.fd)
305 return key
306
307 def unregister(self, fileobj):
308 key = super().unregister(fileobj)
309 self._readers.discard(key.fd)
310 self._writers.discard(key.fd)
311 return key
312
313 if sys.platform == 'win32':
314 def _select(self, r, w, _, timeout=None):
315 r, w, x = select.select(r, w, w, timeout)
316 return r, w + x, []
317 else:
318 _select = select.select
319
320 def select(self, timeout=None):
321 timeout = None if timeout is None else max(timeout, 0)
322 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400323 try:
324 r, w, _ = self._select(self._readers, self._writers, [], timeout)
325 except InterruptedError:
326 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200327 r = set(r)
328 w = set(w)
329 for fd in r | w:
330 events = 0
331 if fd in r:
332 events |= EVENT_READ
333 if fd in w:
334 events |= EVENT_WRITE
335
336 key = self._key_from_fd(fd)
337 if key:
338 ready.append((key, events & key.events))
339 return ready
340
341
342if hasattr(select, 'poll'):
343
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100344 class PollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200345 """Poll-based selector."""
346
347 def __init__(self):
348 super().__init__()
349 self._poll = select.poll()
350
351 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 Stinnerdcd97402014-01-31 12:12:53 +0100372 # poll() has a resolution of 1 millisecond, round away from
373 # zero to wait *at least* timeout seconds.
Victor Stinner665758f2014-01-31 16:24:21 +0100374 timeout = math.ceil(timeout * 1e3)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200375 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400376 try:
377 fd_event_list = self._poll.poll(timeout)
378 except InterruptedError:
379 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200380 for fd, event in fd_event_list:
381 events = 0
382 if event & ~select.POLLIN:
383 events |= EVENT_WRITE
384 if event & ~select.POLLOUT:
385 events |= EVENT_READ
386
387 key = self._key_from_fd(fd)
388 if key:
389 ready.append((key, events & key.events))
390 return ready
391
392
393if hasattr(select, 'epoll'):
394
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100395 class EpollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200396 """Epoll-based selector."""
397
398 def __init__(self):
399 super().__init__()
400 self._epoll = select.epoll()
401
402 def fileno(self):
403 return self._epoll.fileno()
404
405 def register(self, fileobj, events, data=None):
406 key = super().register(fileobj, events, data)
407 epoll_events = 0
408 if events & EVENT_READ:
409 epoll_events |= select.EPOLLIN
410 if events & EVENT_WRITE:
411 epoll_events |= select.EPOLLOUT
Yury Selivanov525aedc2016-09-15 19:30:42 -0400412 try:
413 self._epoll.register(key.fd, epoll_events)
414 except BaseException:
415 super().unregister(fileobj)
416 raise
Charles-François Natali243d8d82013-09-04 19:02:49 +0200417 return key
418
419 def unregister(self, fileobj):
420 key = super().unregister(fileobj)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800421 try:
422 self._epoll.unregister(key.fd)
423 except OSError:
424 # This can happen if the FD was closed since it
425 # was registered.
426 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200427 return key
428
429 def select(self, timeout=None):
Victor Stinner567b26e2014-01-21 21:00:47 +0100430 if timeout is None:
431 timeout = -1
432 elif timeout <= 0:
433 timeout = 0
Victor Stinnerdcd97402014-01-31 12:12:53 +0100434 else:
435 # epoll_wait() has a resolution of 1 millisecond, round away
436 # from zero to wait *at least* timeout seconds.
437 timeout = math.ceil(timeout * 1e3) * 1e-3
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500438
Yury Selivanovdfc44e02014-12-08 12:30:10 -0500439 # epoll_wait() expects `maxevents` to be greater than zero;
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500440 # we want to make sure that `select()` can be called when no
441 # FD is registered.
442 max_ev = max(len(self._fd_to_key), 1)
443
Charles-François Natali243d8d82013-09-04 19:02:49 +0200444 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400445 try:
446 fd_event_list = self._epoll.poll(timeout, max_ev)
447 except InterruptedError:
448 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200449 for fd, event in fd_event_list:
450 events = 0
451 if event & ~select.EPOLLIN:
452 events |= EVENT_WRITE
453 if event & ~select.EPOLLOUT:
454 events |= EVENT_READ
455
456 key = self._key_from_fd(fd)
457 if key:
458 ready.append((key, events & key.events))
459 return ready
460
461 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400462 self._epoll.close()
463 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200464
465
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100466if hasattr(select, 'devpoll'):
467
468 class DevpollSelector(_BaseSelectorImpl):
469 """Solaris /dev/poll selector."""
470
471 def __init__(self):
472 super().__init__()
473 self._devpoll = select.devpoll()
474
475 def fileno(self):
476 return self._devpoll.fileno()
477
478 def register(self, fileobj, events, data=None):
479 key = super().register(fileobj, events, data)
480 poll_events = 0
481 if events & EVENT_READ:
482 poll_events |= select.POLLIN
483 if events & EVENT_WRITE:
484 poll_events |= select.POLLOUT
485 self._devpoll.register(key.fd, poll_events)
486 return key
487
488 def unregister(self, fileobj):
489 key = super().unregister(fileobj)
490 self._devpoll.unregister(key.fd)
491 return key
492
493 def select(self, timeout=None):
494 if timeout is None:
495 timeout = None
496 elif timeout <= 0:
497 timeout = 0
498 else:
499 # devpoll() has a resolution of 1 millisecond, round away from
500 # zero to wait *at least* timeout seconds.
501 timeout = math.ceil(timeout * 1e3)
502 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400503 try:
504 fd_event_list = self._devpoll.poll(timeout)
505 except InterruptedError:
506 return ready
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100507 for fd, event in fd_event_list:
508 events = 0
509 if event & ~select.POLLIN:
510 events |= EVENT_WRITE
511 if event & ~select.POLLOUT:
512 events |= EVENT_READ
513
514 key = self._key_from_fd(fd)
515 if key:
516 ready.append((key, events & key.events))
517 return ready
518
519 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400520 self._devpoll.close()
521 super().close()
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100522
523
Charles-François Natali243d8d82013-09-04 19:02:49 +0200524if hasattr(select, 'kqueue'):
525
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100526 class KqueueSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200527 """Kqueue-based selector."""
528
529 def __init__(self):
530 super().__init__()
531 self._kqueue = select.kqueue()
532
533 def fileno(self):
534 return self._kqueue.fileno()
535
536 def register(self, fileobj, events, data=None):
537 key = super().register(fileobj, events, data)
Yury Selivanov525aedc2016-09-15 19:30:42 -0400538 try:
539 if events & EVENT_READ:
540 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
541 select.KQ_EV_ADD)
542 self._kqueue.control([kev], 0, 0)
543 if events & EVENT_WRITE:
544 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
545 select.KQ_EV_ADD)
546 self._kqueue.control([kev], 0, 0)
547 except BaseException:
548 super().unregister(fileobj)
549 raise
Charles-François Natali243d8d82013-09-04 19:02:49 +0200550 return key
551
552 def unregister(self, fileobj):
553 key = super().unregister(fileobj)
554 if key.events & EVENT_READ:
555 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
556 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800557 try:
558 self._kqueue.control([kev], 0, 0)
559 except OSError:
560 # This can happen if the FD was closed since it
561 # was registered.
562 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200563 if key.events & EVENT_WRITE:
564 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
565 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800566 try:
567 self._kqueue.control([kev], 0, 0)
568 except OSError:
569 # See comment above.
570 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200571 return key
572
573 def select(self, timeout=None):
574 timeout = None if timeout is None else max(timeout, 0)
575 max_ev = len(self._fd_to_key)
576 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400577 try:
578 kev_list = self._kqueue.control(None, max_ev, timeout)
579 except InterruptedError:
580 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200581 for kev in kev_list:
582 fd = kev.ident
583 flag = kev.filter
584 events = 0
585 if flag == select.KQ_FILTER_READ:
586 events |= EVENT_READ
587 if flag == select.KQ_FILTER_WRITE:
588 events |= EVENT_WRITE
589
590 key = self._key_from_fd(fd)
591 if key:
592 ready.append((key, events & key.events))
593 return ready
594
595 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400596 self._kqueue.close()
597 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200598
599
Victor Stinner53a6d742015-01-09 00:13:39 +0100600# Choose the best implementation, roughly:
601# epoll|kqueue|devpoll > poll > select.
Charles-François Natali243d8d82013-09-04 19:02:49 +0200602# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
603if 'KqueueSelector' in globals():
604 DefaultSelector = KqueueSelector
605elif 'EpollSelector' in globals():
606 DefaultSelector = EpollSelector
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100607elif 'DevpollSelector' in globals():
608 DefaultSelector = DevpollSelector
Charles-François Natali243d8d82013-09-04 19:02:49 +0200609elif 'PollSelector' in globals():
610 DefaultSelector = PollSelector
611else:
612 DefaultSelector = SelectSelector