comparison mercurial/thirdparty/selectors2.py @ 35245:414114a7c18f

thirdparty: move selectors2 module to where it should be
author Yuya Nishihara <yuya@tcha.org>
date Thu, 30 Nov 2017 22:43:03 +0900
parents mercurial/selectors2.py@a568a46751b6
children d1bda397df73
comparison
equal deleted inserted replaced
35244:98f97eb20597 35245:414114a7c18f
1 """ Back-ported, durable, and portable selectors """
2
3 # MIT License
4 #
5 # Copyright (c) 2017 Seth Michael Larson
6 #
7 # Permission is hereby granted, free of charge, to any person obtaining a copy
8 # of this software and associated documentation files (the "Software"), to deal
9 # in the Software without restriction, including without limitation the rights
10 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 # copies of the Software, and to permit persons to whom the Software is
12 # furnished to do so, subject to the following conditions:
13 #
14 # The above copyright notice and this permission notice shall be included in all
15 # copies or substantial portions of the Software.
16 #
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 # SOFTWARE.
24
25 from __future__ import absolute_import
26
27 import collections
28 import errno
29 import math
30 import select
31 import socket
32 import sys
33 import time
34
35 from .. import pycompat
36
37 namedtuple = collections.namedtuple
38 Mapping = collections.Mapping
39
40 try:
41 monotonic = time.monotonic
42 except AttributeError:
43 monotonic = time.time
44
45 __author__ = 'Seth Michael Larson'
46 __email__ = 'sethmichaellarson@protonmail.com'
47 __version__ = '2.0.0'
48 __license__ = 'MIT'
49 __url__ = 'https://www.github.com/SethMichaelLarson/selectors2'
50
51 __all__ = ['EVENT_READ',
52 'EVENT_WRITE',
53 'SelectorKey',
54 'DefaultSelector',
55 'BaseSelector']
56
57 EVENT_READ = (1 << 0)
58 EVENT_WRITE = (1 << 1)
59 _DEFAULT_SELECTOR = None
60 _SYSCALL_SENTINEL = object() # Sentinel in case a system call returns None.
61 _ERROR_TYPES = (OSError, IOError, socket.error)
62
63
64 SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data'])
65
66
67 class _SelectorMapping(Mapping):
68 """ Mapping of file objects to selector keys """
69
70 def __init__(self, selector):
71 self._selector = selector
72
73 def __len__(self):
74 return len(self._selector._fd_to_key)
75
76 def __getitem__(self, fileobj):
77 try:
78 fd = self._selector._fileobj_lookup(fileobj)
79 return self._selector._fd_to_key[fd]
80 except KeyError:
81 raise KeyError("{0!r} is not registered.".format(fileobj))
82
83 def __iter__(self):
84 return iter(self._selector._fd_to_key)
85
86
87 def _fileobj_to_fd(fileobj):
88 """ Return a file descriptor from a file object. If
89 given an integer will simply return that integer back. """
90 if isinstance(fileobj, int):
91 fd = fileobj
92 else:
93 try:
94 fd = int(fileobj.fileno())
95 except (AttributeError, TypeError, ValueError):
96 raise ValueError("Invalid file object: {0!r}".format(fileobj))
97 if fd < 0:
98 raise ValueError("Invalid file descriptor: {0}".format(fd))
99 return fd
100
101
102 class BaseSelector(object):
103 """ Abstract Selector class
104
105 A selector supports registering file objects to be monitored
106 for specific I/O events.
107
108 A file object is a file descriptor or any object with a
109 `fileno()` method. An arbitrary object can be attached to the
110 file object which can be used for example to store context info,
111 a callback, etc.
112
113 A selector can use various implementations (select(), poll(), epoll(),
114 and kqueue()) depending on the platform. The 'DefaultSelector' class uses
115 the most efficient implementation for the current platform.
116 """
117 def __init__(self):
118 # Maps file descriptors to keys.
119 self._fd_to_key = {}
120
121 # Read-only mapping returned by get_map()
122 self._map = _SelectorMapping(self)
123
124 def _fileobj_lookup(self, fileobj):
125 """ Return a file descriptor from a file object.
126 This wraps _fileobj_to_fd() to do an exhaustive
127 search in case the object is invalid but we still
128 have it in our map. Used by unregister() so we can
129 unregister an object that was previously registered
130 even if it is closed. It is also used by _SelectorMapping
131 """
132 try:
133 return _fileobj_to_fd(fileobj)
134 except ValueError:
135
136 # Search through all our mapped keys.
137 for key in self._fd_to_key.values():
138 if key.fileobj is fileobj:
139 return key.fd
140
141 # Raise ValueError after all.
142 raise
143
144 def register(self, fileobj, events, data=None):
145 """ Register a file object for a set of events to monitor. """
146 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
147 raise ValueError("Invalid events: {0!r}".format(events))
148
149 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
150
151 if key.fd in self._fd_to_key:
152 raise KeyError("{0!r} (FD {1}) is already registered"
153 .format(fileobj, key.fd))
154
155 self._fd_to_key[key.fd] = key
156 return key
157
158 def unregister(self, fileobj):
159 """ Unregister a file object from being monitored. """
160 try:
161 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
162 except KeyError:
163 raise KeyError("{0!r} is not registered".format(fileobj))
164
165 # Getting the fileno of a closed socket on Windows errors with EBADF.
166 except socket.error as err:
167 if err.errno != errno.EBADF:
168 raise
169 else:
170 for key in self._fd_to_key.values():
171 if key.fileobj is fileobj:
172 self._fd_to_key.pop(key.fd)
173 break
174 else:
175 raise KeyError("{0!r} is not registered".format(fileobj))
176 return key
177
178 def modify(self, fileobj, events, data=None):
179 """ Change a registered file object monitored events and data. """
180 # NOTE: Some subclasses optimize this operation even further.
181 try:
182 key = self._fd_to_key[self._fileobj_lookup(fileobj)]
183 except KeyError:
184 raise KeyError("{0!r} is not registered".format(fileobj))
185
186 if events != key.events:
187 self.unregister(fileobj)
188 key = self.register(fileobj, events, data)
189
190 elif data != key.data:
191 # Use a shortcut to update the data.
192 key = key._replace(data=data)
193 self._fd_to_key[key.fd] = key
194
195 return key
196
197 def select(self, timeout=None):
198 """ Perform the actual selection until some monitored file objects
199 are ready or the timeout expires. """
200 raise NotImplementedError()
201
202 def close(self):
203 """ Close the selector. This must be called to ensure that all
204 underlying resources are freed. """
205 self._fd_to_key.clear()
206 self._map = None
207
208 def get_key(self, fileobj):
209 """ Return the key associated with a registered file object. """
210 mapping = self.get_map()
211 if mapping is None:
212 raise RuntimeError("Selector is closed")
213 try:
214 return mapping[fileobj]
215 except KeyError:
216 raise KeyError("{0!r} is not registered".format(fileobj))
217
218 def get_map(self):
219 """ Return a mapping of file objects to selector keys """
220 return self._map
221
222 def _key_from_fd(self, fd):
223 """ Return the key associated to a given file descriptor
224 Return None if it is not found. """
225 try:
226 return self._fd_to_key[fd]
227 except KeyError:
228 return None
229
230 def __enter__(self):
231 return self
232
233 def __exit__(self, *_):
234 self.close()
235
236
237 # Almost all platforms have select.select()
238 if hasattr(select, "select"):
239 class SelectSelector(BaseSelector):
240 """ Select-based selector. """
241 def __init__(self):
242 super(SelectSelector, self).__init__()
243 self._readers = set()
244 self._writers = set()
245
246 def register(self, fileobj, events, data=None):
247 key = super(SelectSelector, self).register(fileobj, events, data)
248 if events & EVENT_READ:
249 self._readers.add(key.fd)
250 if events & EVENT_WRITE:
251 self._writers.add(key.fd)
252 return key
253
254 def unregister(self, fileobj):
255 key = super(SelectSelector, self).unregister(fileobj)
256 self._readers.discard(key.fd)
257 self._writers.discard(key.fd)
258 return key
259
260 def select(self, timeout=None):
261 # Selecting on empty lists on Windows errors out.
262 if not len(self._readers) and not len(self._writers):
263 return []
264
265 timeout = None if timeout is None else max(timeout, 0.0)
266 ready = []
267 r, w, _ = _syscall_wrapper(self._wrap_select, True, self._readers,
268 self._writers, timeout)
269 r = set(r)
270 w = set(w)
271 for fd in r | w:
272 events = 0
273 if fd in r:
274 events |= EVENT_READ
275 if fd in w:
276 events |= EVENT_WRITE
277
278 key = self._key_from_fd(fd)
279 if key:
280 ready.append((key, events & key.events))
281 return ready
282
283 def _wrap_select(self, r, w, timeout=None):
284 """ Wrapper for select.select because timeout is a positional arg """
285 return select.select(r, w, [], timeout)
286
287 __all__.append('SelectSelector')
288
289 # Jython has a different implementation of .fileno() for socket objects.
290 if pycompat.isjython:
291 class _JythonSelectorMapping(object):
292 """ This is an implementation of _SelectorMapping that is built
293 for use specifically with Jython, which does not provide a hashable
294 value from socket.socket.fileno(). """
295
296 def __init__(self, selector):
297 assert isinstance(selector, JythonSelectSelector)
298 self._selector = selector
299
300 def __len__(self):
301 return len(self._selector._sockets)
302
303 def __getitem__(self, fileobj):
304 for sock, key in self._selector._sockets:
305 if sock is fileobj:
306 return key
307 else:
308 raise KeyError("{0!r} is not registered.".format(fileobj))
309
310 class JythonSelectSelector(SelectSelector):
311 """ This is an implementation of SelectSelector that is for Jython
312 which works around that Jython's socket.socket.fileno() does not
313 return an integer fd value. All SelectorKey.fd will be equal to -1
314 and should not be used. This instead uses object id to compare fileobj
315 and will only use select.select as it's the only selector that allows
316 directly passing in socket objects rather than registering fds.
317 See: http://bugs.jython.org/issue1678
318 https://wiki.python.org/jython/NewSocketModule#socket.fileno.28.29_does_not_return_an_integer
319 """
320
321 def __init__(self):
322 super(JythonSelectSelector, self).__init__()
323
324 self._sockets = [] # Uses a list of tuples instead of dictionary.
325 self._map = _JythonSelectorMapping(self)
326 self._readers = []
327 self._writers = []
328
329 # Jython has a select.cpython_compatible_select function in older versions.
330 self._select_func = getattr(select, 'cpython_compatible_select', select.select)
331
332 def register(self, fileobj, events, data=None):
333 for sock, _ in self._sockets:
334 if sock is fileobj:
335 raise KeyError("{0!r} is already registered"
336 .format(fileobj, sock))
337
338 key = SelectorKey(fileobj, -1, events, data)
339 self._sockets.append((fileobj, key))
340
341 if events & EVENT_READ:
342 self._readers.append(fileobj)
343 if events & EVENT_WRITE:
344 self._writers.append(fileobj)
345 return key
346
347 def unregister(self, fileobj):
348 for i, (sock, key) in enumerate(self._sockets):
349 if sock is fileobj:
350 break
351 else:
352 raise KeyError("{0!r} is not registered.".format(fileobj))
353
354 if key.events & EVENT_READ:
355 self._readers.remove(fileobj)
356 if key.events & EVENT_WRITE:
357 self._writers.remove(fileobj)
358
359 del self._sockets[i]
360 return key
361
362 def _wrap_select(self, r, w, timeout=None):
363 """ Wrapper for select.select because timeout is a positional arg """
364 return self._select_func(r, w, [], timeout)
365
366 __all__.append('JythonSelectSelector')
367 SelectSelector = JythonSelectSelector # Override so the wrong selector isn't used.
368
369
370 if hasattr(select, "poll"):
371 class PollSelector(BaseSelector):
372 """ Poll-based selector """
373 def __init__(self):
374 super(PollSelector, self).__init__()
375 self._poll = select.poll()
376
377 def register(self, fileobj, events, data=None):
378 key = super(PollSelector, self).register(fileobj, events, data)
379 event_mask = 0
380 if events & EVENT_READ:
381 event_mask |= select.POLLIN
382 if events & EVENT_WRITE:
383 event_mask |= select.POLLOUT
384 self._poll.register(key.fd, event_mask)
385 return key
386
387 def unregister(self, fileobj):
388 key = super(PollSelector, self).unregister(fileobj)
389 self._poll.unregister(key.fd)
390 return key
391
392 def _wrap_poll(self, timeout=None):
393 """ Wrapper function for select.poll.poll() so that
394 _syscall_wrapper can work with only seconds. """
395 if timeout is not None:
396 if timeout <= 0:
397 timeout = 0
398 else:
399 # select.poll.poll() has a resolution of 1 millisecond,
400 # round away from zero to wait *at least* timeout seconds.
401 timeout = math.ceil(timeout * 1000)
402
403 result = self._poll.poll(timeout)
404 return result
405
406 def select(self, timeout=None):
407 ready = []
408 fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout)
409 for fd, event_mask in fd_events:
410 events = 0
411 if event_mask & ~select.POLLIN:
412 events |= EVENT_WRITE
413 if event_mask & ~select.POLLOUT:
414 events |= EVENT_READ
415
416 key = self._key_from_fd(fd)
417 if key:
418 ready.append((key, events & key.events))
419
420 return ready
421
422 __all__.append('PollSelector')
423
424 if hasattr(select, "epoll"):
425 class EpollSelector(BaseSelector):
426 """ Epoll-based selector """
427 def __init__(self):
428 super(EpollSelector, self).__init__()
429 self._epoll = select.epoll()
430
431 def fileno(self):
432 return self._epoll.fileno()
433
434 def register(self, fileobj, events, data=None):
435 key = super(EpollSelector, self).register(fileobj, events, data)
436 events_mask = 0
437 if events & EVENT_READ:
438 events_mask |= select.EPOLLIN
439 if events & EVENT_WRITE:
440 events_mask |= select.EPOLLOUT
441 _syscall_wrapper(self._epoll.register, False, key.fd, events_mask)
442 return key
443
444 def unregister(self, fileobj):
445 key = super(EpollSelector, self).unregister(fileobj)
446 try:
447 _syscall_wrapper(self._epoll.unregister, False, key.fd)
448 except _ERROR_TYPES:
449 # This can occur when the fd was closed since registry.
450 pass
451 return key
452
453 def select(self, timeout=None):
454 if timeout is not None:
455 if timeout <= 0:
456 timeout = 0.0
457 else:
458 # select.epoll.poll() has a resolution of 1 millisecond
459 # but luckily takes seconds so we don't need a wrapper
460 # like PollSelector. Just for better rounding.
461 timeout = math.ceil(timeout * 1000) * 0.001
462 timeout = float(timeout)
463 else:
464 timeout = -1.0 # epoll.poll() must have a float.
465
466 # We always want at least 1 to ensure that select can be called
467 # with no file descriptors registered. Otherwise will fail.
468 max_events = max(len(self._fd_to_key), 1)
469
470 ready = []
471 fd_events = _syscall_wrapper(self._epoll.poll, True,
472 timeout=timeout,
473 maxevents=max_events)
474 for fd, event_mask in fd_events:
475 events = 0
476 if event_mask & ~select.EPOLLIN:
477 events |= EVENT_WRITE
478 if event_mask & ~select.EPOLLOUT:
479 events |= EVENT_READ
480
481 key = self._key_from_fd(fd)
482 if key:
483 ready.append((key, events & key.events))
484 return ready
485
486 def close(self):
487 self._epoll.close()
488 super(EpollSelector, self).close()
489
490 __all__.append('EpollSelector')
491
492
493 if hasattr(select, "devpoll"):
494 class DevpollSelector(BaseSelector):
495 """Solaris /dev/poll selector."""
496
497 def __init__(self):
498 super(DevpollSelector, self).__init__()
499 self._devpoll = select.devpoll()
500
501 def fileno(self):
502 return self._devpoll.fileno()
503
504 def register(self, fileobj, events, data=None):
505 key = super(DevpollSelector, self).register(fileobj, events, data)
506 poll_events = 0
507 if events & EVENT_READ:
508 poll_events |= select.POLLIN
509 if events & EVENT_WRITE:
510 poll_events |= select.POLLOUT
511 self._devpoll.register(key.fd, poll_events)
512 return key
513
514 def unregister(self, fileobj):
515 key = super(DevpollSelector, self).unregister(fileobj)
516 self._devpoll.unregister(key.fd)
517 return key
518
519 def _wrap_poll(self, timeout=None):
520 """ Wrapper function for select.poll.poll() so that
521 _syscall_wrapper can work with only seconds. """
522 if timeout is not None:
523 if timeout <= 0:
524 timeout = 0
525 else:
526 # select.devpoll.poll() has a resolution of 1 millisecond,
527 # round away from zero to wait *at least* timeout seconds.
528 timeout = math.ceil(timeout * 1000)
529
530 result = self._devpoll.poll(timeout)
531 return result
532
533 def select(self, timeout=None):
534 ready = []
535 fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout)
536 for fd, event_mask in fd_events:
537 events = 0
538 if event_mask & ~select.POLLIN:
539 events |= EVENT_WRITE
540 if event_mask & ~select.POLLOUT:
541 events |= EVENT_READ
542
543 key = self._key_from_fd(fd)
544 if key:
545 ready.append((key, events & key.events))
546
547 return ready
548
549 def close(self):
550 self._devpoll.close()
551 super(DevpollSelector, self).close()
552
553 __all__.append('DevpollSelector')
554
555
556 if hasattr(select, "kqueue"):
557 class KqueueSelector(BaseSelector):
558 """ Kqueue / Kevent-based selector """
559 def __init__(self):
560 super(KqueueSelector, self).__init__()
561 self._kqueue = select.kqueue()
562
563 def fileno(self):
564 return self._kqueue.fileno()
565
566 def register(self, fileobj, events, data=None):
567 key = super(KqueueSelector, self).register(fileobj, events, data)
568 if events & EVENT_READ:
569 kevent = select.kevent(key.fd,
570 select.KQ_FILTER_READ,
571 select.KQ_EV_ADD)
572
573 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
574
575 if events & EVENT_WRITE:
576 kevent = select.kevent(key.fd,
577 select.KQ_FILTER_WRITE,
578 select.KQ_EV_ADD)
579
580 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
581
582 return key
583
584 def unregister(self, fileobj):
585 key = super(KqueueSelector, self).unregister(fileobj)
586 if key.events & EVENT_READ:
587 kevent = select.kevent(key.fd,
588 select.KQ_FILTER_READ,
589 select.KQ_EV_DELETE)
590 try:
591 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
592 except _ERROR_TYPES:
593 pass
594 if key.events & EVENT_WRITE:
595 kevent = select.kevent(key.fd,
596 select.KQ_FILTER_WRITE,
597 select.KQ_EV_DELETE)
598 try:
599 _syscall_wrapper(self._kqueue.control, False, [kevent], 0, 0)
600 except _ERROR_TYPES:
601 pass
602
603 return key
604
605 def select(self, timeout=None):
606 if timeout is not None:
607 timeout = max(timeout, 0)
608
609 max_events = len(self._fd_to_key) * 2
610 ready_fds = {}
611
612 kevent_list = _syscall_wrapper(self._kqueue.control, True,
613 None, max_events, timeout)
614
615 for kevent in kevent_list:
616 fd = kevent.ident
617 event_mask = kevent.filter
618 events = 0
619 if event_mask == select.KQ_FILTER_READ:
620 events |= EVENT_READ
621 if event_mask == select.KQ_FILTER_WRITE:
622 events |= EVENT_WRITE
623
624 key = self._key_from_fd(fd)
625 if key:
626 if key.fd not in ready_fds:
627 ready_fds[key.fd] = (key, events & key.events)
628 else:
629 old_events = ready_fds[key.fd][1]
630 ready_fds[key.fd] = (key, (events | old_events) & key.events)
631
632 return list(ready_fds.values())
633
634 def close(self):
635 self._kqueue.close()
636 super(KqueueSelector, self).close()
637
638 __all__.append('KqueueSelector')
639
640
641 def _can_allocate(struct):
642 """ Checks that select structs can be allocated by the underlying
643 operating system, not just advertised by the select module. We don't
644 check select() because we'll be hopeful that most platforms that
645 don't have it available will not advertise it. (ie: GAE) """
646 try:
647 # select.poll() objects won't fail until used.
648 if struct == 'poll':
649 p = select.poll()
650 p.poll(0)
651
652 # All others will fail on allocation.
653 else:
654 getattr(select, struct)().close()
655 return True
656 except (OSError, AttributeError):
657 return False
658
659
660 # Python 3.5 uses a more direct route to wrap system calls to increase speed.
661 if sys.version_info >= (3, 5):
662 def _syscall_wrapper(func, _, *args, **kwargs):
663 """ This is the short-circuit version of the below logic
664 because in Python 3.5+ all selectors restart system calls. """
665 return func(*args, **kwargs)
666 else:
667 def _syscall_wrapper(func, recalc_timeout, *args, **kwargs):
668 """ Wrapper function for syscalls that could fail due to EINTR.
669 All functions should be retried if there is time left in the timeout
670 in accordance with PEP 475. """
671 timeout = kwargs.get("timeout", None)
672 if timeout is None:
673 expires = None
674 recalc_timeout = False
675 else:
676 timeout = float(timeout)
677 if timeout < 0.0: # Timeout less than 0 treated as no timeout.
678 expires = None
679 else:
680 expires = monotonic() + timeout
681
682 args = list(args)
683 if recalc_timeout and "timeout" not in kwargs:
684 raise ValueError(
685 "Timeout must be in args or kwargs to be recalculated")
686
687 result = _SYSCALL_SENTINEL
688 while result is _SYSCALL_SENTINEL:
689 try:
690 result = func(*args, **kwargs)
691 # OSError is thrown by select.select
692 # IOError is thrown by select.epoll.poll
693 # select.error is thrown by select.poll.poll
694 # Aren't we thankful for Python 3.x rework for exceptions?
695 except (OSError, IOError, select.error) as e:
696 # select.error wasn't a subclass of OSError in the past.
697 errcode = None
698 if hasattr(e, "errno"):
699 errcode = e.errno
700 elif hasattr(e, "args"):
701 errcode = e.args[0]
702
703 # Also test for the Windows equivalent of EINTR.
704 is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and
705 errcode == errno.WSAEINTR))
706
707 if is_interrupt:
708 if expires is not None:
709 current_time = monotonic()
710 if current_time > expires:
711 raise OSError(errno=errno.ETIMEDOUT)
712 if recalc_timeout:
713 if "timeout" in kwargs:
714 kwargs["timeout"] = expires - current_time
715 continue
716 raise
717 return result
718
719
720 # Choose the best implementation, roughly:
721 # kqueue == devpoll == epoll > poll > select
722 # select() also can't accept a FD > FD_SETSIZE (usually around 1024)
723 def DefaultSelector():
724 """ This function serves as a first call for DefaultSelector to
725 detect if the select module is being monkey-patched incorrectly
726 by eventlet, greenlet, and preserve proper behavior. """
727 global _DEFAULT_SELECTOR
728 if _DEFAULT_SELECTOR is None:
729 if pycompat.isjython:
730 _DEFAULT_SELECTOR = JythonSelectSelector
731 elif _can_allocate('kqueue'):
732 _DEFAULT_SELECTOR = KqueueSelector
733 elif _can_allocate('devpoll'):
734 _DEFAULT_SELECTOR = DevpollSelector
735 elif _can_allocate('epoll'):
736 _DEFAULT_SELECTOR = EpollSelector
737 elif _can_allocate('poll'):
738 _DEFAULT_SELECTOR = PollSelector
739 elif hasattr(select, 'select'):
740 _DEFAULT_SELECTOR = SelectSelector
741 else: # Platform-specific: AppEngine
742 raise RuntimeError('Platform does not have a selector.')
743 return _DEFAULT_SELECTOR()