Skip to content

Commit 6e6c59b

Browse files
committed
Issue #23285: PEP 475 -- Retry system calls failing with EINTR.
1 parent d005090 commit 6e6c59b

File tree

18 files changed

+753
-522
lines changed

18 files changed

+753
-522
lines changed

Doc/whatsnew/3.5.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ Please read on for a comprehensive list of user-facing changes.
111111
PEP written by Carl Meyer
112112

113113

114+
PEP 475: Retry system calls failing with EINTR
115+
----------------------------------------------
116+
117+
:pep:`475` adds support for automatic retry of system calls failing with EINTR:
118+
this means that user code doesn't have to deal with EINTR or InterruptedError
119+
manually, and should make it more robust against asynchronous signal reception.
120+
121+
.. seealso::
122+
123+
:pep:`475` -- Retry system calls failing with EINTR
114124

115125

116126
Other Language Changes

Lib/_pyio.py

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1012,10 +1012,7 @@ def _read_unlocked(self, n=None):
10121012
current_size = 0
10131013
while True:
10141014
# Read until EOF or until read() would block.
1015-
try:
1016-
chunk = self.raw.read()
1017-
except InterruptedError:
1018-
continue
1015+
chunk = self.raw.read()
10191016
if chunk in empty_values:
10201017
nodata_val = chunk
10211018
break
@@ -1034,10 +1031,7 @@ def _read_unlocked(self, n=None):
10341031
chunks = [buf[pos:]]
10351032
wanted = max(self.buffer_size, n)
10361033
while avail < n:
1037-
try:
1038-
chunk = self.raw.read(wanted)
1039-
except InterruptedError:
1040-
continue
1034+
chunk = self.raw.read(wanted)
10411035
if chunk in empty_values:
10421036
nodata_val = chunk
10431037
break
@@ -1066,12 +1060,7 @@ def _peek_unlocked(self, n=0):
10661060
have = len(self._read_buf) - self._read_pos
10671061
if have < want or have <= 0:
10681062
to_read = self.buffer_size - have
1069-
while True:
1070-
try:
1071-
current = self.raw.read(to_read)
1072-
except InterruptedError:
1073-
continue
1074-
break
1063+
current = self.raw.read(to_read)
10751064
if current:
10761065
self._read_buf = self._read_buf[self._read_pos:] + current
10771066
self._read_pos = 0
@@ -1220,8 +1209,6 @@ def _flush_unlocked(self):
12201209
while self._write_buf:
12211210
try:
12221211
n = self.raw.write(self._write_buf)
1223-
except InterruptedError:
1224-
continue
12251212
except BlockingIOError:
12261213
raise RuntimeError("self.raw should implement RawIOBase: it "
12271214
"should not raise BlockingIOError")

Lib/distutils/spawn.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,6 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
137137
try:
138138
pid, status = os.waitpid(pid, 0)
139139
except OSError as exc:
140-
import errno
141-
if exc.errno == errno.EINTR:
142-
continue
143140
if not DEBUG:
144141
cmd = executable
145142
raise DistutilsExecError(

Lib/multiprocessing/connection.py

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -365,10 +365,7 @@ def _close(self, _close=os.close):
365365
def _send(self, buf, write=_write):
366366
remaining = len(buf)
367367
while True:
368-
try:
369-
n = write(self._handle, buf)
370-
except InterruptedError:
371-
continue
368+
n = write(self._handle, buf)
372369
remaining -= n
373370
if remaining == 0:
374371
break
@@ -379,10 +376,7 @@ def _recv(self, size, read=_read):
379376
handle = self._handle
380377
remaining = size
381378
while remaining > 0:
382-
try:
383-
chunk = read(handle, remaining)
384-
except InterruptedError:
385-
continue
379+
chunk = read(handle, remaining)
386380
n = len(chunk)
387381
if n == 0:
388382
if remaining == size:
@@ -595,13 +589,7 @@ def __init__(self, address, family, backlog=1):
595589
self._unlink = None
596590

597591
def accept(self):
598-
while True:
599-
try:
600-
s, self._last_accepted = self._socket.accept()
601-
except InterruptedError:
602-
pass
603-
else:
604-
break
592+
s, self._last_accepted = self._socket.accept()
605593
s.setblocking(True)
606594
return Connection(s.detach())
607595

Lib/multiprocessing/forkserver.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,6 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None):
188188
finally:
189189
os._exit(code)
190190

