summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregory P. Smith <greg@mad-scientist.com>2010-01-04 04:50:36 (GMT)
committerGregory P. Smith <greg@mad-scientist.com>2010-01-04 04:50:36 (GMT)
commitaafdca895b5384455de662f89955f240daaa8caf (patch)
treeaa4290d54b444398f555a0dd141326031deaa77d
parent960737de5932f91bd901d00d898337b6dc479236 (diff)
downloadcpython-aafdca895b5384455de662f89955f240daaa8caf.zip
cpython-aafdca895b5384455de662f89955f240daaa8caf.tar.gz
cpython-aafdca895b5384455de662f89955f240daaa8caf.tar.bz2
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. ........
-rw-r--r--Lib/socket.py14
-rw-r--r--Lib/test/test_socket.py113
-rw-r--r--Misc/NEWS4
3 files changed, 128 insertions, 3 deletions
diff --git a/Lib/socket.py b/Lib/socket.py
index 9133411..a82e48d 100644
--- a/Lib/socket.py
+++ b/Lib/socket.py
@@ -49,9 +49,11 @@ from _socket import *
import os, sys, io
try:
- from errno import EBADF
+ import errno
except ImportError:
- EBADF = 9
+ errno = None
+EBADF = getattr(errno, 'EBADF', 9)
+EINTR = getattr(errno, 'EINTR', 4)
__all__ = ["getfqdn", "create_connection"]
__all__.extend(os._get_exports_list(_socket))
@@ -212,7 +214,13 @@ class SocketIO(io.RawIOBase):
def readinto(self, b):
self._checkClosed()
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):
self._checkClosed()
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 09e2cc8..4326e65 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -4,6 +4,7 @@ import unittest
from test import support
import errno
+import io
import socket
import select
import _thread as thread
@@ -906,6 +907,117 @@ 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 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):
"""Repeat the tests from FileObjectClassTestCase with bufsize==0.
@@ -1310,6 +1422,7 @@ def test_main():
tests.extend([
NonBlockingTCPTests,
FileObjectClassTestCase,
+ FileObjectInterruptedTestCase,
UnbufferedFileObjectClassTestCase,
LineBufferedFileObjectClassTestCase,
SmallBufferedFileObjectClassTestCase,
diff --git a/Misc/NEWS b/Misc/NEWS
index 1f29728..c78c960 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -194,6 +194,10 @@ C-API
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,
and make it implement the `io.BufferedIOBase` ABC to allow for further
speedups by wrapping it in an `io.BufferedReader`. Patch by Nir Aides.