blob: ecd8632d7048acb86ca25b29cfe39552e0796ff1 [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
Raymond Hettinger5b798ab2015-08-17 22:04:45 -070047SelectorKey.__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"""
52SelectorKey.fileobj.__doc__ = 'File object registered.'
53SelectorKey.fd.__doc__ = 'Underlying file descriptor.'
54SelectorKey.events.__doc__ = 'Events that must be waited for on this file object.'
55SelectorKey.data.__doc__ = ('''Optional opaque data associated to this file object.
56For example, this could be used to store a per-client session ID.''')
Charles-François Natali243d8d82013-09-04 19:02:49 +020057
Charles-François Natali4574b492013-10-30 20:31:04 +010058class _SelectorMapping(Mapping):
59 """Mapping of file objects to selector keys."""
60
61 def __init__(self, selector):
62 self._selector = selector
63
64 def __len__(self):
65 return len(self._selector._fd_to_key)
66
67 def __getitem__(self, fileobj):
68 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -080069 fd = self._selector._fileobj_lookup(fileobj)
70 return self._selector._fd_to_key[fd]
Charles-François Natali4574b492013-10-30 20:31:04 +010071 except KeyError:
72 raise KeyError("{!r} is not registered".format(fileobj)) from None
73
74 def __iter__(self):
75 return iter(self._selector._fd_to_key)
76
77
Charles-François Natali243d8d82013-09-04 19:02:49 +020078class BaseSelector(metaclass=ABCMeta):
Charles-François Natalib3330a0a2013-12-01 11:04:17 +010079 """Selector abstract base class.
Charles-François Natali243d8d82013-09-04 19:02:49 +020080
81 A selector supports registering file objects to be monitored for specific
82 I/O events.
83
84 A file object is a file descriptor or any object with a `fileno()` method.
85 An arbitrary object can be attached to the file object, which can be used
86 for example to store context information, a callback, etc.
87
88 A selector can use various implementations (select(), poll(), epoll()...)
89 depending on the platform. The default `Selector` class uses the most
Yury Selivanovb0b0e622014-02-18 22:27:48 -050090 efficient implementation on the current platform.
Charles-François Natali243d8d82013-09-04 19:02:49 +020091 """
92
Charles-François Natalib3330a0a2013-12-01 11:04:17 +010093 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +020094 def register(self, fileobj, events, data=None):
95 """Register a file object.
96
97 Parameters:
98 fileobj -- file object or file descriptor
99 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
100 data -- attached data
101
102 Returns:
103 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800104
105 Raises:
106 ValueError if events is invalid
107 KeyError if fileobj is already registered
108 OSError if fileobj is closed or otherwise is unacceptable to
109 the underlying system call (if a system call is made)
110
111 Note:
112 OSError may or may not be raised
Charles-François Natali243d8d82013-09-04 19:02:49 +0200113 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100114 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200115
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100116 @abstractmethod
Charles-François Natali243d8d82013-09-04 19:02:49 +0200117 def unregister(self, fileobj):
118 """Unregister a file object.
119
120 Parameters:
121 fileobj -- file object or file descriptor
122
123 Returns:
124 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800125
126 Raises:
127 KeyError if fileobj is not registered
128
129 Note:
130 If fileobj is registered but has since been closed this does
131 *not* raise OSError (even if the wrapped syscall does)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200132 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100133 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200134
135 def modify(self, fileobj, events, data=None):
136 """Change a registered file object monitored events or attached data.
137
138 Parameters:
139 fileobj -- file object or file descriptor
140 events -- events to monitor (bitwise mask of EVENT_READ|EVENT_WRITE)
141 data -- attached data
142
143 Returns:
144 SelectorKey instance
Guido van Rossum9710ff02013-12-07 15:57:01 -0800145
146 Raises:
147 Anything that unregister() or register() raises
Charles-François Natali243d8d82013-09-04 19:02:49 +0200148 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100149 self.unregister(fileobj)
150 return self.register(fileobj, events, data)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200151
152 @abstractmethod
153 def select(self, timeout=None):
154 """Perform the actual selection, until some monitored file objects are
155 ready or a timeout expires.
156
157 Parameters:
158 timeout -- if timeout > 0, this specifies the maximum wait time, in
159 seconds
160 if timeout <= 0, the select() call won't block, and will
161 report the currently ready file objects
162 if timeout is None, select() will block until a monitored
163 file object becomes ready
164
165 Returns:
166 list of (key, events) for ready file objects
167 `events` is a bitwise mask of EVENT_READ|EVENT_WRITE
168 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100169 raise NotImplementedError
Charles-François Natali243d8d82013-09-04 19:02:49 +0200170
171 def close(self):
172 """Close the selector.
173
174 This must be called to make sure that any underlying resource is freed.
175 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100176 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200177
178 def get_key(self, fileobj):
179 """Return the key associated to a registered file object.
180
181 Returns:
182 SelectorKey for this file object
183 """
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100184 mapping = self.get_map()
Victor Stinner458fc6f2015-01-13 10:00:55 +0100185 if mapping is None:
186 raise RuntimeError('Selector is closed')
Charles-François Natali243d8d82013-09-04 19:02:49 +0200187 try:
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100188 return mapping[fileobj]
Charles-François Natali243d8d82013-09-04 19:02:49 +0200189 except KeyError:
190 raise KeyError("{!r} is not registered".format(fileobj)) from None
191
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100192 @abstractmethod
Charles-François Natali4574b492013-10-30 20:31:04 +0100193 def get_map(self):
194 """Return a mapping of file objects to selector keys."""
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100195 raise NotImplementedError
Charles-François Natali4574b492013-10-30 20:31:04 +0100196
Charles-François Natali243d8d82013-09-04 19:02:49 +0200197 def __enter__(self):
198 return self
199
200 def __exit__(self, *args):
201 self.close()
202
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100203
204class _BaseSelectorImpl(BaseSelector):
205 """Base selector implementation."""
206
207 def __init__(self):
208 # this maps file descriptors to keys
209 self._fd_to_key = {}
210 # read-only mapping returned by get_map()
211 self._map = _SelectorMapping(self)
212
Guido van Rossum9710ff02013-12-07 15:57:01 -0800213 def _fileobj_lookup(self, fileobj):
214 """Return a file descriptor from a file object.
215
216 This wraps _fileobj_to_fd() to do an exhaustive search in case
217 the object is invalid but we still have it in our map. This
218 is used by unregister() so we can unregister an object that
219 was previously registered even if it is closed. It is also
220 used by _SelectorMapping.
221 """
222 try:
223 return _fileobj_to_fd(fileobj)
224 except ValueError:
225 # Do an exhaustive search.
226 for key in self._fd_to_key.values():
227 if key.fileobj is fileobj:
228 return key.fd
229 # Raise ValueError after all.
230 raise
231
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100232 def register(self, fileobj, events, data=None):
233 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)):
234 raise ValueError("Invalid events: {!r}".format(events))
235
Guido van Rossum9710ff02013-12-07 15:57:01 -0800236 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data)
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100237
238 if key.fd in self._fd_to_key:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800239 raise KeyError("{!r} (FD {}) is already registered"
240 .format(fileobj, key.fd))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100241
242 self._fd_to_key[key.fd] = key
243 return key
244
245 def unregister(self, fileobj):
246 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800247 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj))
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100248 except KeyError:
249 raise KeyError("{!r} is not registered".format(fileobj)) from None
250 return key
251
252 def modify(self, fileobj, events, data=None):
253 # TODO: Subclasses can probably optimize this even further.
254 try:
Guido van Rossum9710ff02013-12-07 15:57:01 -0800255 key = self._fd_to_key[self._fileobj_lookup(fileobj)]
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100256 except KeyError:
257 raise KeyError("{!r} is not registered".format(fileobj)) from None
258 if events != key.events:
259 self.unregister(fileobj)
260 key = self.register(fileobj, events, data)
261 elif data != key.data:
262 # Use a shortcut to update the data.
263 key = key._replace(data=data)
264 self._fd_to_key[key.fd] = key
265 return key
266
267 def close(self):
268 self._fd_to_key.clear()
Victor Stinner38dc2502015-01-13 09:58:33 +0100269 self._map = None
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100270
271 def get_map(self):
272 return self._map
273
Charles-François Natali243d8d82013-09-04 19:02:49 +0200274 def _key_from_fd(self, fd):
275 """Return the key associated to a given file descriptor.
276
277 Parameters:
278 fd -- file descriptor
279
280 Returns:
281 corresponding key, or None if not found
282 """
283 try:
284 return self._fd_to_key[fd]
285 except KeyError:
286 return None
287
288
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100289class SelectSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200290 """Select-based selector."""
291
292 def __init__(self):
293 super().__init__()
294 self._readers = set()
295 self._writers = set()
296
297 def register(self, fileobj, events, data=None):
298 key = super().register(fileobj, events, data)
299 if events & EVENT_READ:
300 self._readers.add(key.fd)
301 if events & EVENT_WRITE:
302 self._writers.add(key.fd)
303 return key
304
305 def unregister(self, fileobj):
306 key = super().unregister(fileobj)
307 self._readers.discard(key.fd)
308 self._writers.discard(key.fd)
309 return key
310
311 if sys.platform == 'win32':
312 def _select(self, r, w, _, timeout=None):
313 r, w, x = select.select(r, w, w, timeout)
314 return r, w + x, []
315 else:
316 _select = select.select
317
318 def select(self, timeout=None):
319 timeout = None if timeout is None else max(timeout, 0)
320 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400321 try:
322 r, w, _ = self._select(self._readers, self._writers, [], timeout)
323 except InterruptedError:
324 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200325 r = set(r)
326 w = set(w)
327 for fd in r | w:
328 events = 0
329 if fd in r:
330 events |= EVENT_READ
331 if fd in w:
332 events |= EVENT_WRITE
333
334 key = self._key_from_fd(fd)
335 if key:
336 ready.append((key, events & key.events))
337 return ready
338
339
340if hasattr(select, 'poll'):
341
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100342 class PollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200343 """Poll-based selector."""
344
345 def __init__(self):
346 super().__init__()
347 self._poll = select.poll()
348
349 def register(self, fileobj, events, data=None):
350 key = super().register(fileobj, events, data)
351 poll_events = 0
352 if events & EVENT_READ:
353 poll_events |= select.POLLIN
354 if events & EVENT_WRITE:
355 poll_events |= select.POLLOUT
356 self._poll.register(key.fd, poll_events)
357 return key
358
359 def unregister(self, fileobj):
360 key = super().unregister(fileobj)
361 self._poll.unregister(key.fd)
362 return key
363
364 def select(self, timeout=None):
Victor Stinner11da8e22014-01-21 01:48:28 +0100365 if timeout is None:
366 timeout = None
Victor Stinner7067b5d2014-01-21 17:49:41 +0100367 elif timeout <= 0:
Victor Stinner11da8e22014-01-21 01:48:28 +0100368 timeout = 0
369 else:
Victor Stinnerdcd97402014-01-31 12:12:53 +0100370 # poll() has a resolution of 1 millisecond, round away from
371 # zero to wait *at least* timeout seconds.
Victor Stinner665758f2014-01-31 16:24:21 +0100372 timeout = math.ceil(timeout * 1e3)
Charles-François Natali243d8d82013-09-04 19:02:49 +0200373 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400374 try:
375 fd_event_list = self._poll.poll(timeout)
376 except InterruptedError:
377 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200378 for fd, event in fd_event_list:
379 events = 0
380 if event & ~select.POLLIN:
381 events |= EVENT_WRITE
382 if event & ~select.POLLOUT:
383 events |= EVENT_READ
384
385 key = self._key_from_fd(fd)
386 if key:
387 ready.append((key, events & key.events))
388 return ready
389
390
391if hasattr(select, 'epoll'):
392
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100393 class EpollSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200394 """Epoll-based selector."""
395
396 def __init__(self):
397 super().__init__()
398 self._epoll = select.epoll()
399
400 def fileno(self):
401 return self._epoll.fileno()
402
403 def register(self, fileobj, events, data=None):
404 key = super().register(fileobj, events, data)
405 epoll_events = 0
406 if events & EVENT_READ:
407 epoll_events |= select.EPOLLIN
408 if events & EVENT_WRITE:
409 epoll_events |= select.EPOLLOUT
410 self._epoll.register(key.fd, epoll_events)
411 return key
412
413 def unregister(self, fileobj):
414 key = super().unregister(fileobj)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800415 try:
416 self._epoll.unregister(key.fd)
417 except OSError:
418 # This can happen if the FD was closed since it
419 # was registered.
420 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200421 return key
422
423 def select(self, timeout=None):
Victor Stinner567b26e2014-01-21 21:00:47 +0100424 if timeout is None:
425 timeout = -1
426 elif timeout <= 0:
427 timeout = 0
Victor Stinnerdcd97402014-01-31 12:12:53 +0100428 else:
429 # epoll_wait() has a resolution of 1 millisecond, round away
430 # from zero to wait *at least* timeout seconds.
431 timeout = math.ceil(timeout * 1e3) * 1e-3
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500432
Yury Selivanovdfc44e02014-12-08 12:30:10 -0500433 # epoll_wait() expects `maxevents` to be greater than zero;
Yury Selivanovd60ef4a2014-12-08 12:21:58 -0500434 # we want to make sure that `select()` can be called when no
435 # FD is registered.
436 max_ev = max(len(self._fd_to_key), 1)
437
Charles-François Natali243d8d82013-09-04 19:02:49 +0200438 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400439 try:
440 fd_event_list = self._epoll.poll(timeout, max_ev)
441 except InterruptedError:
442 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200443 for fd, event in fd_event_list:
444 events = 0
445 if event & ~select.EPOLLIN:
446 events |= EVENT_WRITE
447 if event & ~select.EPOLLOUT:
448 events |= EVENT_READ
449
450 key = self._key_from_fd(fd)
451 if key:
452 ready.append((key, events & key.events))
453 return ready
454
455 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400456 self._epoll.close()
457 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200458
459
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100460if hasattr(select, 'devpoll'):
461
462 class DevpollSelector(_BaseSelectorImpl):
463 """Solaris /dev/poll selector."""
464
465 def __init__(self):
466 super().__init__()
467 self._devpoll = select.devpoll()
468
469 def fileno(self):
470 return self._devpoll.fileno()
471
472 def register(self, fileobj, events, data=None):
473 key = super().register(fileobj, events, data)
474 poll_events = 0
475 if events & EVENT_READ:
476 poll_events |= select.POLLIN
477 if events & EVENT_WRITE:
478 poll_events |= select.POLLOUT
479 self._devpoll.register(key.fd, poll_events)
480 return key
481
482 def unregister(self, fileobj):
483 key = super().unregister(fileobj)
484 self._devpoll.unregister(key.fd)
485 return key
486
487 def select(self, timeout=None):
488 if timeout is None:
489 timeout = None
490 elif timeout <= 0:
491 timeout = 0
492 else:
493 # devpoll() has a resolution of 1 millisecond, round away from
494 # zero to wait *at least* timeout seconds.
495 timeout = math.ceil(timeout * 1e3)
496 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400497 try:
498 fd_event_list = self._devpoll.poll(timeout)
499 except InterruptedError:
500 return ready
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100501 for fd, event in fd_event_list:
502 events = 0
503 if event & ~select.POLLIN:
504 events |= EVENT_WRITE
505 if event & ~select.POLLOUT:
506 events |= EVENT_READ
507
508 key = self._key_from_fd(fd)
509 if key:
510 ready.append((key, events & key.events))
511 return ready
512
513 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400514 self._devpoll.close()
515 super().close()
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100516
517
Charles-François Natali243d8d82013-09-04 19:02:49 +0200518if hasattr(select, 'kqueue'):
519
Charles-François Natalib3330a0a2013-12-01 11:04:17 +0100520 class KqueueSelector(_BaseSelectorImpl):
Charles-François Natali243d8d82013-09-04 19:02:49 +0200521 """Kqueue-based selector."""
522
523 def __init__(self):
524 super().__init__()
525 self._kqueue = select.kqueue()
526
527 def fileno(self):
528 return self._kqueue.fileno()
529
530 def register(self, fileobj, events, data=None):
531 key = super().register(fileobj, events, data)
532 if events & EVENT_READ:
533 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
534 select.KQ_EV_ADD)
535 self._kqueue.control([kev], 0, 0)
536 if events & EVENT_WRITE:
537 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
538 select.KQ_EV_ADD)
539 self._kqueue.control([kev], 0, 0)
540 return key
541
542 def unregister(self, fileobj):
543 key = super().unregister(fileobj)
544 if key.events & EVENT_READ:
545 kev = select.kevent(key.fd, select.KQ_FILTER_READ,
546 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800547 try:
548 self._kqueue.control([kev], 0, 0)
549 except OSError:
550 # This can happen if the FD was closed since it
551 # was registered.
552 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200553 if key.events & EVENT_WRITE:
554 kev = select.kevent(key.fd, select.KQ_FILTER_WRITE,
555 select.KQ_EV_DELETE)
Guido van Rossum9710ff02013-12-07 15:57:01 -0800556 try:
557 self._kqueue.control([kev], 0, 0)
558 except OSError:
559 # See comment above.
560 pass
Charles-François Natali243d8d82013-09-04 19:02:49 +0200561 return key
562
563 def select(self, timeout=None):
564 timeout = None if timeout is None else max(timeout, 0)
565 max_ev = len(self._fd_to_key)
566 ready = []
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400567 try:
568 kev_list = self._kqueue.control(None, max_ev, timeout)
569 except InterruptedError:
570 return ready
Charles-François Natali243d8d82013-09-04 19:02:49 +0200571 for kev in kev_list:
572 fd = kev.ident
573 flag = kev.filter
574 events = 0
575 if flag == select.KQ_FILTER_READ:
576 events |= EVENT_READ
577 if flag == select.KQ_FILTER_WRITE:
578 events |= EVENT_WRITE
579
580 key = self._key_from_fd(fd)
581 if key:
582 ready.append((key, events & key.events))
583 return ready
584
585 def close(self):
Yury Selivanov90ecfe62015-05-11 13:48:16 -0400586 self._kqueue.close()
587 super().close()
Charles-François Natali243d8d82013-09-04 19:02:49 +0200588
589
Victor Stinner53a6d742015-01-09 00:13:39 +0100590# Choose the best implementation, roughly:
591# epoll|kqueue|devpoll > poll > select.
Charles-François Natali243d8d82013-09-04 19:02:49 +0200592# select() also can't accept a FD > FD_SETSIZE (usually around 1024)
593if 'KqueueSelector' in globals():
594 DefaultSelector = KqueueSelector
595elif 'EpollSelector' in globals():
596 DefaultSelector = EpollSelector
Giampaolo Rodola'f97e8292014-03-20 21:43:41 +0100597elif 'DevpollSelector' in globals():
598 DefaultSelector = DevpollSelector
Charles-François Natali243d8d82013-09-04 19:02:49 +0200599elif 'PollSelector' in globals():
600 DefaultSelector = PollSelector
601else:
602 DefaultSelector = SelectSelector