Issue #23285: PEP 475 -- Retry system calls failing with EINTR.
This commit is contained in:
parent
d005090e01
commit
6e6c59b508
|
@ -111,6 +111,16 @@ Please read on for a comprehensive list of user-facing changes.
|
|||
PEP written by Carl Meyer
|
||||
|
||||
|
||||
PEP 475: Retry system calls failing with EINTR
|
||||
----------------------------------------------
|
||||
|
||||
:pep:`475` adds support for automatic retry of system calls failing with EINTR:
|
||||
this means that user code doesn't have to deal with EINTR or InterruptedError
|
||||
manually, and should make it more robust against asynchronous signal reception.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:pep:`475` -- Retry system calls failing with EINTR
|
||||
|
||||
|
||||
Other Language Changes
|
||||
|
|
19
Lib/_pyio.py
19
Lib/_pyio.py
|
@ -1012,10 +1012,7 @@ class BufferedReader(_BufferedIOMixin):
|
|||
current_size = 0
|
||||
while True:
|
||||
# Read until EOF or until read() would block.
|
||||
try:
|
||||
chunk = self.raw.read()
|
||||
except InterruptedError:
|
||||
continue
|
||||
chunk = self.raw.read()
|
||||
if chunk in empty_values:
|
||||
nodata_val = chunk
|
||||
break
|
||||
|
@ -1034,10 +1031,7 @@ class BufferedReader(_BufferedIOMixin):
|
|||
chunks = [buf[pos:]]
|
||||
wanted = max(self.buffer_size, n)
|
||||
while avail < n:
|
||||
try:
|
||||
chunk = self.raw.read(wanted)
|
||||
except InterruptedError:
|
||||
continue
|
||||
chunk = self.raw.read(wanted)
|
||||
if chunk in empty_values:
|
||||
nodata_val = chunk
|
||||
break
|
||||
|
@ -1066,12 +1060,7 @@ class BufferedReader(_BufferedIOMixin):
|
|||
have = len(self._read_buf) - self._read_pos
|
||||
if have < want or have <= 0:
|
||||
to_read = self.buffer_size - have
|
||||
while True:
|
||||
try:
|
||||
current = self.raw.read(to_read)
|
||||
except InterruptedError:
|
||||
continue
|
||||
break
|
||||
current = self.raw.read(to_read)
|
||||
if current:
|
||||
self._read_buf = self._read_buf[self._read_pos:] + current
|
||||
self._read_pos = 0
|
||||
|
@ -1220,8 +1209,6 @@ class BufferedWriter(_BufferedIOMixin):
|
|||
while self._write_buf:
|
||||
try:
|
||||
n = self.raw.write(self._write_buf)
|
||||
except InterruptedError:
|
||||
continue
|
||||
except BlockingIOError:
|
||||
raise RuntimeError("self.raw should implement RawIOBase: it "
|
||||
"should not raise BlockingIOError")
|
||||
|
|
|
@ -137,9 +137,6 @@ def _spawn_posix(cmd, search_path=1, verbose=0, dry_run=0):
|
|||
try:
|
||||
pid, status = os.waitpid(pid, 0)
|
||||
except OSError as exc:
|
||||
import errno
|
||||
if exc.errno == errno.EINTR:
|
||||
continue
|
||||
if not DEBUG:
|
||||
cmd = executable
|
||||
raise DistutilsExecError(
|
||||
|
|
|
@ -365,10 +365,7 @@ class Connection(_ConnectionBase):
|
|||
def _send(self, buf, write=_write):
|
||||
remaining = len(buf)
|
||||
while True:
|
||||
try:
|
||||
n = write(self._handle, buf)
|
||||
except InterruptedError:
|
||||
continue
|
||||
n = write(self._handle, buf)
|
||||
remaining -= n
|
||||
if remaining == 0:
|
||||
break
|
||||
|
@ -379,10 +376,7 @@ class Connection(_ConnectionBase):
|
|||
handle = self._handle
|
||||
remaining = size
|
||||
while remaining > 0:
|
||||
try:
|
||||
chunk = read(handle, remaining)
|
||||
except InterruptedError:
|
||||
continue
|
||||
chunk = read(handle, remaining)
|
||||
n = len(chunk)
|
||||
if n == 0:
|
||||
if remaining == size:
|
||||
|
@ -595,13 +589,7 @@ class SocketListener(object):
|
|||
self._unlink = None
|
||||
|
||||
def accept(self):
|
||||
while True:
|
||||
try:
|
||||
s, self._last_accepted = self._socket.accept()
|
||||
except InterruptedError:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
s, self._last_accepted = self._socket.accept()
|
||||
s.setblocking(True)
|
||||
return Connection(s.detach())
|
||||
|
||||
|
|
|
@ -188,8 +188,6 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None):
|
|||
finally:
|
||||
os._exit(code)
|
||||
|
||||
except InterruptedError:
|
||||
pass
|
||||
except OSError as e:
|
||||
if e.errno != errno.ECONNABORTED:
|
||||
raise
|
||||
|
@ -230,13 +228,7 @@ def read_unsigned(fd):
|
|||
data = b''
|
||||
length = UNSIGNED_STRUCT.size
|
||||
while len(data) < length:
|
||||
while True:
|
||||
try:
|
||||
s = os.read(fd, length - len(data))
|
||||
except InterruptedError:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
s = os.read(fd, length - len(data))
|
||||
if not s:
|
||||
raise EOFError('unexpected EOF')
|
||||
data += s
|
||||
|
@ -245,13 +237,7 @@ def read_unsigned(fd):
|
|||
def write_unsigned(fd, n):
|
||||
msg = UNSIGNED_STRUCT.pack(n)
|
||||
while msg:
|
||||
while True:
|
||||
try:
|
||||
nbytes = os.write(fd, msg)
|
||||
except InterruptedError:
|
||||
pass
|
||||
else:
|
||||
break
|
||||
nbytes = os.write(fd, msg)
|
||||
if nbytes == 0:
|
||||
raise RuntimeError('should not get here')
|
||||
msg = msg[nbytes:]
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import os
|
||||
import sys
|
||||
import signal
|
||||
import errno
|
||||
|
||||
from . import util
|
||||
|
||||
|
@ -29,8 +28,6 @@ class Popen(object):
|
|||
try:
|
||||
pid, sts = os.waitpid(self.pid, flag)
|
||||
except OSError as e:
|
||||
if e.errno == errno.EINTR:
|
||||
continue
|
||||
# Child process not yet created. See #1731717
|
||||
# e.errno == errno.ECHILD == 10
|
||||
return None
|
||||
|
|
|
@ -572,8 +572,6 @@ class SocketIO(io.RawIOBase):
|
|||
except timeout:
|
||||
self._timeout_occurred = True
|
||||
raise
|
||||
except InterruptedError:
|
||||
continue
|
||||
except error as e:
|
||||
if e.args[0] in _blocking_errnos:
|
||||
return None
|
||||
|
|
|
@ -553,8 +553,6 @@ class ForkingMixIn:
|
|||
try:
|
||||
pid, _ = os.waitpid(-1, 0)
|
||||
self.active_children.discard(pid)
|
||||
except InterruptedError:
|
||||
pass
|
||||
except ChildProcessError:
|
||||
# we don't have any children, we're done
|
||||
self.active_children.clear()
|
||||
|
|
|
@ -489,14 +489,6 @@ STDOUT = -2
|
|||
DEVNULL = -3
|
||||
|
||||
|
||||
def _eintr_retry_call(func, *args):
|
||||
while True:
|
||||
try:
|
||||
return func(*args)
|
||||
except InterruptedError:
|
||||
continue
|
||||
|
||||
|
||||
# XXX This function is only used by multiprocessing and the test suite,
|
||||
# but it's here so that it can be imported when Python is compiled without
|
||||
# threads.
|
||||
|
@ -963,10 +955,10 @@ class Popen(object):
|
|||
if self.stdin:
|
||||
self._stdin_write(input)
|
||||
elif self.stdout:
|
||||
stdout = _eintr_retry_call(self.stdout.read)
|
||||
stdout = self.stdout.read()
|
||||
self.stdout.close()
|
||||
elif self.stderr:
|
||||
stderr = _eintr_retry_call(self.stderr.read)
|
||||
stderr = self.stderr.read()
|
||||
self.stderr.close()
|
||||
self.wait()
|
||||
else:
|
||||
|
@ -1410,7 +1402,7 @@ class Popen(object):
|
|||
# exception (limited in size)
|
||||
errpipe_data = bytearray()
|
||||
while True:
|
||||
part = _eintr_retry_call(os.read, errpipe_read, 50000)
|
||||
part = os.read(errpipe_read, 50000)
|
||||
errpipe_data += part
|
||||
if not part or len(errpipe_data) > 50000:
|
||||
break
|
||||
|
@ -1420,7 +1412,7 @@ class Popen(object):
|
|||
|
||||
if errpipe_data:
|
||||
try:
|
||||
_eintr_retry_call(os.waitpid, self.pid, 0)
|
||||
os.waitpid(self.pid, 0)
|
||||
except ChildProcessError:
|
||||
pass
|
||||
try:
|
||||
|
@ -1505,7 +1497,7 @@ class Popen(object):
|
|||
def _try_wait(self, wait_flags):
|
||||
"""All callers to this function MUST hold self._waitpid_lock."""
|
||||
try:
|
||||
(pid, sts) = _eintr_retry_call(os.waitpid, self.pid, wait_flags)
|
||||
(pid, sts) = os.waitpid(self.pid, wait_flags)
|
||||
except ChildProcessError:
|
||||
# This happens if SIGCLD is set to be ignored or waiting
|
||||
# for child processes has otherwise been disabled for our
|
||||
|
|
|
@ -0,0 +1,260 @@
|
|||
"""
|
||||
This test suite exercises some system calls subject to interruption with EINTR,
|
||||
to check that it is actually handled transparently.
|
||||
It is intended to be run by the main test suite within a child process, to
|
||||
ensure there is no background thread running (so that signals are delivered to
|
||||
the correct thread).
|
||||
Signals are generated in-process using setitimer(ITIMER_REAL), which allows
|
||||
sub-second periodicity (contrarily to signal()).
|
||||
"""
|
||||
|
||||
import io
|
||||
import os
|
||||
import signal
|
||||
import socket
|
||||
import time
|
||||
import unittest
|
||||
|
||||
from test import support
|
||||
|
||||
|
||||
@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()")
|
||||
class EINTRBaseTest(unittest.TestCase):
|
||||
""" Base class for EINTR tests. """
|
||||
|
||||
# delay for initial signal delivery
|
||||
signal_delay = 0.1
|
||||
# signal delivery periodicity
|
||||
signal_period = 0.1
|
||||
# default sleep time for tests - should obviously have:
|
||||
# sleep_time > signal_period
|
||||
sleep_time = 0.2
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.orig_handler = signal.signal(signal.SIGALRM, lambda *args: None)
|
||||
signal.setitimer(signal.ITIMER_REAL, cls.signal_delay,
|
||||
cls.signal_period)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
signal.setitimer(signal.ITIMER_REAL, 0, 0)
|
||||
signal.signal(signal.SIGALRM, cls.orig_handler)
|
||||
|
||||
@classmethod
|
||||
def _sleep(cls):
|
||||
# default sleep time
|
||||
time.sleep(cls.sleep_time)
|
||||
|
||||
|
||||
@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()")
|
||||
class OSEINTRTest(EINTRBaseTest):
|
||||
""" EINTR tests for the os module. """
|
||||
|
||||
def _test_wait_multiple(self, wait_func):
|
||||
num = 3
|
||||
for _ in range(num):
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
self._sleep()
|
||||
os._exit(0)
|
||||
for _ in range(num):
|
||||
wait_func()
|
||||
|
||||
def test_wait(self):
|
||||
self._test_wait_multiple(os.wait)
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'wait3'), 'requires wait3()')
|
||||
def test_wait3(self):
|
||||
self._test_wait_multiple(lambda: os.wait3(0))
|
||||
|
||||
def _test_wait_single(self, wait_func):
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
self._sleep()
|
||||
os._exit(0)
|
||||
else:
|
||||
wait_func(pid)
|
||||
|
||||
def test_waitpid(self):
|
||||
self._test_wait_single(lambda pid: os.waitpid(pid, 0))
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'wait4'), 'requires wait4()')
|
||||
def test_wait4(self):
|
||||
self._test_wait_single(lambda pid: os.wait4(pid, 0))
|
||||
|
||||
def test_read(self):
|
||||
rd, wr = os.pipe()
|
||||
self.addCleanup(os.close, rd)
|
||||
# wr closed explicitly by parent
|
||||
|
||||
# the payload below are smaller than PIPE_BUF, hence the writes will be
|
||||
# atomic
|
||||
datas = [b"hello", b"world", b"spam"]
|
||||
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
os.close(rd)
|
||||
for data in datas:
|
||||
# let the parent block on read()
|
||||
self._sleep()
|
||||
os.write(wr, data)
|
||||
os._exit(0)
|
||||
else:
|
||||
self.addCleanup(os.waitpid, pid, 0)
|
||||
os.close(wr)
|
||||
for data in datas:
|
||||
self.assertEqual(data, os.read(rd, len(data)))
|
||||
|
||||
def test_write(self):
|
||||
rd, wr = os.pipe()
|
||||
self.addCleanup(os.close, wr)
|
||||
# rd closed explicitly by parent
|
||||
|
||||
# we must write enough data for the write() to block
|
||||
data = b"xyz" * support.PIPE_MAX_SIZE
|
||||
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
os.close(wr)
|
||||
read_data = io.BytesIO()
|
||||
# let the parent block on write()
|
||||
self._sleep()
|
||||
while len(read_data.getvalue()) < len(data):
|
||||
chunk = os.read(rd, 2 * len(data))
|
||||
read_data.write(chunk)
|
||||
self.assertEqual(read_data.getvalue(), data)
|
||||
os._exit(0)
|
||||
else:
|
||||
os.close(rd)
|
||||
written = 0
|
||||
while written < len(data):
|
||||
written += os.write(wr, memoryview(data)[written:])
|
||||
self.assertEqual(0, os.waitpid(pid, 0)[1])
|
||||
|
||||
|
||||
@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()")
|
||||
class SocketEINTRTest(EINTRBaseTest):
|
||||
""" EINTR tests for the socket module. """
|
||||
|
||||
@unittest.skipUnless(hasattr(socket, 'socketpair'), 'needs socketpair()')
|
||||
def _test_recv(self, recv_func):
|
||||
rd, wr = socket.socketpair()
|
||||
self.addCleanup(rd.close)
|
||||
# wr closed explicitly by parent
|
||||
|
||||
# single-byte payload guard us against partial recv
|
||||
datas = [b"x", b"y", b"z"]
|
||||
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
rd.close()
|
||||
for data in datas:
|
||||
# let the parent block on recv()
|
||||
self._sleep()
|
||||
wr.sendall(data)
|
||||
os._exit(0)
|
||||
else:
|
||||
self.addCleanup(os.waitpid, pid, 0)
|
||||
wr.close()
|
||||
for data in datas:
|
||||
self.assertEqual(data, recv_func(rd, len(data)))
|
||||
|
||||
def test_recv(self):
|
||||
self._test_recv(socket.socket.recv)
|
||||
|
||||
@unittest.skipUnless(hasattr(socket.socket, 'recvmsg'), 'needs recvmsg()')
|
||||
def test_recvmsg(self):
|
||||
self._test_recv(lambda sock, data: sock.recvmsg(data)[0])
|
||||
|
||||
def _test_send(self, send_func):
|
||||
rd, wr = socket.socketpair()
|
||||
self.addCleanup(wr.close)
|
||||
# rd closed explicitly by parent
|
||||
|
||||
# we must send enough data for the send() to block
|
||||
data = b"xyz" * (support.SOCK_MAX_SIZE // 3)
|
||||
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
wr.close()
|
||||
# let the parent block on send()
|
||||
self._sleep()
|
||||
received_data = bytearray(len(data))
|
||||
n = 0
|
||||
while n < len(data):
|
||||
n += rd.recv_into(memoryview(received_data)[n:])
|
||||
self.assertEqual(received_data, data)
|
||||
os._exit(0)
|
||||
else:
|
||||
rd.close()
|
||||
written = 0
|
||||
while written < len(data):
|
||||
sent = send_func(wr, memoryview(data)[written:])
|
||||
# sendall() returns None
|
||||
written += len(data) if sent is None else sent
|
||||
self.assertEqual(0, os.waitpid(pid, 0)[1])
|
||||
|
||||
def test_send(self):
|
||||
self._test_send(socket.socket.send)
|
||||
|
||||
def test_sendall(self):
|
||||
self._test_send(socket.socket.sendall)
|
||||
|
||||
@unittest.skipUnless(hasattr(socket.socket, 'sendmsg'), 'needs sendmsg()')
|
||||
def test_sendmsg(self):
|
||||
self._test_send(lambda sock, data: sock.sendmsg([data]))
|
||||
|
||||
def test_accept(self):
|
||||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.addCleanup(sock.close)
|
||||
|
||||
sock.bind((support.HOST, 0))
|
||||
_, port = sock.getsockname()
|
||||
sock.listen()
|
||||
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
# let parent block on accept()
|
||||
self._sleep()
|
||||
with socket.create_connection((support.HOST, port)):
|
||||
self._sleep()
|
||||
os._exit(0)
|
||||
else:
|
||||
self.addCleanup(os.waitpid, pid, 0)
|
||||
client_sock, _ = sock.accept()
|
||||
client_sock.close()
|
||||
|
||||
@unittest.skipUnless(hasattr(os, 'mkfifo'), 'needs mkfifo()')
|
||||
def _test_open(self, do_open_close_reader, do_open_close_writer):
|
||||
# Use a fifo: until the child opens it for reading, the parent will
|
||||
# block when trying to open it for writing.
|
||||
support.unlink(support.TESTFN)
|
||||
os.mkfifo(support.TESTFN)
|
||||
self.addCleanup(support.unlink, support.TESTFN)
|
||||
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
# let the parent block
|
||||
self._sleep()
|
||||
do_open_close_reader(support.TESTFN)
|
||||
os._exit(0)
|
||||
else:
|
||||
self.addCleanup(os.waitpid, pid, 0)
|
||||
do_open_close_writer(support.TESTFN)
|
||||
|
||||
def test_open(self):
|
||||
self._test_open(lambda path: open(path, 'r').close(),
|
||||
lambda path: open(path, 'w').close())
|
||||
|
||||
def test_os_open(self):
|
||||
self._test_open(lambda path: os.close(os.open(path, os.O_RDONLY)),
|
||||
lambda path: os.close(os.open(path, os.O_WRONLY)))
|
||||
|
||||
|
||||
def test_main():
|
||||
support.run_unittest(OSEINTRTest, SocketEINTRTest)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_main()
|
|
@ -0,0 +1,20 @@
|
|||
import os
|
||||
import signal
|
||||
import unittest
|
||||
|
||||
from test import script_helper, support
|
||||
|
||||
|
||||
@unittest.skipUnless(os.name == "posix", "only supported on Unix")
|
||||
class EINTRTests(unittest.TestCase):
|
||||
|
||||
@unittest.skipUnless(hasattr(signal, "setitimer"), "requires setitimer()")
|
||||
def test_all(self):
|
||||
# Run the tester in a sub-process, to make sure there is only one
|
||||
# thread (for reliable signal delivery).
|
||||
tester = support.findfile("eintr_tester.py", subdir="eintrdata")
|
||||
script_helper.assert_python_ok(tester)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
|
@ -587,7 +587,7 @@ class SiginterruptTest(unittest.TestCase):
|
|||
r, w = os.pipe()
|
||||
|
||||
def handler(signum, frame):
|
||||
pass
|
||||
1 / 0
|
||||
|
||||
signal.signal(signal.SIGALRM, handler)
|
||||
if interrupt is not None:
|
||||
|
@ -604,9 +604,8 @@ class SiginterruptTest(unittest.TestCase):
|
|||
try:
|
||||
# blocking call: read from a pipe without data
|
||||
os.read(r, 1)
|
||||
except OSError as err:
|
||||
if err.errno != errno.EINTR:
|
||||
raise
|
||||
except ZeroDivisionError:
|
||||
pass
|
||||
else:
|
||||
sys.exit(2)
|
||||
sys.exit(3)
|
||||
|
|
|
@ -3590,7 +3590,7 @@ class InterruptedTimeoutBase(unittest.TestCase):
|
|||
def setUp(self):
|
||||
super().setUp()
|
||||
orig_alrm_handler = signal.signal(signal.SIGALRM,
|
||||
lambda signum, frame: None)
|
||||
lambda signum, frame: 1 / 0)
|
||||
self.addCleanup(signal.signal, signal.SIGALRM, orig_alrm_handler)
|
||||
self.addCleanup(self.setAlarm, 0)
|
||||
|
||||
|
@ -3627,13 +3627,11 @@ class InterruptedRecvTimeoutTest(InterruptedTimeoutBase, UDPTestBase):
|
|||
self.serv.settimeout(self.timeout)
|
||||
|
||||
def checkInterruptedRecv(self, func, *args, **kwargs):
|
||||
# Check that func(*args, **kwargs) raises OSError with an
|
||||
# Check that func(*args, **kwargs) raises
|
||||
# errno of EINTR when interrupted by a signal.
|
||||
self.setAlarm(self.alarm_time)
|
||||
with self.assertRaises(OSError) as cm:
|
||||
with self.assertRaises(ZeroDivisionError) as cm:
|
||||
func(*args, **kwargs)
|
||||
self.assertNotIsInstance(cm.exception, socket.timeout)
|
||||
self.assertEqual(cm.exception.errno, errno.EINTR)
|
||||
|
||||
def testInterruptedRecvTimeout(self):
|
||||
self.checkInterruptedRecv(self.serv.recv, 1024)
|
||||
|
@ -3689,12 +3687,10 @@ class InterruptedSendTimeoutTest(InterruptedTimeoutBase,
|
|||
# Check that func(*args, **kwargs), run in a loop, raises
|
||||
# OSError with an errno of EINTR when interrupted by a
|
||||
# signal.
|
||||
with self.assertRaises(OSError) as cm:
|
||||
with self.assertRaises(ZeroDivisionError) as cm:
|
||||
while True:
|
||||
self.setAlarm(self.alarm_time)
|
||||
func(*args, **kwargs)
|
||||
self.assertNotIsInstance(cm.exception, socket.timeout)
|
||||
self.assertEqual(cm.exception.errno, errno.EINTR)
|
||||
|
||||
# Issue #12958: The following tests have problems on OS X prior to 10.7
|
||||
@support.requires_mac_ver(10, 7)
|
||||
|
@ -4062,117 +4058,6 @@ class FileObjectClassTestCase(SocketConnectedTest):
|
|||
pass
|
||||
|
||||
|
||||
class FileObjectInterruptedTestCase(unittest.TestCase):
|
||||
"""Test that the file object correctly handles EINTR internally."""
|
||||
|
||||
class MockSocket(object):
|
||||
def __init__(self, recv_funcs=()):
|
||||
# A generator that returns callables that we'll call for each
|
||||
# call to recv().
|
||||
self._recv_step = iter(recv_funcs)
|
||||
|
||||
def recv_into(self, buffer):
|
||||
data = next(self._recv_step)()
|
||||
assert len(buffer) >= len(data)
|
||||
buffer[:len(data)] = data
|
||||
return len(data)
|
||||
|
||||
def _decref_socketios(self):
|
||||
pass
|
||||
|
||||
def _textiowrap_for_test(self, buffering=-1):
|
||||
raw = socket.SocketIO(self, "r")
|
||||
if buffering < 0:
|
||||
buffering = io.DEFAULT_BUFFER_SIZE
|
||||
if buffering == 0:
|
||||
return raw
|
||||
buffer = io.BufferedReader(raw, buffering)
|
||||
text = io.TextIOWrapper(buffer, None, None)
|
||||
text.mode = "rb"
|
||||
return text
|
||||
|
||||
@staticmethod
|
||||
def _raise_eintr():
|
||||
raise OSError(errno.EINTR, "interrupted")
|
||||
|
||||
def _textiowrap_mock_socket(self, mock, buffering=-1):
|
||||
raw = socket.SocketIO(mock, "r")
|
||||
if buffering < 0:
|
||||
buffering = io.DEFAULT_BUFFER_SIZE
|
||||
if buffering == 0:
|
||||
return raw
|
||||
buffer = io.BufferedReader(raw, buffering)
|
||||
text = io.TextIOWrapper(buffer, None, None)
|
||||
text.mode = "rb"
|
||||
return text
|
||||
|
||||
def _test_readline(self, size=-1, buffering=-1):
|
||||
mock_sock = self.MockSocket(recv_funcs=[
|
||||
lambda : b"This is the first line\nAnd the sec",
|
||||
self._raise_eintr,
|
||||
lambda : b"ond line is here\n",
|
||||
lambda : b"",
|
||||
lambda : b"", # XXX(gps): io library does an extra EOF read
|
||||
])
|
||||
fo = mock_sock._textiowrap_for_test(buffering=buffering)
|
||||
self.assertEqual(fo.readline(size), "This is the first line\n")
|
||||
self.assertEqual(fo.readline(size), "And the second line is here\n")
|
||||
|
||||
def _test_read(self, size=-1, buffering=-1):
|
||||
mock_sock = self.MockSocket(recv_funcs=[
|
||||
lambda : b"This is the first line\nAnd the sec",
|
||||
self._raise_eintr,
|
||||
lambda : b"ond line is here\n",
|
||||
lambda : b"",
|
||||
lambda : b"", # XXX(gps): io library does an extra EOF read
|
||||
])
|
||||
expecting = (b"This is the first line\n"
|
||||
b"And the second line is here\n")
|
||||
fo = mock_sock._textiowrap_for_test(buffering=buffering)
|
||||
if buffering == 0:
|
||||
data = b''
|
||||
else:
|
||||
data = ''
|
||||
expecting = expecting.decode('utf-8')
|
||||
while len(data) != len(expecting):
|
||||
part = fo.read(size)
|
||||
if not part:
|
||||
break
|
||||
data += part
|
||||
self.assertEqual(data, expecting)
|
||||
|
||||
def test_default(self):
|
||||
self._test_readline()
|
||||
self._test_readline(size=100)
|
||||
self._test_read()
|
||||
self._test_read(size=100)
|
||||
|
||||
def test_with_1k_buffer(self):
|
||||
self._test_readline(buffering=1024)
|
||||
self._test_readline(size=100, buffering=1024)
|
||||
self._test_read(buffering=1024)
|
||||
self._test_read(size=100, buffering=1024)
|
||||
|
||||
def _test_readline_no_buffer(self, size=-1):
|
||||
mock_sock = self.MockSocket(recv_funcs=[
|
||||
lambda : b"a",
|
||||
lambda : b"\n",
|
||||
lambda : b"B",
|
||||
self._raise_eintr,
|
||||
lambda : b"b",
|
||||
lambda : b"",
|
||||
])
|
||||
fo = mock_sock._textiowrap_for_test(buffering=0)
|
||||
self.assertEqual(fo.readline(size), b"a\n")
|
||||
self.assertEqual(fo.readline(size), b"Bb")
|
||||
|
||||
def test_no_buffer(self):
|
||||
self._test_readline_no_buffer()
|
||||
self._test_readline_no_buffer(size=4)
|
||||
self._test_read(buffering=0)
|
||||
self._test_read(size=100, buffering=0)
|
||||
|
||||
|
||||
class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase):
|
||||
|
||||
"""Repeat the tests from FileObjectClassTestCase with bufsize==0.
|
||||
|
@ -5388,7 +5273,6 @@ def test_main():
|
|||
tests.extend([
|
||||
NonBlockingTCPTests,
|
||||
FileObjectClassTestCase,
|
||||
FileObjectInterruptedTestCase,
|
||||
UnbufferedFileObjectClassTestCase,
|
||||
LineBufferedFileObjectClassTestCase,
|
||||
SmallBufferedFileObjectClassTestCase,
|
||||
|
|
|
@ -2421,25 +2421,6 @@ class ProcessTestCaseNoPoll(ProcessTestCase):
|
|||
ProcessTestCase.tearDown(self)
|
||||
|
||||
|
||||
class HelperFunctionTests(unittest.TestCase):
|
||||
@unittest.skipIf(mswindows, "errno and EINTR make no sense on windows")
|
||||
def test_eintr_retry_call(self):
|
||||
record_calls = []
|
||||
def fake_os_func(*args):
|
||||
record_calls.append(args)
|
||||
if len(record_calls) == 2:
|
||||
raise OSError(errno.EINTR, "fake interrupted system call")
|
||||
return tuple(reversed(args))
|
||||
|
||||
self.assertEqual((999, 256),
|
||||
subprocess._eintr_retry_call(fake_os_func, 256, 999))
|
||||
self.assertEqual([(256, 999)], record_calls)
|
||||
# This time there will be an EINTR so it will loop once.
|
||||
self.assertEqual((666,),
|
||||
subprocess._eintr_retry_call(fake_os_func, 666))
|
||||
self.assertEqual([(256, 999), (666,), (666,)], record_calls)
|
||||
|
||||
|
||||
@unittest.skipUnless(mswindows, "Windows-specific tests")
|
||||
class CommandsWithSpaces (BaseTestCase):
|
||||
|
||||
|
@ -2528,7 +2509,6 @@ def test_main():
|
|||
Win32ProcessTestCase,
|
||||
CommandTests,
|
||||
ProcessTestCaseNoPoll,
|
||||
HelperFunctionTests,
|
||||
CommandsWithSpaces,
|
||||
ContextManagerTests,
|
||||
)
|
||||
|
|
|
@ -10,6 +10,8 @@ Release date: TBA
|
|||
Core and Builtins
|
||||
-----------------
|
||||
|
||||
- Issue #23285: PEP 475 - EINTR handling.
|
||||
|
||||
- Issue #22735: Fix many edge cases (including crashes) involving custom mro()
|
||||
implementations.
|
||||
|
||||
|
|
|
@ -218,6 +218,7 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
|
|||
#ifdef HAVE_FSTAT
|
||||
struct stat fdfstat;
|
||||
#endif
|
||||
int async_err = 0;
|
||||
|
||||
assert(PyFileIO_Check(oself));
|
||||
if (self->fd >= 0) {
|
||||
|
@ -360,15 +361,18 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
|
|||
|
||||
errno = 0;
|
||||
if (opener == Py_None) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
#ifdef MS_WINDOWS
|
||||
if (widename != NULL)
|
||||
self->fd = _wopen(widename, flags, 0666);
|
||||
else
|
||||
if (widename != NULL)
|
||||
self->fd = _wopen(widename, flags, 0666);
|
||||
else
|
||||
#endif
|
||||
self->fd = open(name, flags, 0666);
|
||||
self->fd = open(name, flags, 0666);
|
||||
|
||||
Py_END_ALLOW_THREADS
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (self->fd < 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
}
|
||||
else {
|
||||
PyObject *fdobj;
|
||||
|
@ -397,7 +401,8 @@ fileio_init(PyObject *oself, PyObject *args, PyObject *kwds)
|
|||
|
||||
fd_is_own = 1;
|
||||
if (self->fd < 0) {
|
||||
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
|
||||
if (!async_err)
|
||||
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, nameobj);
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
@ -550,7 +555,7 @@ fileio_readinto(fileio *self, PyObject *args)
|
|||
{
|
||||
Py_buffer pbuf;
|
||||
Py_ssize_t n, len;
|
||||
int err;
|
||||
int err, async_err = 0;
|
||||
|
||||
if (self->fd < 0)
|
||||
return err_closed();
|
||||
|
@ -562,16 +567,19 @@ fileio_readinto(fileio *self, PyObject *args)
|
|||
|
||||
if (_PyVerify_fd(self->fd)) {
|
||||
len = pbuf.len;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
#ifdef MS_WINDOWS
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = read(self->fd, pbuf.buf, (int)len);
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = read(self->fd, pbuf.buf, (int)len);
|
||||
#else
|
||||
n = read(self->fd, pbuf.buf, len);
|
||||
n = read(self->fd, pbuf.buf, len);
|
||||
#endif
|
||||
Py_END_ALLOW_THREADS
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
} else
|
||||
n = -1;
|
||||
err = errno;
|
||||
|
@ -580,7 +588,8 @@ fileio_readinto(fileio *self, PyObject *args)
|
|||
if (err == EAGAIN)
|
||||
Py_RETURN_NONE;
|
||||
errno = err;
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
if (!async_err)
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -627,6 +636,7 @@ fileio_readall(fileio *self)
|
|||
Py_ssize_t bytes_read = 0;
|
||||
Py_ssize_t n;
|
||||
size_t bufsize;
|
||||
int async_err = 0;
|
||||
|
||||
if (self->fd < 0)
|
||||
return err_closed();
|
||||
|
@ -673,27 +683,23 @@ fileio_readall(fileio *self)
|
|||
return NULL;
|
||||
}
|
||||
}
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
n = bufsize - bytes_read;
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
n = bufsize - bytes_read;
|
||||
#ifdef MS_WINDOWS
|
||||
if (n > INT_MAX)
|
||||
n = INT_MAX;
|
||||
n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n);
|
||||
if (n > INT_MAX)
|
||||
n = INT_MAX;
|
||||
n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, (int)n);
|
||||
#else
|
||||
n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n);
|
||||
n = read(self->fd, PyBytes_AS_STRING(result) + bytes_read, n);
|
||||
#endif
|
||||
Py_END_ALLOW_THREADS
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
if (n == 0)
|
||||
break;
|
||||
if (n < 0) {
|
||||
if (errno == EINTR) {
|
||||
if (PyErr_CheckSignals()) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (errno == EAGAIN) {
|
||||
if (bytes_read > 0)
|
||||
break;
|
||||
|
@ -701,7 +707,8 @@ fileio_readall(fileio *self)
|
|||
Py_RETURN_NONE;
|
||||
}
|
||||
Py_DECREF(result);
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
if (!async_err)
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
bytes_read += n;
|
||||
|
@ -723,6 +730,7 @@ fileio_read(fileio *self, PyObject *args)
|
|||
char *ptr;
|
||||
Py_ssize_t n;
|
||||
Py_ssize_t size = -1;
|
||||
int async_err = 0;
|
||||
PyObject *bytes;
|
||||
|
||||
if (self->fd < 0)
|
||||
|
@ -747,14 +755,17 @@ fileio_read(fileio *self, PyObject *args)
|
|||
ptr = PyBytes_AS_STRING(bytes);
|
||||
|
||||
if (_PyVerify_fd(self->fd)) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
#ifdef MS_WINDOWS
|
||||
n = read(self->fd, ptr, (int)size);
|
||||
n = read(self->fd, ptr, (int)size);
|
||||
#else
|
||||
n = read(self->fd, ptr, size);
|
||||
n = read(self->fd, ptr, size);
|
||||
#endif
|
||||
Py_END_ALLOW_THREADS
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
} else
|
||||
n = -1;
|
||||
|
||||
|
@ -764,7 +775,8 @@ fileio_read(fileio *self, PyObject *args)
|
|||
if (err == EAGAIN)
|
||||
Py_RETURN_NONE;
|
||||
errno = err;
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
if (!async_err)
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -783,7 +795,7 @@ fileio_write(fileio *self, PyObject *args)
|
|||
{
|
||||
Py_buffer pbuf;
|
||||
Py_ssize_t n, len;
|
||||
int err;
|
||||
int err, async_err = 0;
|
||||
|
||||
if (self->fd < 0)
|
||||
return err_closed();
|
||||
|
@ -794,24 +806,26 @@ fileio_write(fileio *self, PyObject *args)
|
|||
return NULL;
|
||||
|
||||
if (_PyVerify_fd(self->fd)) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
len = pbuf.len;
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
errno = 0;
|
||||
len = pbuf.len;
|
||||
#ifdef MS_WINDOWS
|
||||
if (len > 32767 && isatty(self->fd)) {
|
||||
/* Issue #11395: the Windows console returns an error (12: not
|
||||
enough space error) on writing into stdout if stdout mode is
|
||||
binary and the length is greater than 66,000 bytes (or less,
|
||||
depending on heap usage). */
|
||||
len = 32767;
|
||||
}
|
||||
else if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = write(self->fd, pbuf.buf, (int)len);
|
||||
if (len > 32767 && isatty(self->fd)) {
|
||||
/* Issue #11395: the Windows console returns an error (12: not
|
||||
enough space error) on writing into stdout if stdout mode is
|
||||
binary and the length is greater than 66,000 bytes (or less,
|
||||
depending on heap usage). */
|
||||
len = 32767;
|
||||
} else if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = write(self->fd, pbuf.buf, (int)len);
|
||||
#else
|
||||
n = write(self->fd, pbuf.buf, len);
|
||||
n = write(self->fd, pbuf.buf, len);
|
||||
#endif
|
||||
Py_END_ALLOW_THREADS
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
} else
|
||||
n = -1;
|
||||
err = errno;
|
||||
|
@ -822,7 +836,8 @@ fileio_write(fileio *self, PyObject *args)
|
|||
if (err == EAGAIN)
|
||||
Py_RETURN_NONE;
|
||||
errno = err;
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
if (!async_err)
|
||||
PyErr_SetFromErrno(PyExc_IOError);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -1361,13 +1361,16 @@ static PyObject *
|
|||
posix_fildes_fd(int fd, int (*func)(int))
|
||||
{
|
||||
int res;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = (*func)(fd);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res < 0)
|
||||
return posix_error();
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
int async_err = 0;
|
||||
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = (*func)(fd);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (res != 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3479,11 +3482,16 @@ os_fchmod_impl(PyModuleDef *module, int fd, int mode)
|
|||
/*[clinic end generated code: output=3c19fbfd724a8e0f input=8ab11975ca01ee5b]*/
|
||||
{
|
||||
int res;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = fchmod(fd, mode);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res < 0)
|
||||
return posix_error();
|
||||
int async_err = 0;
|
||||
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = fchmod(fd, mode);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (res != 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif /* HAVE_FCHMOD */
|
||||
|
@ -4104,11 +4112,16 @@ os_fchown_impl(PyModuleDef *module, int fd, uid_t uid, gid_t gid)
|
|||
/*[clinic end generated code: output=687781cb7d8974d6 input=3af544ba1b13a0d7]*/
|
||||
{
|
||||
int res;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = fchown(fd, uid, gid);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res < 0)
|
||||
return posix_error();
|
||||
int async_err = 0;
|
||||
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = fchown(fd, uid, gid);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (res != 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif /* HAVE_FCHOWN */
|
||||
|
@ -9602,12 +9615,17 @@ os_wait3_impl(PyModuleDef *module, int options)
|
|||
{
|
||||
pid_t pid;
|
||||
struct rusage ru;
|
||||
int async_err = 0;
|
||||
WAIT_TYPE status;
|
||||
WAIT_STATUS_INT(status) = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
pid = wait3(&status, options, &ru);
|
||||
Py_END_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
pid = wait3(&status, options, &ru);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (pid < 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
return wait_helper(pid, WAIT_STATUS_INT(status), &ru);
|
||||
}
|
||||
|
@ -9665,15 +9683,21 @@ static PyObject *
|
|||
os_wait4_impl(PyModuleDef *module, pid_t pid, int options)
|
||||
/*[clinic end generated code: output=20dfb05289d37dc6 input=d11deed0750600ba]*/
|
||||
{
|
||||
pid_t res;
|
||||
struct rusage ru;
|
||||
int async_err = 0;
|
||||
WAIT_TYPE status;
|
||||
WAIT_STATUS_INT(status) = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
pid = wait4(pid, &status, options, &ru);
|
||||
Py_END_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = wait4(pid, &status, options, &ru);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (res < 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
return wait_helper(pid, WAIT_STATUS_INT(status), &ru);
|
||||
return wait_helper(res, WAIT_STATUS_INT(status), &ru);
|
||||
}
|
||||
#endif /* HAVE_WAIT4 */
|
||||
|
||||
|
@ -9744,14 +9768,17 @@ os_waitid_impl(PyModuleDef *module, idtype_t idtype, id_t id, int options)
|
|||
{
|
||||
PyObject *result;
|
||||
int res;
|
||||
int async_err = 0;
|
||||
siginfo_t si;
|
||||
si.si_pid = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = waitid(idtype, id, &si, options);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (res == -1)
|
||||
return posix_error();
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = waitid(idtype, id, &si, options);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (res < 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
if (si.si_pid == 0)
|
||||
Py_RETURN_NONE;
|
||||
|
@ -9828,16 +9855,20 @@ static PyObject *
|
|||
os_waitpid_impl(PyModuleDef *module, pid_t pid, int options)
|
||||
/*[clinic end generated code: output=095a6b00af70b7ac input=0bf1666b8758fda3]*/
|
||||
{
|
||||
pid_t res;
|
||||
int async_err = 0;
|
||||
WAIT_TYPE status;
|
||||
WAIT_STATUS_INT(status) = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
pid = waitpid(pid, &status, options);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (pid == -1)
|
||||
return posix_error();
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = waitpid(pid, &status, options);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (res < 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status));
|
||||
return Py_BuildValue("Ni", PyLong_FromPid(res), WAIT_STATUS_INT(status));
|
||||
}
|
||||
#elif defined(HAVE_CWAIT)
|
||||
/* MS C has a variant of waitpid() that's usable for most purposes. */
|
||||
|
@ -9894,15 +9925,19 @@ os_waitpid_impl(PyModuleDef *module, Py_intptr_t pid, int options)
|
|||
/*[clinic end generated code: output=c20b95b15ad44a3a input=444c8f51cca5b862]*/
|
||||
{
|
||||
int status;
|
||||
Py_intptr_t res;
|
||||
int async_err = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
pid = _cwait(&status, pid, options);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (pid == -1)
|
||||
return posix_error();
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = _cwait(&status, pid, options);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (res != 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
/* shift the status left a byte so this is more like the POSIX waitpid */
|
||||
return Py_BuildValue(_Py_PARSE_INTPTR "i", pid, status << 8);
|
||||
return Py_BuildValue(_Py_PARSE_INTPTR "i", res, status << 8);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -9943,14 +9978,17 @@ os_wait_impl(PyModuleDef *module)
|
|||
/*[clinic end generated code: output=2a83a9d164e7e6a8 input=03b0182d4a4700ce]*/
|
||||
{
|
||||
pid_t pid;
|
||||
int async_err = 0;
|
||||
WAIT_TYPE status;
|
||||
WAIT_STATUS_INT(status) = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
pid = wait(&status);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (pid == -1)
|
||||
return posix_error();
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
pid = wait(&status);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (pid < 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status));
|
||||
}
|
||||
|
@ -10837,6 +10875,7 @@ os_open_impl(PyModuleDef *module, path_t *path, int flags, int mode, int dir_fd)
|
|||
/*[clinic end generated code: output=05b68fc4ed5e29c9 input=ad8623b29acd2934]*/
|
||||
{
|
||||
int fd;
|
||||
int async_err = 0;
|
||||
|
||||
#ifdef O_CLOEXEC
|
||||
int *atomic_flag_works = &_Py_open_cloexec_works;
|
||||
|
@ -10850,22 +10889,25 @@ os_open_impl(PyModuleDef *module, path_t *path, int flags, int mode, int dir_fd)
|
|||
flags |= O_CLOEXEC;
|
||||
#endif
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
#ifdef MS_WINDOWS
|
||||
if (path->wide)
|
||||
fd = _wopen(path->wide, flags, mode);
|
||||
else
|
||||
if (path->wide)
|
||||
fd = _wopen(path->wide, flags, mode);
|
||||
else
|
||||
#endif
|
||||
#ifdef HAVE_OPENAT
|
||||
if (dir_fd != DEFAULT_DIR_FD)
|
||||
fd = openat(dir_fd, path->narrow, flags, mode);
|
||||
else
|
||||
if (dir_fd != DEFAULT_DIR_FD)
|
||||
fd = openat(dir_fd, path->narrow, flags, mode);
|
||||
else
|
||||
#endif
|
||||
fd = open(path->narrow, flags, mode);
|
||||
Py_END_ALLOW_THREADS
|
||||
fd = open(path->narrow, flags, mode);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
if (fd == -1) {
|
||||
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
|
||||
if (!async_err)
|
||||
PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -10924,6 +10966,10 @@ os_close_impl(PyModuleDef *module, int fd)
|
|||
int res;
|
||||
if (!_PyVerify_fd(fd))
|
||||
return posix_error();
|
||||
/* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/
|
||||
* and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||
* for more details.
|
||||
*/
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = close(fd);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
@ -11089,6 +11135,10 @@ os_dup2_impl(PyModuleDef *module, int fd, int fd2, int inheritable)
|
|||
if (!_PyVerify_fd_dup2(fd, fd2))
|
||||
return posix_error();
|
||||
|
||||
/* dup2() can fail with EINTR if the target FD is already open, because it
|
||||
* then has to be closed. See os_close_impl() for why we don't handle EINTR
|
||||
* upon close(), and therefore below.
|
||||
*/
|
||||
#ifdef MS_WINDOWS
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = dup2(fd, fd2);
|
||||
|
@ -11355,6 +11405,7 @@ os_read_impl(PyModuleDef *module, int fd, Py_ssize_t length)
|
|||
/*[clinic end generated code: output=1f3bc27260a24968 input=1df2eaa27c0bf1d3]*/
|
||||
{
|
||||
Py_ssize_t n;
|
||||
int async_err = 0;
|
||||
PyObject *buffer;
|
||||
|
||||
if (length < 0) {
|
||||
|
@ -11375,13 +11426,16 @@ os_read_impl(PyModuleDef *module, int fd, Py_ssize_t length)
|
|||
buffer = PyBytes_FromStringAndSize((char *)NULL, length);
|
||||
if (buffer == NULL)
|
||||
return NULL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
n = read(fd, PyBytes_AS_STRING(buffer), READ_CAST length);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
n = read(fd, PyBytes_AS_STRING(buffer), READ_CAST length);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
if (n < 0) {
|
||||
Py_DECREF(buffer);
|
||||
return posix_error();
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
}
|
||||
|
||||
if (n != length)
|
||||
|
@ -11515,6 +11569,7 @@ os_readv_impl(PyModuleDef *module, int fd, PyObject *buffers)
|
|||
{
|
||||
int cnt;
|
||||
Py_ssize_t n;
|
||||
int async_err = 0;
|
||||
struct iovec *iov;
|
||||
Py_buffer *buf;
|
||||
|
||||
|
@ -11529,13 +11584,16 @@ os_readv_impl(PyModuleDef *module, int fd, PyObject *buffers)
|
|||
if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0)
|
||||
return -1;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
n = readv(fd, iov, cnt);
|
||||
Py_END_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
n = readv(fd, iov, cnt);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
iov_cleanup(iov, buf, cnt);
|
||||
if (n < 0) {
|
||||
posix_error();
|
||||
if (!async_err)
|
||||
posix_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -11598,6 +11656,7 @@ os_pread_impl(PyModuleDef *module, int fd, int length, Py_off_t offset)
|
|||
/*[clinic end generated code: output=7b62bf6c06e20ae8 input=084948dcbaa35d4c]*/
|
||||
{
|
||||
Py_ssize_t n;
|
||||
int async_err = 0;
|
||||
PyObject *buffer;
|
||||
|
||||
if (length < 0) {
|
||||
|
@ -11611,12 +11670,16 @@ os_pread_impl(PyModuleDef *module, int fd, int length, Py_off_t offset)
|
|||
Py_DECREF(buffer);
|
||||
return posix_error();
|
||||
}
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
n = pread(fd, PyBytes_AS_STRING(buffer), length, offset);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
n = pread(fd, PyBytes_AS_STRING(buffer), length, offset);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
if (n < 0) {
|
||||
Py_DECREF(buffer);
|
||||
return posix_error();
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
}
|
||||
if (n != length)
|
||||
_PyBytes_Resize(&buffer, n);
|
||||
|
@ -11677,6 +11740,7 @@ os_write_impl(PyModuleDef *module, int fd, Py_buffer *data)
|
|||
/*[clinic end generated code: output=aeb96acfdd4d5112 input=3207e28963234f3c]*/
|
||||
{
|
||||
Py_ssize_t size;
|
||||
int async_err = 0;
|
||||
Py_ssize_t len = data->len;
|
||||
|
||||
if (!_PyVerify_fd(fd)) {
|
||||
|
@ -11684,17 +11748,21 @@ os_write_impl(PyModuleDef *module, int fd, Py_buffer *data)
|
|||
return -1;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
#ifdef MS_WINDOWS
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
size = write(fd, data->buf, (int)len);
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
size = write(fd, data->buf, (int)len);
|
||||
#else
|
||||
size = write(fd, data->buf, len);
|
||||
size = write(fd, data->buf, len);
|
||||
#endif
|
||||
Py_END_ALLOW_THREADS
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
if (size < 0) {
|
||||
posix_error();
|
||||
if (!async_err)
|
||||
posix_error();
|
||||
return -1;
|
||||
}
|
||||
return size;
|
||||
|
@ -11713,6 +11781,7 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
|
|||
{
|
||||
int in, out;
|
||||
Py_ssize_t ret;
|
||||
int async_err = 0;
|
||||
off_t offset;
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__)
|
||||
|
@ -11775,13 +11844,15 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
|
|||
}
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
#ifdef __APPLE__
|
||||
ret = sendfile(in, out, offset, &sbytes, &sf, flags);
|
||||
ret = sendfile(in, out, offset, &sbytes, &sf, flags);
|
||||
#else
|
||||
ret = sendfile(in, out, offset, len, &sf, &sbytes, flags);
|
||||
ret = sendfile(in, out, offset, len, &sf, &sbytes, flags);
|
||||
#endif
|
||||
Py_END_ALLOW_THREADS
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
if (sf.headers != NULL)
|
||||
iov_cleanup(sf.headers, hbuf, sf.hdr_cnt);
|
||||
|
@ -11800,7 +11871,7 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict)
|
|||
return posix_error();
|
||||
}
|
||||
}
|
||||
return posix_error();
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
}
|
||||
goto done;
|
||||
|
||||
|
@ -11821,21 +11892,26 @@ done:
|
|||
return NULL;
|
||||
#ifdef linux
|
||||
if (offobj == Py_None) {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = sendfile(out, in, NULL, count);
|
||||
Py_END_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = sendfile(out, in, NULL, count);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (ret < 0)
|
||||
return posix_error();
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
return Py_BuildValue("n", ret);
|
||||
}
|
||||
#endif
|
||||
if (!Py_off_t_converter(offobj, &offset))
|
||||
return NULL;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = sendfile(out, in, &offset, count);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
ret = sendfile(out, in, &offset, count);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (ret < 0)
|
||||
return posix_error();
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
return Py_BuildValue("n", ret);
|
||||
#endif
|
||||
}
|
||||
|
@ -11891,15 +11967,18 @@ os_fstat_impl(PyModuleDef *module, int fd)
|
|||
{
|
||||
STRUCT_STAT st;
|
||||
int res;
|
||||
int async_err = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = FSTAT(fd, &st);
|
||||
Py_END_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
res = FSTAT(fd, &st);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (res != 0) {
|
||||
#ifdef MS_WINDOWS
|
||||
return PyErr_SetFromWindowsErr(0);
|
||||
#else
|
||||
return posix_error();
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -12185,6 +12264,7 @@ os_writev_impl(PyModuleDef *module, int fd, PyObject *buffers)
|
|||
{
|
||||
int cnt;
|
||||
Py_ssize_t result;
|
||||
int async_err = 0;
|
||||
struct iovec *iov;
|
||||
Py_buffer *buf;
|
||||
|
||||
|
@ -12199,12 +12279,14 @@ os_writev_impl(PyModuleDef *module, int fd, PyObject *buffers)
|
|||
return -1;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = writev(fd, iov, cnt);
|
||||
Py_END_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = writev(fd, iov, cnt);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
iov_cleanup(iov, buf, cnt);
|
||||
if (result < 0)
|
||||
if (result < 0 && !async_err)
|
||||
posix_error();
|
||||
|
||||
return result;
|
||||
|
@ -12275,17 +12357,20 @@ os_pwrite_impl(PyModuleDef *module, int fd, Py_buffer *buffer, Py_off_t offset)
|
|||
/*[clinic end generated code: output=ec9cc5b2238e96a7 input=19903f1b3dd26377]*/
|
||||
{
|
||||
Py_ssize_t size;
|
||||
int async_err = 0;
|
||||
|
||||
if (!_PyVerify_fd(fd)) {
|
||||
posix_error();
|
||||
return -1;
|
||||
}
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset);
|
||||
Py_END_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
if (size < 0)
|
||||
if (size < 0 && !async_err)
|
||||
posix_error();
|
||||
return size;
|
||||
}
|
||||
|
@ -12353,18 +12438,21 @@ os_mkfifo_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd)
|
|||
/*[clinic end generated code: output=b3321927546893d0 input=73032e98a36e0e19]*/
|
||||
{
|
||||
int result;
|
||||
int async_err = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
#ifdef HAVE_MKFIFOAT
|
||||
if (dir_fd != DEFAULT_DIR_FD)
|
||||
result = mkfifoat(dir_fd, path->narrow, mode);
|
||||
else
|
||||
if (dir_fd != DEFAULT_DIR_FD)
|
||||
result = mkfifoat(dir_fd, path->narrow, mode);
|
||||
else
|
||||
#endif
|
||||
result = mkfifo(path->narrow, mode);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (result < 0)
|
||||
return posix_error();
|
||||
result = mkfifo(path->narrow, mode);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (result != 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
if (result != 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
@ -12448,18 +12536,21 @@ os_mknod_impl(PyModuleDef *module, path_t *path, int mode, dev_t device, int dir
|
|||
/*[clinic end generated code: output=f71d54eaf9bb6f1a input=ee44531551a4d83b]*/
|
||||
{
|
||||
int result;
|
||||
int async_err = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
#ifdef HAVE_MKNODAT
|
||||
if (dir_fd != DEFAULT_DIR_FD)
|
||||
result = mknodat(dir_fd, path->narrow, mode, device);
|
||||
else
|
||||
if (dir_fd != DEFAULT_DIR_FD)
|
||||
result = mknodat(dir_fd, path->narrow, mode, device);
|
||||
else
|
||||
#endif
|
||||
result = mknod(path->narrow, mode, device);
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
if (result < 0)
|
||||
return posix_error();
|
||||
result = mknod(path->narrow, mode, device);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (result != 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
if (result != 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
|
@ -12662,12 +12753,16 @@ os_ftruncate_impl(PyModuleDef *module, int fd, Py_off_t length)
|
|||
/*[clinic end generated code: output=62326766cb9b76bf input=63b43641e52818f2]*/
|
||||
{
|
||||
int result;
|
||||
int async_err = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = ftruncate(fd, length);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (result < 0)
|
||||
return posix_error();
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = ftruncate(fd, length);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (result != 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
if (result != 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif /* HAVE_FTRUNCATE */
|
||||
|
@ -12805,14 +12900,16 @@ os_posix_fallocate_impl(PyModuleDef *module, int fd, Py_off_t offset, Py_off_t l
|
|||
/*[clinic end generated code: output=0cd702d2065c79db input=d7a2ef0ab2ca52fb]*/
|
||||
{
|
||||
int result;
|
||||
int async_err = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = posix_fallocate(fd, offset, length);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (result != 0) {
|
||||
errno = result;
|
||||
return posix_error();
|
||||
}
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = posix_fallocate(fd, offset, length);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (result != 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
if (result != 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif /* HAVE_POSIX_FALLOCATE) && !POSIX_FADVISE_AIX_BUG */
|
||||
|
@ -12883,14 +12980,16 @@ os_posix_fadvise_impl(PyModuleDef *module, int fd, Py_off_t offset, Py_off_t len
|
|||
/*[clinic end generated code: output=dad93f32c04dd4f7 input=0fbe554edc2f04b5]*/
|
||||
{
|
||||
int result;
|
||||
int async_err = 0;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = posix_fadvise(fd, offset, length, advice);
|
||||
Py_END_ALLOW_THREADS
|
||||
if (result != 0) {
|
||||
errno = result;
|
||||
return posix_error();
|
||||
}
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = posix_fadvise(fd, offset, length, advice);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (result != 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
if (result != 0)
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
Py_RETURN_NONE;
|
||||
}
|
||||
#endif /* HAVE_POSIX_FADVISE && !POSIX_FADVISE_AIX_BUG */
|
||||
|
@ -13745,13 +13844,17 @@ os_fstatvfs_impl(PyModuleDef *module, int fd)
|
|||
/*[clinic end generated code: output=0e32bf07f946ec0d input=d8122243ac50975e]*/
|
||||
{
|
||||
int result;
|
||||
int async_err = 0;
|
||||
struct statvfs st;
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = fstatvfs(fd, &st);
|
||||
Py_END_ALLOW_THREADS
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
result = fstatvfs(fd, &st);
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (result != 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
if (result != 0)
|
||||
return posix_error();
|
||||
return (!async_err) ? posix_error() : NULL;
|
||||
|
||||
return _pystatvfs_fromstructstatvfs(st);
|
||||
}
|
||||
|
|
|
@ -2037,6 +2037,7 @@ sock_accept(PySocketSockObject *s)
|
|||
PyObject *addr = NULL;
|
||||
PyObject *res = NULL;
|
||||
int timeout;
|
||||
int async_err = 0;
|
||||
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
|
||||
/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
|
||||
static int accept4_works = -1;
|
||||
|
@ -2050,27 +2051,27 @@ sock_accept(PySocketSockObject *s)
|
|||
return select_error();
|
||||
|
||||
BEGIN_SELECT_LOOP(s)
|
||||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select_ex(s, 0, interval);
|
||||
if (!timeout) {
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select_ex(s, 0, interval);
|
||||
if (!timeout) {
|
||||
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
|
||||
if (accept4_works != 0) {
|
||||
newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen,
|
||||
SOCK_CLOEXEC);
|
||||
if (newfd == INVALID_SOCKET && accept4_works == -1) {
|
||||
/* On Linux older than 2.6.28, accept4() fails with ENOSYS */
|
||||
accept4_works = (errno != ENOSYS);
|
||||
if (accept4_works != 0) {
|
||||
newfd = accept4(s->sock_fd, SAS2SA(&addrbuf), &addrlen,
|
||||
SOCK_CLOEXEC);
|
||||
if (newfd == INVALID_SOCKET && accept4_works == -1) {
|
||||
/* On Linux older than 2.6.28, accept4() fails with ENOSYS */
|
||||
accept4_works = (errno != ENOSYS);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (accept4_works == 0)
|
||||
newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
|
||||
if (accept4_works == 0)
|
||||
newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
|
||||
#else
|
||||
newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
|
||||
newfd = accept(s->sock_fd, SAS2SA(&addrbuf), &addrlen);
|
||||
#endif
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (newfd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (timeout == 1) {
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
return NULL;
|
||||
|
@ -2078,7 +2079,7 @@ sock_accept(PySocketSockObject *s)
|
|||
END_SELECT_LOOP(s)
|
||||
|
||||
if (newfd == INVALID_SOCKET)
|
||||
return s->errorhandler();
|
||||
return (!async_err) ? s->errorhandler() : NULL;
|
||||
|
||||
#ifdef MS_WINDOWS
|
||||
if (!SetHandleInformation((HANDLE)newfd, HANDLE_FLAG_INHERIT, 0)) {
|
||||
|
@ -2341,6 +2342,10 @@ sock_close(PySocketSockObject *s)
|
|||
{
|
||||
SOCKET_T fd;
|
||||
|
||||
/* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/
|
||||
* and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html
|
||||
* for more details.
|
||||
*/
|
||||
if ((fd = s->sock_fd) != -1) {
|
||||
s->sock_fd = -1;
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
|
@ -2513,10 +2518,8 @@ sock_connect_ex(PySocketSockObject *s, PyObject *addro)
|
|||
|
||||
/* Signals are not errors (though they may raise exceptions). Adapted
|
||||
from PyErr_SetFromErrnoWithFilenameObject(). */
|
||||
#ifdef EINTR
|
||||
if (res == EINTR && PyErr_CheckSignals())
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
return PyLong_FromLong((long) res);
|
||||
}
|
||||
|
@ -2650,6 +2653,7 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
|
|||
{
|
||||
Py_ssize_t outlen = -1;
|
||||
int timeout;
|
||||
int async_err = 0;
|
||||
|
||||
if (!IS_SELECTABLE(s)) {
|
||||
select_error();
|
||||
|
@ -2661,18 +2665,20 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
|
|||
}
|
||||
|
||||
BEGIN_SELECT_LOOP(s)
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select_ex(s, 0, interval);
|
||||
if (!timeout) {
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select_ex(s, 0, interval);
|
||||
if (!timeout) {
|
||||
#ifdef MS_WINDOWS
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
outlen = recv(s->sock_fd, cbuf, (int)len, flags);
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
outlen = recv(s->sock_fd, cbuf, (int)len, flags);
|
||||
#else
|
||||
outlen = recv(s->sock_fd, cbuf, len, flags);
|
||||
outlen = recv(s->sock_fd, cbuf, len, flags);
|
||||
#endif
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (outlen < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
if (timeout == 1) {
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
|
@ -2682,7 +2688,8 @@ sock_recv_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags)
|
|||
if (outlen < 0) {
|
||||
/* Note: the call to errorhandler() ALWAYS indirectly returned
|
||||
NULL, so ignore its return value */
|
||||
s->errorhandler();
|
||||
if (!async_err)
|
||||
s->errorhandler();
|
||||
return -1;
|
||||
}
|
||||
return outlen;
|
||||
|
@ -2819,6 +2826,7 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
|
|||
int timeout;
|
||||
Py_ssize_t n = -1;
|
||||
socklen_t addrlen;
|
||||
int async_err = 0;
|
||||
|
||||
*addr = NULL;
|
||||
|
||||
|
@ -2831,21 +2839,23 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
|
|||
}
|
||||
|
||||
BEGIN_SELECT_LOOP(s)
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
memset(&addrbuf, 0, addrlen);
|
||||
timeout = internal_select_ex(s, 0, interval);
|
||||
if (!timeout) {
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
memset(&addrbuf, 0, addrlen);
|
||||
timeout = internal_select_ex(s, 0, interval);
|
||||
if (!timeout) {
|
||||
#ifdef MS_WINDOWS
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = recvfrom(s->sock_fd, cbuf, (int)len, flags,
|
||||
(void *) &addrbuf, &addrlen);
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = recvfrom(s->sock_fd, cbuf, (int)len, flags,
|
||||
(void *) &addrbuf, &addrlen);
|
||||
#else
|
||||
n = recvfrom(s->sock_fd, cbuf, len, flags,
|
||||
SAS2SA(&addrbuf), &addrlen);
|
||||
n = recvfrom(s->sock_fd, cbuf, len, flags,
|
||||
SAS2SA(&addrbuf), &addrlen);
|
||||
#endif
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
if (timeout == 1) {
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
|
@ -2853,7 +2863,8 @@ sock_recvfrom_guts(PySocketSockObject *s, char* cbuf, Py_ssize_t len, int flags,
|
|||
}
|
||||
END_SELECT_LOOP(s)
|
||||
if (n < 0) {
|
||||
s->errorhandler();
|
||||
if (!async_err)
|
||||
s->errorhandler();
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -2993,6 +3004,7 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
|
|||
{
|
||||
ssize_t bytes_received = -1;
|
||||
int timeout;
|
||||
int async_err = 0;
|
||||
sock_addr_t addrbuf;
|
||||
socklen_t addrbuflen;
|
||||
struct msghdr msg = {0};
|
||||
|
@ -3028,25 +3040,29 @@ sock_recvmsg_guts(PySocketSockObject *s, struct iovec *iov, int iovlen,
|
|||
}
|
||||
|
||||
BEGIN_SELECT_LOOP(s)
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
msg.msg_name = SAS2SA(&addrbuf);
|
||||
msg.msg_namelen = addrbuflen;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = iovlen;
|
||||
msg.msg_control = controlbuf;
|
||||
msg.msg_controllen = controllen;
|
||||
timeout = internal_select_ex(s, 0, interval);
|
||||
if (!timeout)
|
||||
bytes_received = recvmsg(s->sock_fd, &msg, flags);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (timeout == 1) {
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
goto finally;
|
||||
}
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
msg.msg_name = SAS2SA(&addrbuf);
|
||||
msg.msg_namelen = addrbuflen;
|
||||
msg.msg_iov = iov;
|
||||
msg.msg_iovlen = iovlen;
|
||||
msg.msg_control = controlbuf;
|
||||
msg.msg_controllen = controllen;
|
||||
timeout = internal_select_ex(s, 0, interval);
|
||||
if (!timeout)
|
||||
bytes_received = recvmsg(s->sock_fd, &msg, flags);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (timeout == 1) {
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
goto finally;
|
||||
}
|
||||
} while (bytes_received < 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
END_SELECT_LOOP(s)
|
||||
|
||||
if (bytes_received < 0) {
|
||||
s->errorhandler();
|
||||
if (!async_err)
|
||||
s->errorhandler();
|
||||
goto finally;
|
||||
}
|
||||
|
||||
|
@ -3305,6 +3321,7 @@ sock_send(PySocketSockObject *s, PyObject *args)
|
|||
{
|
||||
char *buf;
|
||||
Py_ssize_t len, n = -1;
|
||||
int async_err = 0;
|
||||
int flags = 0, timeout;
|
||||
Py_buffer pbuf;
|
||||
|
||||
|
@ -3319,18 +3336,20 @@ sock_send(PySocketSockObject *s, PyObject *args)
|
|||
len = pbuf.len;
|
||||
|
||||
BEGIN_SELECT_LOOP(s)
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select_ex(s, 1, interval);
|
||||
if (!timeout) {
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select_ex(s, 1, interval);
|
||||
if (!timeout) {
|
||||
#ifdef MS_WINDOWS
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = send(s->sock_fd, buf, (int)len, flags);
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = send(s->sock_fd, buf, (int)len, flags);
|
||||
#else
|
||||
n = send(s->sock_fd, buf, len, flags);
|
||||
n = send(s->sock_fd, buf, len, flags);
|
||||
#endif
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
if (timeout == 1) {
|
||||
PyBuffer_Release(&pbuf);
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
|
@ -3340,7 +3359,7 @@ sock_send(PySocketSockObject *s, PyObject *args)
|
|||
|
||||
PyBuffer_Release(&pbuf);
|
||||
if (n < 0)
|
||||
return s->errorhandler();
|
||||
return (!async_err) ? s->errorhandler() : NULL;
|
||||
return PyLong_FromSsize_t(n);
|
||||
}
|
||||
|
||||
|
@ -3359,7 +3378,8 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
|
|||
{
|
||||
char *buf;
|
||||
Py_ssize_t len, n = -1;
|
||||
int flags = 0, timeout, saved_errno;
|
||||
int async_err = 0;
|
||||
int flags = 0, timeout;
|
||||
Py_buffer pbuf;
|
||||
|
||||
if (!PyArg_ParseTuple(args, "y*|i:sendall", &pbuf, &flags))
|
||||
|
@ -3391,29 +3411,16 @@ sock_sendall(PySocketSockObject *s, PyObject *args)
|
|||
PyErr_SetString(socket_timeout, "timed out");
|
||||
return NULL;
|
||||
}
|
||||
/* PyErr_CheckSignals() might change errno */
|
||||
saved_errno = errno;
|
||||
/* We must run our signal handlers before looping again.
|
||||
send() can return a successful partial write when it is
|
||||
interrupted, so we can't restrict ourselves to EINTR. */
|
||||
if (PyErr_CheckSignals()) {
|
||||
PyBuffer_Release(&pbuf);
|
||||
return NULL;
|
||||
if (n >= 0) {
|
||||
buf += n;
|
||||
len -= n;
|
||||
}
|
||||
if (n < 0) {
|
||||
/* If interrupted, try again */
|
||||
if (saved_errno == EINTR)
|
||||
continue;
|
||||
else
|
||||
break;
|
||||
}
|
||||
buf += n;
|
||||
len -= n;
|
||||
} while (len > 0);
|
||||
} while (len > 0 && (n >= 0 || errno == EINTR) &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
PyBuffer_Release(&pbuf);
|
||||
|
||||
if (n < 0)
|
||||
return s->errorhandler();
|
||||
if (n < 0 || async_err)
|
||||
return (!async_err) ? s->errorhandler() : NULL;
|
||||
|
||||
Py_INCREF(Py_None);
|
||||
return Py_None;
|
||||
|
@ -3439,6 +3446,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
|
|||
Py_ssize_t len, arglen;
|
||||
sock_addr_t addrbuf;
|
||||
int addrlen, n = -1, flags, timeout;
|
||||
int async_err = 0;
|
||||
|
||||
flags = 0;
|
||||
arglen = PyTuple_Size(args);
|
||||
|
@ -3473,20 +3481,22 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
|
|||
}
|
||||
|
||||
BEGIN_SELECT_LOOP(s)
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select_ex(s, 1, interval);
|
||||
if (!timeout) {
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
timeout = internal_select_ex(s, 1, interval);
|
||||
if (!timeout) {
|
||||
#ifdef MS_WINDOWS
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = sendto(s->sock_fd, buf, (int)len, flags,
|
||||
SAS2SA(&addrbuf), addrlen);
|
||||
if (len > INT_MAX)
|
||||
len = INT_MAX;
|
||||
n = sendto(s->sock_fd, buf, (int)len, flags,
|
||||
SAS2SA(&addrbuf), addrlen);
|
||||
#else
|
||||
n = sendto(s->sock_fd, buf, len, flags,
|
||||
SAS2SA(&addrbuf), addrlen);
|
||||
n = sendto(s->sock_fd, buf, len, flags,
|
||||
SAS2SA(&addrbuf), addrlen);
|
||||
#endif
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
}
|
||||
Py_END_ALLOW_THREADS
|
||||
} while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals()));
|
||||
|
||||
if (timeout == 1) {
|
||||
PyBuffer_Release(&pbuf);
|
||||
|
@ -3496,7 +3506,7 @@ sock_sendto(PySocketSockObject *s, PyObject *args)
|
|||
END_SELECT_LOOP(s)
|
||||
PyBuffer_Release(&pbuf);
|
||||
if (n < 0)
|
||||
return s->errorhandler();
|
||||
return (!async_err) ? s->errorhandler() : NULL;
|
||||
return PyLong_FromSsize_t(n);
|
||||
}
|
||||
|
||||
|
@ -3528,6 +3538,7 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
|
|||
void *controlbuf = NULL;
|
||||
size_t controllen, controllen_last;
|
||||
ssize_t bytes_sent = -1;
|
||||
int async_err = 0;
|
||||
int addrlen, timeout, flags = 0;
|
||||
PyObject *data_arg, *cmsg_arg = NULL, *addr_arg = NULL, *data_fast = NULL,
|
||||
*cmsg_fast = NULL, *retval = NULL;
|
||||
|
@ -3685,19 +3696,23 @@ sock_sendmsg(PySocketSockObject *s, PyObject *args)
|
|||
}
|
||||
|
||||
BEGIN_SELECT_LOOP(s)
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
timeout = internal_select_ex(s, 1, interval);
|
||||
if (!timeout)
|
||||
bytes_sent = sendmsg(s->sock_fd, &msg, flags);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (timeout == 1) {
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
goto finally;
|
||||
}
|
||||
do {
|
||||
Py_BEGIN_ALLOW_THREADS;
|
||||
timeout = internal_select_ex(s, 1, interval);
|
||||
if (!timeout)
|
||||
bytes_sent = sendmsg(s->sock_fd, &msg, flags);
|
||||
Py_END_ALLOW_THREADS;
|
||||
if (timeout == 1) {
|
||||
PyErr_SetString(socket_timeout, "timed out");
|
||||
goto finally;
|
||||
}
|
||||
} while (bytes_sent < 0 && errno == EINTR &&
|
||||
!(async_err = PyErr_CheckSignals()));
|
||||
END_SELECT_LOOP(s)
|
||||
|
||||
if (bytes_sent < 0) {
|
||||
s->errorhandler();
|
||||
if (!async_err)
|
||||
s->errorhandler();
|
||||
goto finally;
|
||||
}
|
||||
retval = PyLong_FromSsize_t(bytes_sent);
|
||||
|
|
Loading…
Reference in New Issue