Path: blob/master/venv/Lib/site-packages/urllib3/util/wait.py
811 views
import errno1from functools import partial2import select3import sys45try:6from time import monotonic7except ImportError:8from time import time as monotonic910__all__ = ["NoWayToWaitForSocketError", "wait_for_read", "wait_for_write"]111213class NoWayToWaitForSocketError(Exception):14pass151617# How should we wait on sockets?18#19# There are two types of APIs you can use for waiting on sockets: the fancy20# modern stateful APIs like epoll/kqueue, and the older stateless APIs like21# select/poll. The stateful APIs are more efficient when you have a lots of22# sockets to keep track of, because you can set them up once and then use them23# lots of times. But we only ever want to wait on a single socket at a time24# and don't want to keep track of state, so the stateless APIs are actually25# more efficient. So we want to use select() or poll().26#27# Now, how do we choose between select() and poll()? On traditional Unixes,28# select() has a strange calling convention that makes it slow, or fail29# altogether, for high-numbered file descriptors. The point of poll() is to fix30# that, so on Unixes, we prefer poll().31#32# On Windows, there is no poll() (or at least Python doesn't provide a wrapper33# for it), but that's OK, because on Windows, select() doesn't have this34# strange calling convention; plain select() works fine.35#36# So: on Windows we use select(), and everywhere else we use poll(). We also37# fall back to select() in case poll() is somehow broken or missing.3839if sys.version_info >= (3, 5):40# Modern Python, that retries syscalls by default41def _retry_on_intr(fn, timeout):42return fn(timeout)434445else:46# Old and broken Pythons.47def _retry_on_intr(fn, timeout):48if timeout is None:49deadline = float("inf")50else:51deadline = monotonic() + timeout5253while True:54try:55return fn(timeout)56# OSError for 3 <= pyver < 3.5, select.error for pyver <= 2.757except (OSError, select.error) as e:58# 'e.args[0]' incantation works for both OSError and select.error59if e.args[0] != errno.EINTR:60raise61else:62timeout = deadline - monotonic()63if timeout < 0:64timeout = 065if timeout == float("inf"):66timeout = None67continue686970def select_wait_for_socket(sock, read=False, write=False, timeout=None):71if not read and not write:72raise RuntimeError("must specify at least one of read=True, write=True")73rcheck = []74wcheck = []75if read:76rcheck.append(sock)77if write:78wcheck.append(sock)79# When doing a non-blocking connect, most systems signal success by80# marking the socket writable. Windows, though, signals success by marked81# it as "exceptional". We paper over the difference by checking the write82# sockets for both conditions. (The stdlib selectors module does the same83# thing.)84fn = partial(select.select, rcheck, wcheck, wcheck)85rready, wready, xready = _retry_on_intr(fn, timeout)86return bool(rready or wready or xready)878889def poll_wait_for_socket(sock, read=False, write=False, timeout=None):90if not read and not write:91raise RuntimeError("must specify at least one of read=True, write=True")92mask = 093if read:94mask |= select.POLLIN95if write:96mask |= select.POLLOUT97poll_obj = select.poll()98poll_obj.register(sock, mask)99100# For some reason, poll() takes timeout in milliseconds101def do_poll(t):102if t is not None:103t *= 1000104return poll_obj.poll(t)105106return bool(_retry_on_intr(do_poll, timeout))107108109def null_wait_for_socket(*args, **kwargs):110raise NoWayToWaitForSocketError("no select-equivalent available")111112113def _have_working_poll():114# Apparently some systems have a select.poll that fails as soon as you try115# to use it, either due to strange configuration or broken monkeypatching116# from libraries like eventlet/greenlet.117try:118poll_obj = select.poll()119_retry_on_intr(poll_obj.poll, 0)120except (AttributeError, OSError):121return False122else:123return True124125126def wait_for_socket(*args, **kwargs):127# We delay choosing which implementation to use until the first time we're128# called. We could do it at import time, but then we might make the wrong129# decision if someone goes wild with monkeypatching select.poll after130# we're imported.131global wait_for_socket132if _have_working_poll():133wait_for_socket = poll_wait_for_socket134elif hasattr(select, "select"):135wait_for_socket = select_wait_for_socket136else: # Platform-specific: Appengine.137wait_for_socket = null_wait_for_socket138return wait_for_socket(*args, **kwargs)139140141def wait_for_read(sock, timeout=None):142""" Waits for reading to be available on a given socket.143Returns True if the socket is readable, or False if the timeout expired.144"""145return wait_for_socket(sock, read=True, timeout=timeout)146147148def wait_for_write(sock, timeout=None):149""" Waits for writing to be available on a given socket.150Returns True if the socket is readable, or False if the timeout expired.151"""152return wait_for_socket(sock, write=True, timeout=timeout)153154155