191-
except InterruptedError:
192-
pass
193191
except OSError as e:
194192
if e.errno != errno.ECONNABORTED:
195193
raise
@@ -230,13 +228,7 @@ def read_unsigned(fd):
230228
data = b''
231229
length = UNSIGNED_STRUCT.size
232230
while len(data) < length:
233-
while True:
234-
try:
235-
s = os.read(fd, length - len(data))
236-
except InterruptedError:
237-
pass
238-
else:
239-
break
231+
s = os.read(fd, length - len(data))
240232
if not s:
241233
raise EOFError('unexpected EOF')
242234
data += s
@@ -245,13 +237,7 @@ def read_unsigned(fd):
245237
def write_unsigned(fd, n):
246238
msg = UNSIGNED_STRUCT.pack(n)
247239
while msg:
248-
while True:
249-
try:
250-
nbytes = os.write(fd, msg)
251-
except InterruptedError:
252-
pass
253-
else:
254-
break
240+
nbytes = os.write(fd, msg)
255241
if nbytes == 0:
256242
raise RuntimeError('should not get here')
257243
msg = msg[nbytes:]

Lib/multiprocessing/popen_fork.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import os
22
import sys
33
import signal
4-
import errno
54

65
from . import util
76

@@ -29,8 +28,6 @@ def poll(self, flag=os.WNOHANG):
2928
try:
3029
pid, sts = os.waitpid(self.pid, flag)
3130
except OSError as e:
32-
if e.errno == errno.EINTR:
33-
continue
3431
# Child process not yet created. See #1731717
3532
# e.errno == errno.ECHILD == 10
3633
return None

Lib/socket.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,6 @@ def readinto(self, b):
572572
except timeout:
573573
self._timeout_occurred = True
574574
raise
575-
except InterruptedError:
576-
continue
577575
except error as e:
578576
if e.args[0] in _blocking_errnos:
579577
return None

Lib/socketserver.py

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -553,8 +553,6 @@ def collect_children(self):
553553
try:
554554
pid, _ = os.waitpid(-1, 0)
555555
self.active_children.discard(pid)
556-
except InterruptedError:
557-
pass
558556
except ChildProcessError:
559557
# we don't have any children, we're done
560558
self.active_children.clear()

Lib/subprocess.py

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -489,14 +489,6 @@ def _cleanup():
489489
DEVNULL = -3
490490

491491

492-
def _eintr_retry_call(func, *args):
493-
while True:
494-
try:
495-
return func(*args)
496-
except InterruptedError:
497-
continue
498-
499-
500492
# XXX This function is only used by multiprocessing and the test suite,
501493
# but it's here so that it can be imported when Python is compiled without
502494
# threads.
@@ -963,10 +955,10 @@ def communicate(self, input=None, timeout=None):
963955
if self.stdin:
964956
self._stdin_write(input)
965957
elif self.stdout:
966-
stdout = _eintr_retry_call(self.stdout.read)
958+
stdout = self.stdout.read()
967959
self.stdout.close()
968960
elif self.stderr:
969-
stderr = _eintr_retry_call(self.stderr.read)
961+
stderr = self.stderr.read()
970962
self.stderr.close()
971963
self.wait()
972964
else:
@@ -1410,7 +1402,7 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
14101402
# exception (limited in size)
14111403
errpipe_data = bytearray()
14121404
while True:
1413-
part = _eintr_retry_call(os.read, errpipe_read, 50000)
1405+
part = os.read(errpipe_read, 50000)
14141406
errpipe_data += part
14151407
if not part or len(errpipe_data) > 50000:
14161408
break
@@ -1420,7 +1412,7 @@ def _execute_child(self, args, executable, preexec_fn, close_fds,
14201412

14211413
if errpipe_data:
14221414
try:
1423-
_eintr_retry_call(os.waitpid, self.pid, 0)
1415+
os.waitpid(self.pid, 0)
14241416
except ChildProcessError:
14251417
pass
14261418
try:
@@ -1505,7 +1497,7 @@ def _internal_poll(self, _deadstate=None, _waitpid=os.waitpid,
15051497
def _try_wait(self, wait_flags):
15061498
"""All callers to this function MUST hold self._waitpid_lock."""
15071499
try:
1508-
(pid, sts) = _eintr_retry_call(os.waitpid, self.pid, wait_flags)
1500+
(pid, sts) = os.waitpid(self.pid, wait_flags)
15091501
except ChildProcessError:
15101502
# This happens if SIGCLD is set to be ignored or waiting
15111503
# for child processes has otherwise been disabled for our

0 commit comments

Comments
 (0)