mirror of
https://github.com/python/cpython.git
synced 2025-09-26 10:19:53 +00:00
Merged revisions 74426 via svnmerge from
svn+ssh://pythondev@svn.python.org/python/trunk ........ r74426 | gregory.p.smith | 2009-08-13 11:54:50 -0700 (Thu, 13 Aug 2009) | 4 lines Fix issue1628205: Socket file objects returned by socket.socket.makefile() now properly handles EINTR within the read, readline, write & flush methods. The socket.sendall() method now properly handles interrupted system calls. ........
This commit is contained in:
parent
960737de59
commit
aafdca895b
3 changed files with 128 additions and 3 deletions
|
@ -49,9 +49,11 @@ from _socket import *
|
||||||
import os, sys, io
|
import os, sys, io
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from errno import EBADF
|
import errno
|
||||||
except ImportError:
|
except ImportError:
|
||||||
EBADF = 9
|
errno = None
|
||||||
|
EBADF = getattr(errno, 'EBADF', 9)
|
||||||
|
EINTR = getattr(errno, 'EINTR', 4)
|
||||||
|
|
||||||
__all__ = ["getfqdn", "create_connection"]
|
__all__ = ["getfqdn", "create_connection"]
|
||||||
__all__.extend(os._get_exports_list(_socket))
|
__all__.extend(os._get_exports_list(_socket))
|
||||||
|
@ -212,7 +214,13 @@ class SocketIO(io.RawIOBase):
|
||||||
def readinto(self, b):
|
def readinto(self, b):
|
||||||
self._checkClosed()
|
self._checkClosed()
|
||||||
self._checkReadable()
|
self._checkReadable()
|
||||||
return self._sock.recv_into(b)
|
while True:
|
||||||
|
try:
|
||||||
|
return self._sock.recv_into(b)
|
||||||
|
except error as e:
|
||||||
|
if e.args[0] == EINTR:
|
||||||
|
continue
|
||||||
|
raise
|
||||||
|
|
||||||
def write(self, b):
|
def write(self, b):
|
||||||
self._checkClosed()
|
self._checkClosed()
|
||||||
|
|
|
@ -4,6 +4,7 @@ import unittest
|
||||||
from test import support
|
from test import support
|
||||||
|
|
||||||
import errno
|
import errno
|
||||||
|
import io
|
||||||
import socket
|
import socket
|
||||||
import select
|
import select
|
||||||
import _thread as thread
|
import _thread as thread
|
||||||
|
@ -906,6 +907,117 @@ class FileObjectClassTestCase(SocketConnectedTest):
|
||||||
pass
|
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 socket.error(errno.EINTR)
|
||||||
|
|
||||||
|
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.assertEquals(fo.readline(size), "This is the first line\n")
|
||||||
|
self.assertEquals(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('utf8')
|
||||||
|
while len(data) != len(expecting):
|
||||||
|
part = fo.read(size)
|
||||||
|
if not part:
|
||||||
|
break
|
||||||
|
data += part
|
||||||
|
self.assertEquals(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.assertEquals(fo.readline(size), b"a\n")
|
||||||
|
self.assertEquals(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):
|
class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase):
|
||||||
|
|
||||||
"""Repeat the tests from FileObjectClassTestCase with bufsize==0.
|
"""Repeat the tests from FileObjectClassTestCase with bufsize==0.
|
||||||
|
@ -1310,6 +1422,7 @@ def test_main():
|
||||||
tests.extend([
|
tests.extend([
|
||||||
NonBlockingTCPTests,
|
NonBlockingTCPTests,
|
||||||
FileObjectClassTestCase,
|
FileObjectClassTestCase,
|
||||||
|
FileObjectInterruptedTestCase,
|
||||||
UnbufferedFileObjectClassTestCase,
|
UnbufferedFileObjectClassTestCase,
|
||||||
LineBufferedFileObjectClassTestCase,
|
LineBufferedFileObjectClassTestCase,
|
||||||
SmallBufferedFileObjectClassTestCase,
|
SmallBufferedFileObjectClassTestCase,
|
||||||
|
|
|
@ -194,6 +194,10 @@ C-API
|
||||||
Library
|
Library
|
||||||
-------
|
-------
|
||||||
|
|
||||||
|
- Issue #1628205: Socket file objects returned by socket.socket.makefile() now
|
||||||
|
properly handles EINTR within the read, readline, write & flush methods.
|
||||||
|
The socket.sendall() method now properly handles interrupted system calls.
|
||||||
|
|
||||||
- Issue #7471: Improve the performance of GzipFile's buffering mechanism,
|
- Issue #7471: Improve the performance of GzipFile's buffering mechanism,
|
||||||
and make it implement the `io.BufferedIOBase` ABC to allow for further
|
and make it implement the `io.BufferedIOBase` ABC to allow for further
|
||||||
speedups by wrapping it in an `io.BufferedReader`. Patch by Nir Aides.
|
speedups by wrapping it in an `io.BufferedReader`. Patch by Nir Aides.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue