Issue #23285: PEP 475 -- Retry system calls failing with EINTR.

This commit is contained in:
Charles-François Natali 2015-02-07 13:27:50 +00:00
parent d005090e01
commit 6e6c59b508
18 changed files with 753 additions and 522 deletions

View File

@ -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

View File

@ -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")

View File

@ -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(

View File

@ -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())

View File

@ -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:]

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

20
Lib/test/test_eintr.py Normal file
View File

@ -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()

View File

@ -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)

View File

@ -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,

View File

@ -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,
)

View File

@ -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.

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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);