blob: d8769e35411523f0fd0b9fadd31dca0d7d77cbf2 [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'])
Charles-François Natali243d8d82013-09-04 19:02:49 +020046
Yury Selivanov0c6a3442016-03-02 10:37:59 -050047SelectorKey.__doc__ = """SelectorKey(fileobj, fd, events, data)
48
49 Object used to associate a file object to its backing
50 file descriptor, selected event mask, and attached data.
51"""
52if sys.version_info >= (3, 5):
53 SelectorKey.fileobj.__doc__ = 'File object registered.'
54 SelectorKey.fd.__doc__ = 'Underlying file descriptor.'
55 SelectorKey.events.__doc__ = 'Events that must be waited for on this file object.'
56 SelectorKey.data.__doc__ = ('''Optional opaque data associated to this file object.
57 For example, this could be used to store a per-client session ID.''')
Charles-François Natali243d8d82013-09-04 19:02:49 +020058
Charles-François Natali4574b492013-10-30 20:31:04 +010059class _SelectorMapping(Mapping):
60 """Mapping of file objects to selector keys."""
61
62 def __init__(self, selector):
63 self._selector = selector
64
65 def __len__(self):
66 return len(self._selector._fd_to_key)
67
68 def __getitem__(self, fileobj):
69 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -080070 fd = self._selector._fileobj_lookup(fileobj)
71 return self._selector._fd_to_key[fd]
Charles-François Natali4574b492013-10-30 20:31:04 +010072 except KeyError:
73 raise KeyError("{!r} is not registered".format(fileobj)) from None
74
75 def __iter__(self):
76 return iter(self._selector._fd_to_key)
77
78
Charles-François Natali243d8d82013-09-04 19:02:49 +020079class BaseSelector(metaclass=ABCMeta):
Charles-François Natalib3330a0a2013-12-01 11:04:17 +010080 """Selector abstract base class.
Charles-François Natali243d8d82013-09-04 19:02:49 +020081
82 A selector supports registering file objects to be monitored for specific
83 I/O events.
84
85 A file object is a file descriptor or any object with a `fileno()` method.
86 An arbitrary object can be attached to the file object, which can be used
87 for example to store context information, a callback, etc.
88
89 A selector can use various implementations (select(), poll(), epoll()...)
90 depending on the platform. The default `Selector` class uses the most
Yury Selivanovb0b0e622014-02-18 22:27:48 -050091 efficient implementation on the current platform.
Charles-François Natali243d8d82013-09-04 19:02:49 +020092 """
93
Charles-François Natalib3330a0a2013-12-01 11:04:17 +010094 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +020095 def register(self, fileobj, events, data=None):
96 """Register a file object.
97
98 Parameters:
99 fileobj -- file object or file descriptor
100 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
101 data -- attached data
102
103 Returns:
104 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800105
106 Raises:
107 ValueError if events is invalid
108 KeyError if fileobj is already registered
109 OSError if fileobj is closed or otherwise is unacceptable to
110 the underlying system call (if a system call is made)
111
112 Note:
113 OSError may or may not be raised
Charles-François Natali243d8d82013-09-04 19:02:49 +0200114 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100115 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200116
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100117 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +0200118 def unregister(self, fileobj):
119 """Unregister a file object.
120
121 Parameters:
122 fileobj -- file object or file descriptor
123
124 Returns:
125 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800126
127 Raises:
128 KeyError if fileobj is not registered
129
130 Note:
131 If fileobj is registered but has since been closed this does
132 *not* raise OSError (even if the wrapped syscall does)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200133 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100134 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200135
136 def modify(self, fileobj, events, data=None):
137 """Change a registered file object monitored events or attached data.
138
139 Parameters:
140 fileobj -- file object or file descriptor
141 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
142 data -- attached data
143
144 Returns:
145 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800146
147 Raises:
148 Anything that unregister() or register() raises
Charles-François Natali243d8d82013-09-04 19:02:49 +0200149 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100150 self.unregister(fileobj)
151 return self.register(fileobj, events, data)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200152
153 @abstractmethod
154 def select(self, timeout=None):
155 """Perform the actual selection, until some monitored file objects are
156 ready or a timeout expires.
157
158 Parameters:
159 timeout -- if timeout > 0, this specifies the maximum wait time, in
160 seconds
161 if timeout <= 0, the select() call won't block, and will
162 report the currently ready file objects
163 if timeout is None, select() will block until a monitored
164 file object becomes ready
165
166 Returns:
167 list of (key, events) for ready file objects
168 `events` is a bitwise mask of EVENT_READ|EVENT_WRITE
169 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100170 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200171
172 def close(self):
173 """Close the selector.
174
175 This must be called to make sure that any underlying resource is freed.
176 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100177 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200178
179 def get_key(self, fileobj):
180 """Return the key associated to a registered file object.
181
182 Returns:
183 SelectorKey for this file object
184 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100185 mapping = self.get_map()
Victor Stinner458fc6f2015-01-13 10:00:55 +0100186 if mapping is None:
187 raise RuntimeError('Selector is closed')
Charles-François Natali243d8d82013-09-04 19:02:49 +0200188 try:
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100189 return mapping[fileobj]
Charles-François Natali243d8d82013-09-04 19:02:49 +0200190 except KeyError:
191 raise KeyError("{!r} is not registered".format(fileobj)) from None
192
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100193 @abstractmethod
Charles-François Natali4574b492013-10-30 20:31:04 +0100194 def get_map(self):
195 """Return a mapping of file objects to selector keys."""
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100196 raise NotImplementedError
Charles-François Natali4574b492013-10-30 20:31:04 +0100197
Charles-François Natali243d8d82013-09-04 19:02:49 +0200198 def __enter__(self):
199 return self
200
201 def __exit__(self, *args):
202 self.close()
203
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100204
205class _BaseSelectorImpl(BaseSelector):
206 """Base selector implementation."""
207
208 def __init__(self):
209 # this maps file descriptors to keys
210 self._fd_to_key = {}
211 # read-only mapping returned by get_map()
212 self._map = _SelectorMapping(self)
213
Guido van Rossum9710ff02013-12-07 15:57:01 -0800214 def _fileobj_lookup(self, fileobj):
215 """Return a file descriptor from a file object.
216
217 This wraps _fileobj_to_fd() to do an exhaustive search in case
218 the object is invalid but we still have it in our map. This
219 is used by unregister() so we can unregister an object that
220 was previously registered even if it is closed. It is also
221 used by _SelectorMapping.
222 """
223 try:
224 return _fileobj_to_fd(fileobj)
225 except ValueError:
226 # Do an exhaustive search.
227 for key in self._fd_to_key.values():
228 if key.fileobj is fileobj:
229 return key.fd
230 # Raise ValueError after all.
231 raise
232
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100233 def register(self, fileobj, events, data=None):
234 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
235 raise ValueError("Invalid events: {!r}".format(events))
236
Guido van Rossum9710ff02013-12-07 15:57:01 -0800237 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100238
239 if key.fd in self._fd_to_key:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800240 raise KeyError("{!r} (FD {}) is already registered"
241 .format(fileobj, key.fd))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100242
243 self._fd_to_key[key.fd] = key
244 return key
245
246 def unregister(self, fileobj):
247 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800248 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100249 except KeyError:
250 raise KeyError("{!r} is not registered".format(fileobj)) from None
251 return key
252
253 def modify(self, fileobj, events, data=None):
254 # TODO: Subclasses can probably optimize this even further.
255 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800256 key = self._fd_to_key[self._fileobj_lookup(fileobj)]
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100257 except KeyError:
258 raise KeyError("{!r} is not registered".format(fileobj)) from None
259 if events != key.events:
260 self.unregister(fileobj)
261 key = self.register(fileobj, events, data)
262 elif data != key.data:
263 # Use a shortcut to update the data.
264 key = key._replace(data=data)
265 self._fd_to_key[key.fd] = key
266 return key
267
268 def close(self):
269 self._fd_to_key.clear()
Victor Stinner38dc2502015-01-13 09:58:33 +0100270 self._map = None
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100271
272 def get_map(self):
273 return self._map
274
Charles-François Natali243d8d82013-09-04 19:02:49 +0200275 def _key_from_fd(self, fd):
276 """Return the key associated to a given file descriptor.
277
278 Parameters:
279 fd -- file descriptor
280
281 Returns:
282 corresponding key, or None if not found
283 """
284 try:
285 return self._fd_to_key[fd]
286 except KeyError:
287 return None
288
289
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100290class SelectSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200291 """Select-based selector."""
292
293 def __init__(self):
294 super().__init__()
295 self._readers = set()
296 self._writers = set()
297
298 def register(self, fileobj, events, data=None):
299 key = super().register(fileobj, events, data)
300 if events & EVENT_READ:
301 self._readers.add(key.fd)
302 if events & EVENT_WRITE:
303 self._writers.add(key.fd)
304 return key
305
306 def unregister(self, fileobj):
307 key = super().unregister(fileobj)
308 self._readers.discard(key.fd)
309 self._writers.discard(key.fd)
310 return key
311
312 if sys.platform == 'win32':
313 def _select(self, r, w, _, timeout=None):
314 r, w, x = select.select(r, w, w, timeout)
315 return r, w + x, []
316 else:
317 _select = select.select
318
319 def select(self, timeout=None):
320 timeout = None if timeout is None else max(timeout, 0)
321 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400322 try:
323 r, w, _ = self._select(self._readers, self._writers, [], timeout)
324 except InterruptedError:
325 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200326 r = set(r)
327 w = set(w)
328 for fd in r | w:
329 events = 0
330 if fd in r:
331 events |= EVENT_READ
332 if fd in w:
333 events |= EVENT_WRITE
334
335 key = self._key_from_fd(fd)
336 if key:
337 ready.append((key, events & key.events))
338 return ready
339
340
341if hasattr(select, 'poll'):
342
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100343 class PollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200344 """Poll-based selector."""
345
346 def __init__(self):
347 super().__init__()
348 self._poll = select.poll()
349
350 def register(self, fileobj, events, data=None):
351 key = super().register(fileobj, events, data)
352 poll_events = 0
353 if events & EVENT_READ:
354 poll_events |= select.POLLIN
355 if events & EVENT_WRITE:
356 poll_events |= select.POLLOUT
357 self._poll.register(key.fd, poll_events)
358 return key
359
360 def unregister(self, fileobj):
361 key = super().unregister(fileobj)
362 self._poll.unregister(key.fd)
363 return key
364
365 def select(self, timeout=None):
Victor Stinner11da8e22014-01-21 01:48:28 +0100366 if timeout is None:
367 timeout = None
Victor Stinner7067b5d2014-01-21 17:49:41 +0100368 elif timeout <= 0:
Victor Stinner11da8e22014-01-21 01:48:28 +0100369 timeout = 0
370 else:
Victor Stinnerdcd97402014-01-31 12:12:53 +0100371 # poll() has a resolution of 1 millisecond, round away from
372 # zero to wait *at least* timeout seconds.
Victor Stinner665758f2014-01-31 16:24:21 +0100373 timeout = math.ceil(timeout * 1e3)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200374 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400375 try:
376 fd_event_list = self._poll.poll(timeout)
377 except InterruptedError:
378 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200379 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
401 def fileno(self):
402 return self._epoll.fileno()
403
404 def register(self, fileobj, events, data=None):
405 key = super().register(fileobj, events, data)
406 epoll_events = 0
407 if events & EVENT_READ:
408 epoll_events |= select.EPOLLIN
409 if events & EVENT_WRITE:
410 epoll_events |= select.EPOLLOUT
411 self._epoll.register(key.fd, epoll_events)
412 return key
413
414 def unregister(self, fileobj):
415 key = super().unregister(fileobj)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800416 try:
417 self._epoll.unregister(key.fd)
418 except OSError:
419 # This can happen if the FD was closed since it
420 # was registered.
421 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200422 return key
423
424 def select(self, timeout=None):
Victor Stinner567b26e2014-01-21 21:00:47 +0100425 if timeout is None:
426 timeout = -1
427 elif timeout <= 0:
428 timeout = 0
Victor Stinnerdcd97402014-01-31 12:12:53 +0100429 else:
430 # epoll_wait() has a resolution of 1 millisecond, round away
431 # from zero to wait *at least* timeout seconds.
432 timeout = math.ceil(timeout * 1e3) * 1e-3
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500433
Yury Selivanovdfc44e02014-12-08 12:30:10 -0500434 # epoll_wait() expects `maxevents` to be greater than zero;
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500435 # we want to make sure that `select()` can be called when no
436 # FD is registered.
437 max_ev = max(len(self._fd_to_key), 1)
438
Charles-François Natali243d8d82013-09-04 19:02:49 +0200439 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400440 try:
441 fd_event_list = self._epoll.poll(timeout, max_ev)
442 except InterruptedError:
443 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200444 for fd, event in fd_event_list:
445 events = 0
446 if event & ~select.EPOLLIN:
447 events |= EVENT_WRITE
448 if event & ~select.EPOLLOUT:
449 events |= EVENT_READ
450
451 key = self._key_from_fd(fd)
452 if key:
453 ready.append((key, events & key.events))
454 return ready
455
456 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400457 self._epoll.close()
458 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200459
460
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100461if hasattr(select, 'devpoll'):
462
463 class DevpollSelector(_BaseSelectorImpl):
464 """Solaris /dev/poll selector."""
465
466 def __init__(self):
467 super().__init__()
468 self._devpoll = select.devpoll()
469
470 def fileno(self):
471 return self._devpoll.fileno()
472
473 def register(self, fileobj, events, data=None):
474 key = super().register(fileobj, events, data)
475 poll_events = 0
476 if events & EVENT_READ:
477 poll_events |= select.POLLIN
478 if events & EVENT_WRITE:
479 poll_events |= select.POLLOUT
480 self._devpoll.register(key.fd, poll_events)
481 return key
482
483 def unregister(self, fileobj):
484 key = super().unregister(fileobj)
485 self._devpoll.unregister(key.fd)
486 return key
487
488 def select(self, timeout=None):
489 if timeout is None:
490 timeout = None
491 elif timeout <= 0:
492 timeout = 0
493 else:
494 # devpoll() has a resolution of 1 millisecond, round away from
495 # zero to wait *at least* timeout seconds.
496 timeout = math.ceil(timeout * 1e3)
497 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400498 try:
499 fd_event_list = self._devpoll.poll(timeout)
500 except InterruptedError:
501 return ready
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100502 for fd, event in fd_event_list:
503 events = 0
504 if event & ~select.POLLIN:
505 events |= EVENT_WRITE
506 if event & ~select.POLLOUT:
507 events |= EVENT_READ
508
509 key = self._key_from_fd(fd)
510 if key:
511 ready.append((key, events & key.events))
512 return ready
513
514 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400515 self._devpoll.close()
516 super().close()
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100517
518
Charles-François Natali243d8d82013-09-04 19:02:49 +0200519if hasattr(select, 'kqueue'):
520
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100521 class KqueueSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200522 """Kqueue-based selector."""
523
524 def __init__(self):
525 super().__init__()
526 self._kqueue = select.kqueue()
527
528 def fileno(self):
529 return self._kqueue.fileno()
530
531 def register(self, fileobj, events, data=None):
532 key = super().register(fileobj, events, data)
533 if events & EVENT_READ:
534 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
535 select.KQ_EV_ADD)
536 self._kqueue.control([kev], 0, 0)
537 if events & EVENT_WRITE:
538 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
539 select.KQ_EV_ADD)
540 self._kqueue.control([kev], 0, 0)
541 return key
542
543 def unregister(self, fileobj):
544 key = super().unregister(fileobj)
545 if key.events & EVENT_READ:
546 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
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 # This can happen if the FD was closed since it
552 # was registered.
553 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200554 if key.events & EVENT_WRITE:
555 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
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 # See comment above.
561 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200562 return key
563
564 def select(self, timeout=None):
565 timeout = None if timeout is None else max(timeout, 0)
566 max_ev = len(self._fd_to_key)
567 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400568 try:
569 kev_list = self._kqueue.control(None, max_ev, timeout)
570 except InterruptedError:
571 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200572 for kev in kev_list:
573 fd = kev.ident
574 flag = kev.filter
575 events = 0
576 if flag == select.KQ_FILTER_READ:
577 events |= EVENT_READ
578 if flag == select.KQ_FILTER_WRITE:
579 events |= EVENT_WRITE
580
581 key = self._key_from_fd(fd)
582 if key:
583 ready.append((key, events & key.events))
584 return ready
585
586 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400587 self._kqueue.close()
588 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200589
590
Victor Stinner53a6d742015-01-09 00:13:39 +0100591# Choose the best implementation, roughly:
592# epoll|kqueue|devpoll > poll > select.
Charles-François Natali243d8d82013-09-04 19:02:49 +0200593# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
594if 'KqueueSelector' in globals():
595 DefaultSelector = KqueueSelector
596elif 'EpollSelector' in globals():
597 DefaultSelector = EpollSelector
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100598elif 'DevpollSelector' in globals():
599 DefaultSelector = DevpollSelector
Charles-François Natali243d8d82013-09-04 19:02:49 +0200600elif 'PollSelector' in globals():
601 DefaultSelector = PollSelector
602else:
603 DefaultSelector = SelectSelector