Coverage for /var/srv/projects/api.amasfac.comuna18.com/tmp/venv/lib/python3.9/site-packages/urllib3/util/wait.py: 20%

76 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2023-07-17 14:22 -0600

1import errno 

2import select 

3import sys 

4from functools import partial 

5 

6try: 

7 from time import monotonic 

8except ImportError: 

9 from time import time as monotonic 

10 

11__all__ = ["NoWayToWaitForSocketError", "wait_for_read", "wait_for_write"] 

12 

13 

14class NoWayToWaitForSocketError(Exception): 

15 pass 

16 

17 

18# How should we wait on sockets? 

19# 

20# There are two types of APIs you can use for waiting on sockets: the fancy 

21# modern stateful APIs like epoll/kqueue, and the older stateless APIs like 

22# select/poll. The stateful APIs are more efficient when you have a lots of 

23# sockets to keep track of, because you can set them up once and then use them 

24# lots of times. But we only ever want to wait on a single socket at a time 

25# and don't want to keep track of state, so the stateless APIs are actually 

26# more efficient. So we want to use select() or poll(). 

27# 

28# Now, how do we choose between select() and poll()? On traditional Unixes, 

29# select() has a strange calling convention that makes it slow, or fail 

30# altogether, for high-numbered file descriptors. The point of poll() is to fix 

31# that, so on Unixes, we prefer poll(). 

32# 

33# On Windows, there is no poll() (or at least Python doesn't provide a wrapper 

34# for it), but that's OK, because on Windows, select() doesn't have this 

35# strange calling convention; plain select() works fine. 

36# 

37# So: on Windows we use select(), and everywhere else we use poll(). We also 

38# fall back to select() in case poll() is somehow broken or missing. 

39 

40if sys.version_info >= (3, 5): 40 ↛ 47line 40 didn't jump to line 47, because the condition on line 40 was never false

41 # Modern Python, that retries syscalls by default 

42 def _retry_on_intr(fn, timeout): 

43 return fn(timeout) 

44 

45else: 

46 # Old and broken Pythons. 

47 def _retry_on_intr(fn, timeout): 

48 if timeout is None: 

49 deadline = float("inf") 

50 else: 

51 deadline = monotonic() + timeout 

52 

53 while True: 

54 try: 

55 return fn(timeout) 

56 # OSError for 3 <= pyver < 3.5, select.error for pyver <= 2.7 

57 except (OSError, select.error) as e: 

58 # 'e.args[0]' incantation works for both OSError and select.error 

59 if e.args[0] != errno.EINTR: 

60 raise 

61 else: 

62 timeout = deadline - monotonic() 

63 if timeout < 0: 

64 timeout = 0 

65 if timeout == float("inf"): 

66 timeout = None 

67 continue 

68 

69 

70def select_wait_for_socket(sock, read=False, write=False, timeout=None): 

71 if not read and not write: 

72 raise RuntimeError("must specify at least one of read=True, write=True") 

73 rcheck = [] 

74 wcheck = [] 

75 if read: 

76 rcheck.append(sock) 

77 if write: 

78 wcheck.append(sock) 

79 # When doing a non-blocking connect, most systems signal success by 

80 # marking the socket writable. Windows, though, signals success by marked 

81 # it as "exceptional". We paper over the difference by checking the write 

82 # sockets for both conditions. (The stdlib selectors module does the same 

83 # thing.) 

84 fn = partial(select.select, rcheck, wcheck, wcheck) 

85 rready, wready, xready = _retry_on_intr(fn, timeout) 

86 return bool(rready or wready or xready) 

87 

88 

89def poll_wait_for_socket(sock, read=False, write=False, timeout=None): 

90 if not read and not write: 

91 raise RuntimeError("must specify at least one of read=True, write=True") 

92 mask = 0 

93 if read: 

94 mask |= select.POLLIN 

95 if write: 

96 mask |= select.POLLOUT 

97 poll_obj = select.poll() 

98 poll_obj.register(sock, mask) 

99 

100 # For some reason, poll() takes timeout in milliseconds 

101 def do_poll(t): 

102 if t is not None: 

103 t *= 1000 

104 return poll_obj.poll(t) 

105 

106 return bool(_retry_on_intr(do_poll, timeout)) 

107 

108 

109def null_wait_for_socket(*args, **kwargs): 

110 raise NoWayToWaitForSocketError("no select-equivalent available") 

111 

112 

113def _have_working_poll(): 

114 # Apparently some systems have a select.poll that fails as soon as you try 

115 # to use it, either due to strange configuration or broken monkeypatching 

116 # from libraries like eventlet/greenlet. 

117 try: 

118 poll_obj = select.poll() 

119 _retry_on_intr(poll_obj.poll, 0) 

120 except (AttributeError, OSError): 

121 return False 

122 else: 

123 return True 

124 

125 

126def wait_for_socket(*args, **kwargs): 

127 # We delay choosing which implementation to use until the first time we're 

128 # called. We could do it at import time, but then we might make the wrong 

129 # decision if someone goes wild with monkeypatching select.poll after 

130 # we're imported. 

131 global wait_for_socket 

132 if _have_working_poll(): 

133 wait_for_socket = poll_wait_for_socket 

134 elif hasattr(select, "select"): 

135 wait_for_socket = select_wait_for_socket 

136 else: # Platform-specific: Appengine. 

137 wait_for_socket = null_wait_for_socket 

138 return wait_for_socket(*args, **kwargs) 

139 

140 

141def wait_for_read(sock, timeout=None): 

142 """Waits for reading to be available on a given socket. 

143 Returns True if the socket is readable, or False if the timeout expired. 

144 """ 

145 return wait_for_socket(sock, read=True, timeout=timeout) 

146 

147 

148def wait_for_write(sock, timeout=None): 

149 """Waits for writing to be available on a given socket. 

150 Returns True if the socket is readable, or False if the timeout expired. 

151 """ 

152 return wait_for_socket(sock, write=True, timeout=timeout)