1# This file is from the selectors2.py package. It backports the PSF Licensed 2# selectors module from the Python-3.5 stdlib to older versions of Python. 3# The author, Seth Michael Larson, dual licenses his modifications under the 4# PSF License and MIT License: 5# https://github.com/SethMichaelLarson/selectors2#license 6# 7# Copyright (c) 2016 Seth Michael Larson 8# 9# PSF License (see licenses/PSF-license.txt or https://opensource.org/licenses/Python-2.0) 10# MIT License (see licenses/MIT-license.txt or https://opensource.org/licenses/MIT) 11# 12 13 14# Backport of selectors.py from Python 3.5+ to support Python < 3.4 15# Also has the behavior specified in PEP 475 which is to retry syscalls 16# in the case of an EINTR error. This module is required because selectors34 17# does not follow this behavior and instead returns that no file descriptor 18# events have occurred rather than retry the syscall. The decision to drop 19# support for select.devpoll is made to maintain 100% test coverage. 20 21import errno 22import math 23import select 24import socket 25import sys 26import time 27from collections import namedtuple 28from ansible.module_utils.common._collections_compat import Mapping 29 30try: 31 monotonic = time.monotonic 32except (AttributeError, ImportError): # Python 3.3< 33 monotonic = time.time 34 35__author__ = 'Seth Michael Larson' 36__email__ = 'sethmichaellarson@protonmail.com' 37__version__ = '1.1.1' 38__license__ = 'MIT' 39 40__all__ = [ 41 'EVENT_READ', 42 'EVENT_WRITE', 43 'SelectorError', 44 'SelectorKey', 45 'DefaultSelector' 46] 47 48EVENT_READ = (1 << 0) 49EVENT_WRITE = (1 << 1) 50 51HAS_SELECT = True # Variable that shows whether the platform has a selector. 52_SYSCALL_SENTINEL = object() # Sentinel in case a system call returns None. 53 54 55class SelectorError(Exception): 56 def __init__(self, errcode): 57 super(SelectorError, self).__init__() 58 self.errno = errcode 59 60 def __repr__(self): 61 return "<SelectorError errno={0}>".format(self.errno) 62 63 def __str__(self): 64 return self.__repr__() 65 66 67def _fileobj_to_fd(fileobj): 68 """ Return a file descriptor from a file object. If 69 given an integer will simply return that integer back. """ 70 if isinstance(fileobj, int): 71 fd = fileobj 72 else: 73 try: 74 fd = int(fileobj.fileno()) 75 except (AttributeError, TypeError, ValueError): 76 raise ValueError("Invalid file object: {0!r}".format(fileobj)) 77 if fd < 0: 78 raise ValueError("Invalid file descriptor: {0}".format(fd)) 79 return fd 80 81 82# Python 3.5 uses a more direct route to wrap system calls to increase speed. 83if sys.version_info >= (3, 5): 84 def _syscall_wrapper(func, _, *args, **kwargs): 85 """ This is the short-circuit version of the below logic 86 because in Python 3.5+ all selectors restart system calls. """ 87 try: 88 return func(*args, **kwargs) 89 except (OSError, IOError, select.error) as e: 90 errcode = None 91 if hasattr(e, "errno"): 92 errcode = e.errno 93 elif hasattr(e, "args"): 94 errcode = e.args[0] 95 raise SelectorError(errcode) 96else: 97 def _syscall_wrapper(func, recalc_timeout, *args, **kwargs): 98 """ Wrapper function for syscalls that could fail due to EINTR. 99 All functions should be retried if there is time left in the timeout 100 in accordance with PEP 475. """ 101 timeout = kwargs.get("timeout", None) 102 if timeout is None: 103 expires = None 104 recalc_timeout = False 105 else: 106 timeout = float(timeout) 107 if timeout < 0.0: # Timeout less than 0 treated as no timeout. 108 expires = None 109 else: 110 expires = monotonic() + timeout 111 112 args = list(args) 113 if recalc_timeout and "timeout" not in kwargs: 114 raise ValueError( 115 "Timeout must be in args or kwargs to be recalculated") 116 117 result = _SYSCALL_SENTINEL 118 while result is _SYSCALL_SENTINEL: 119 try: 120 result = func(*args, **kwargs) 121 # OSError is thrown by select.select 122 # IOError is thrown by select.epoll.poll 123 # select.error is thrown by select.poll.poll 124 # Aren't we thankful for Python 3.x rework for exceptions? 125 except (OSError, IOError, select.error) as e: 126 # select.error wasn't a subclass of OSError in the past. 127 errcode = None 128 if hasattr(e, "errno"): 129 errcode = e.errno 130 elif hasattr(e, "args"): 131 errcode = e.args[0] 132 133 # Also test for the Windows equivalent of EINTR. 134 is_interrupt = (errcode == errno.EINTR or (hasattr(errno, "WSAEINTR") and 135 errcode == errno.WSAEINTR)) 136 137 if is_interrupt: 138 if expires is not None: 139 current_time = monotonic() 140 if current_time > expires: 141 raise OSError(errno.ETIMEDOUT) 142 if recalc_timeout: 143 if "timeout" in kwargs: 144 kwargs["timeout"] = expires - current_time 145 continue 146 if errcode: 147 raise SelectorError(errcode) 148 else: 149 raise 150 return result 151 152 153SelectorKey = namedtuple('SelectorKey', ['fileobj', 'fd', 'events', 'data']) 154 155 156class _SelectorMapping(Mapping): 157 """ Mapping of file objects to selector keys """ 158 159 def __init__(self, selector): 160 self._selector = selector 161 162 def __len__(self): 163 return len(self._selector._fd_to_key) 164 165 def __getitem__(self, fileobj): 166 try: 167 fd = self._selector._fileobj_lookup(fileobj) 168 return self._selector._fd_to_key[fd] 169 except KeyError: 170 raise KeyError("{0!r} is not registered.".format(fileobj)) 171 172 def __iter__(self): 173 return iter(self._selector._fd_to_key) 174 175 176class BaseSelector(object): 177 """ Abstract Selector class 178 179 A selector supports registering file objects to be monitored 180 for specific I/O events. 181 182 A file object is a file descriptor or any object with a 183 `fileno()` method. An arbitrary object can be attached to the 184 file object which can be used for example to store context info, 185 a callback, etc. 186 187 A selector can use various implementations (select(), poll(), epoll(), 188 and kqueue()) depending on the platform. The 'DefaultSelector' class uses 189 the most efficient implementation for the current platform. 190 """ 191 def __init__(self): 192 # Maps file descriptors to keys. 193 self._fd_to_key = {} 194 195 # Read-only mapping returned by get_map() 196 self._map = _SelectorMapping(self) 197 198 def _fileobj_lookup(self, fileobj): 199 """ Return a file descriptor from a file object. 200 This wraps _fileobj_to_fd() to do an exhaustive 201 search in case the object is invalid but we still 202 have it in our map. Used by unregister() so we can 203 unregister an object that was previously registered 204 even if it is closed. It is also used by _SelectorMapping 205 """ 206 try: 207 return _fileobj_to_fd(fileobj) 208 except ValueError: 209 210 # Search through all our mapped keys. 211 for key in self._fd_to_key.values(): 212 if key.fileobj is fileobj: 213 return key.fd 214 215 # Raise ValueError after all. 216 raise 217 218 def register(self, fileobj, events, data=None): 219 """ Register a file object for a set of events to monitor. """ 220 if (not events) or (events & ~(EVENT_READ | EVENT_WRITE)): 221 raise ValueError("Invalid events: {0!r}".format(events)) 222 223 key = SelectorKey(fileobj, self._fileobj_lookup(fileobj), events, data) 224 225 if key.fd in self._fd_to_key: 226 raise KeyError("{0!r} (FD {1}) is already registered" 227 .format(fileobj, key.fd)) 228 229 self._fd_to_key[key.fd] = key 230 return key 231 232 def unregister(self, fileobj): 233 """ Unregister a file object from being monitored. """ 234 try: 235 key = self._fd_to_key.pop(self._fileobj_lookup(fileobj)) 236 except KeyError: 237 raise KeyError("{0!r} is not registered".format(fileobj)) 238 239 # Getting the fileno of a closed socket on Windows errors with EBADF. 240 except socket.error as err: 241 if err.errno != errno.EBADF: 242 raise 243 else: 244 for key in self._fd_to_key.values(): 245 if key.fileobj is fileobj: 246 self._fd_to_key.pop(key.fd) 247 break 248 else: 249 raise KeyError("{0!r} is not registered".format(fileobj)) 250 return key 251 252 def modify(self, fileobj, events, data=None): 253 """ Change a registered file object monitored events and data. """ 254 # NOTE: Some subclasses optimize this operation even further. 255 try: 256 key = self._fd_to_key[self._fileobj_lookup(fileobj)] 257 except KeyError: 258 raise KeyError("{0!r} is not registered".format(fileobj)) 259 260 if events != key.events: 261 self.unregister(fileobj) 262 key = self.register(fileobj, events, data) 263 264 elif data != key.data: 265 # Use a shortcut to update the data. 266 key = key._replace(data=data) 267 self._fd_to_key[key.fd] = key 268 269 return key 270 271 def select(self, timeout=None): 272 """ Perform the actual selection until some monitored file objects 273 are ready or the timeout expires. """ 274 raise NotImplementedError() 275 276 def close(self): 277 """ Close the selector. This must be called to ensure that all 278 underlying resources are freed. """ 279 self._fd_to_key.clear() 280 self._map = None 281 282 def get_key(self, fileobj): 283 """ Return the key associated with a registered file object. """ 284 mapping = self.get_map() 285 if mapping is None: 286 raise RuntimeError("Selector is closed") 287 try: 288 return mapping[fileobj] 289 except KeyError: 290 raise KeyError("{0!r} is not registered".format(fileobj)) 291 292 def get_map(self): 293 """ Return a mapping of file objects to selector keys """ 294 return self._map 295 296 def _key_from_fd(self, fd): 297 """ Return the key associated to a given file descriptor 298 Return None if it is not found. """ 299 try: 300 return self._fd_to_key[fd] 301 except KeyError: 302 return None 303 304 def __enter__(self): 305 return self 306 307 def __exit__(self, *args): 308 self.close() 309 310 311# Almost all platforms have select.select() 312if hasattr(select, "select"): 313 class SelectSelector(BaseSelector): 314 """ Select-based selector. """ 315 def __init__(self): 316 super(SelectSelector, self).__init__() 317 self._readers = set() 318 self._writers = set() 319 320 def register(self, fileobj, events, data=None): 321 key = super(SelectSelector, self).register(fileobj, events, data) 322 if events & EVENT_READ: 323 self._readers.add(key.fd) 324 if events & EVENT_WRITE: 325 self._writers.add(key.fd) 326 return key 327 328 def unregister(self, fileobj): 329 key = super(SelectSelector, self).unregister(fileobj) 330 self._readers.discard(key.fd) 331 self._writers.discard(key.fd) 332 return key 333 334 def _select(self, r, w, timeout=None): 335 """ Wrapper for select.select because timeout is a positional arg """ 336 return select.select(r, w, [], timeout) 337 338 def select(self, timeout=None): 339 # Selecting on empty lists on Windows errors out. 340 if not len(self._readers) and not len(self._writers): 341 return [] 342 343 timeout = None if timeout is None else max(timeout, 0.0) 344 ready = [] 345 r, w, _ = _syscall_wrapper(self._select, True, self._readers, 346 self._writers, timeout=timeout) 347 r = set(r) 348 w = set(w) 349 for fd in r | w: 350 events = 0 351 if fd in r: 352 events |= EVENT_READ 353 if fd in w: 354 events |= EVENT_WRITE 355 356 key = self._key_from_fd(fd) 357 if key: 358 ready.append((key, events & key.events)) 359 return ready 360 361 __all__.append('SelectSelector') 362 363 364if hasattr(select, "poll"): 365 class PollSelector(BaseSelector): 366 """ Poll-based selector """ 367 def __init__(self): 368 super(PollSelector, self).__init__() 369 self._poll = select.poll() 370 371 def register(self, fileobj, events, data=None): 372 key = super(PollSelector, self).register(fileobj, events, data) 373 event_mask = 0 374 if events & EVENT_READ: 375 event_mask |= select.POLLIN 376 if events & EVENT_WRITE: 377 event_mask |= select.POLLOUT 378 self._poll.register(key.fd, event_mask) 379 return key 380 381 def unregister(self, fileobj): 382 key = super(PollSelector, self).unregister(fileobj) 383 self._poll.unregister(key.fd) 384 return key 385 386 def _wrap_poll(self, timeout=None): 387 """ Wrapper function for select.poll.poll() so that 388 _syscall_wrapper can work with only seconds. """ 389 if timeout is not None: 390 if timeout <= 0: 391 timeout = 0 392 else: 393 # select.poll.poll() has a resolution of 1 millisecond, 394 # round away from zero to wait *at least* timeout seconds. 395 timeout = math.ceil(timeout * 1e3) 396 397 result = self._poll.poll(timeout) 398 return result 399 400 def select(self, timeout=None): 401 ready = [] 402 fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout) 403 for fd, event_mask in fd_events: 404 events = 0 405 if event_mask & ~select.POLLIN: 406 events |= EVENT_WRITE 407 if event_mask & ~select.POLLOUT: 408 events |= EVENT_READ 409 410 key = self._key_from_fd(fd) 411 if key: 412 ready.append((key, events & key.events)) 413 414 return ready 415 416 __all__.append('PollSelector') 417 418if hasattr(select, "epoll"): 419 class EpollSelector(BaseSelector): 420 """ Epoll-based selector """ 421 def __init__(self): 422 super(EpollSelector, self).__init__() 423 self._epoll = select.epoll() 424 425 def fileno(self): 426 return self._epoll.fileno() 427 428 def register(self, fileobj, events, data=None): 429 key = super(EpollSelector, self).register(fileobj, events, data) 430 events_mask = 0 431 if events & EVENT_READ: 432 events_mask |= select.EPOLLIN 433 if events & EVENT_WRITE: 434 events_mask |= select.EPOLLOUT 435 _syscall_wrapper(self._epoll.register, False, key.fd, events_mask) 436 return key 437 438 def unregister(self, fileobj): 439 key = super(EpollSelector, self).unregister(fileobj) 440 try: 441 _syscall_wrapper(self._epoll.unregister, False, key.fd) 442 except SelectorError: 443 # This can occur when the fd was closed since registry. 444 pass 445 return key 446 447 def select(self, timeout=None): 448 if timeout is not None: 449 if timeout <= 0: 450 timeout = 0.0 451 else: 452 # select.epoll.poll() has a resolution of 1 millisecond 453 # but luckily takes seconds so we don't need a wrapper 454 # like PollSelector. Just for better rounding. 455 timeout = math.ceil(timeout * 1e3) * 1e-3 456 timeout = float(timeout) 457 else: 458 timeout = -1.0 # epoll.poll() must have a float. 459 460 # We always want at least 1 to ensure that select can be called 461 # with no file descriptors registered. Otherwise will fail. 462 max_events = max(len(self._fd_to_key), 1) 463 464 ready = [] 465 fd_events = _syscall_wrapper(self._epoll.poll, True, 466 timeout=timeout, 467 maxevents=max_events) 468 for fd, event_mask in fd_events: 469 events = 0 470 if event_mask & ~select.EPOLLIN: 471 events |= EVENT_WRITE 472 if event_mask & ~select.EPOLLOUT: 473 events |= EVENT_READ 474 475 key = self._key_from_fd(fd) 476 if key: 477 ready.append((key, events & key.events)) 478 return ready 479 480 def close(self): 481 self._epoll.close() 482 super(EpollSelector, self).close() 483 484 __all__.append('EpollSelector') 485 486 487if hasattr(select, "devpoll"): 488 class DevpollSelector(BaseSelector): 489 """Solaris /dev/poll selector.""" 490 491 def __init__(self): 492 super(DevpollSelector, self).__init__() 493 self._devpoll = select.devpoll() 494 495 def fileno(self): 496 return self._devpoll.fileno() 497 498 def register(self, fileobj, events, data=None): 499 key = super(DevpollSelector, self).register(fileobj, events, data) 500 poll_events = 0 501 if events & EVENT_READ: 502 poll_events |= select.POLLIN 503 if events & EVENT_WRITE: 504 poll_events |= select.POLLOUT 505 self._devpoll.register(key.fd, poll_events) 506 return key 507 508 def unregister(self, fileobj): 509 key = super(DevpollSelector, self).unregister(fileobj) 510 self._devpoll.unregister(key.fd) 511 return key 512 513 def _wrap_poll(self, timeout=None): 514 """ Wrapper function for select.poll.poll() so that 515 _syscall_wrapper can work with only seconds. """ 516 if timeout is not None: 517 if timeout <= 0: 518 timeout = 0 519 else: 520 # select.devpoll.poll() has a resolution of 1 millisecond, 521 # round away from zero to wait *at least* timeout seconds. 522 timeout = math.ceil(timeout * 1e3) 523 524 result = self._devpoll.poll(timeout) 525 return result 526 527 def select(self, timeout=None): 528 ready = [] 529 fd_events = _syscall_wrapper(self._wrap_poll, True, timeout=timeout) 530 for fd, event_mask in fd_events: 531 events = 0 532 if event_mask & ~select.POLLIN: 533 events |= EVENT_WRITE 534 if event_mask & ~select.POLLOUT: 535 events |= EVENT_READ 536 537 key = self._key_from_fd(fd) 538 if key: 539 ready.append((key, events & key.events)) 540 541 return ready 542 543 def close(self): 544 self._devpoll.close() 545 super(DevpollSelector, self).close() 546 547 __all__.append('DevpollSelector') 548 549 550if hasattr(select, "kqueue"): 551 class KqueueSelector(BaseSelector): 552 """ Kqueue / Kevent-based selector """ 553 def __init__(self): 554 super(KqueueSelector, self).__init__() 555 self._kqueue = select.kqueue() 556 557 def fileno(self): 558 return self._kqueue.fileno() 559 560 def register(self, fileobj, events, data=None): 561 key = super(KqueueSelector, self).register(fileobj, events, data) 562 if events & EVENT_READ: 563 kevent = select.kevent(key.fd, 564 select.KQ_FILTER_READ, 565 select.KQ_EV_ADD) 566 567 _syscall_wrapper(self._wrap_control, False, [kevent], 0, 0) 568 569 if events & EVENT_WRITE: 570 kevent = select.kevent(key.fd, 571 select.KQ_FILTER_WRITE, 572 select.KQ_EV_ADD) 573 574 _syscall_wrapper(self._wrap_control, False, [kevent], 0, 0) 575 576 return key 577 578 def unregister(self, fileobj): 579 key = super(KqueueSelector, self).unregister(fileobj) 580 if key.events & EVENT_READ: 581 kevent = select.kevent(key.fd, 582 select.KQ_FILTER_READ, 583 select.KQ_EV_DELETE) 584 try: 585 _syscall_wrapper(self._wrap_control, False, [kevent], 0, 0) 586 except SelectorError: 587 pass 588 if key.events & EVENT_WRITE: 589 kevent = select.kevent(key.fd, 590 select.KQ_FILTER_WRITE, 591 select.KQ_EV_DELETE) 592 try: 593 _syscall_wrapper(self._wrap_control, False, [kevent], 0, 0) 594 except SelectorError: 595 pass 596 597 return key 598 599 def select(self, timeout=None): 600 if timeout is not None: 601 timeout = max(timeout, 0) 602 603 max_events = len(self._fd_to_key) * 2 604 ready_fds = {} 605 606 kevent_list = _syscall_wrapper(self._wrap_control, True, 607 None, max_events, timeout=timeout) 608 609 for kevent in kevent_list: 610 fd = kevent.ident 611 event_mask = kevent.filter 612 events = 0 613 if event_mask == select.KQ_FILTER_READ: 614 events |= EVENT_READ 615 if event_mask == select.KQ_FILTER_WRITE: 616 events |= EVENT_WRITE 617 618 key = self._key_from_fd(fd) 619 if key: 620 if key.fd not in ready_fds: 621 ready_fds[key.fd] = (key, events & key.events) 622 else: 623 old_events = ready_fds[key.fd][1] 624 ready_fds[key.fd] = (key, (events | old_events) & key.events) 625 626 return list(ready_fds.values()) 627 628 def close(self): 629 self._kqueue.close() 630 super(KqueueSelector, self).close() 631 632 def _wrap_control(self, changelist, max_events, timeout): 633 return self._kqueue.control(changelist, max_events, timeout) 634 635 __all__.append('KqueueSelector') 636 637 638# Choose the best implementation, roughly: 639# kqueue == epoll == devpoll > poll > select. 640# select() also can't accept a FD > FD_SETSIZE (usually around 1024) 641if 'KqueueSelector' in globals(): # Platform-specific: Mac OS and BSD 642 DefaultSelector = KqueueSelector 643elif 'DevpollSelector' in globals(): 644 DefaultSelector = DevpollSelector 645elif 'EpollSelector' in globals(): # Platform-specific: Linux 646 DefaultSelector = EpollSelector 647elif 'PollSelector' in globals(): # Platform-specific: Linux 648 DefaultSelector = PollSelector 649elif 'SelectSelector' in globals(): # Platform-specific: Windows 650 DefaultSelector = SelectSelector 651else: # Platform-specific: AppEngine 652 def no_selector(_): 653 raise ValueError("Platform does not have a selector") 654 DefaultSelector = no_selector 655 HAS_SELECT = False 656