Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit aafdca8

Browse files
committed
Merged revisions 74426 via svnmerge from
svn+ssh://[email protected]/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. ........
1 parent 960737d commit aafdca8

3 files changed

Lines changed: 128 additions & 3 deletions

File tree

Lib/socket.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@
4949
import os, sys, io
5050

5151
try:
52-
from errno import EBADF
52+
import errno
5353
except ImportError:
54-
EBADF = 9
54+
errno = None
55+
EBADF = getattr(errno, 'EBADF', 9)
56+
EINTR = getattr(errno, 'EINTR', 4)
5557

5658
__all__ = ["getfqdn", "create_connection"]
5759
__all__.extend(os._get_exports_list(_socket))
@@ -212,7 +214,13 @@ def __init__(self, sock, mode):
212214
def readinto(self, b):
213215
self._checkClosed()
214216
self._checkReadable()
215-
return self._sock.recv_into(b)
217+
while True:
218+
try:
219+
return self._sock.recv_into(b)
220+
except error as e:
221+
if e.args[0] == EINTR:
222+
continue
223+
raise
216224

217225
def write(self, b):
218226
self._checkClosed()

Lib/test/test_socket.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
from test import support
55

66
import errno
7+
import io
78
import socket
89
import select
910
import _thread as thread
@@ -906,6 +907,117 @@ def _testRealClose(self):
906907
pass
907908

908909

910+
class FileObjectInterruptedTestCase(unittest.TestCase):
911+
"""Test that the file object correctly handles EINTR internally."""
912+
913+
class MockSocket(object):
914+
def __init__(self, recv_funcs=()):
915+
# A generator that returns callables that we'll call for each
916+
# call to recv().
917+
self._recv_step = iter(recv_funcs)
918+
919+
def recv_into(self, buffer):
920+
data = next(self._recv_step)()
921+
assert len(buffer) >= len(data)
922+
buffer[:len(data)] = data
923+
return len(data)
924+
925+
def _decref_socketios(self):
926+
pass
927+
928+
def _textiowrap_for_test(self, buffering=-1):
929+
raw = socket.SocketIO(self, "r")
930+
if buffering < 0:
931+
buffering = io.DEFAULT_BUFFER_SIZE
932+
if buffering == 0:
933+
return raw
934+
buffer = io.BufferedReader(raw, buffering)
935+
text = io.TextIOWrapper(buffer, None, None)
936+
text.mode = "rb"
937+
return text
938+
939+
@staticmethod
940+
def _raise_eintr():
941+
raise socket.error(errno.EINTR)
942+
943+
def _textiowrap_mock_socket(self, mock, buffering=-1):
944+
raw = socket.SocketIO(mock, "r")
945+
if buffering < 0:
946+
buffering = io.DEFAULT_BUFFER_SIZE
947+
if buffering == 0:
948+
return raw
949+
buffer = io.BufferedReader(raw, buffering)
950+
text = io.TextIOWrapper(buffer, None, None)
951+
text.mode = "rb"
952+
return text
953+
954+
def _test_readline(self, size=-1, buffering=-1):
955+
mock_sock = self.MockSocket(recv_funcs=[
956+
lambda : b"This is the first line\nAnd the sec",
957+
self._raise_eintr,
958+
lambda : b"ond line is here\n",
959+
lambda : b"",
960+
lambda : b"", # XXX(gps): io library does an extra EOF read
961+
])
962+
fo = mock_sock._textiowrap_for_test(buffering=buffering)
963+
self.assertEquals(fo.readline(size), "This is the first line\n")
964+
self.assertEquals(fo.readline(size), "And the second line is here\n")
965+
966+
def _test_read(self, size=-1, buffering=-1):
967+
mock_sock = self.MockSocket(recv_funcs=[
968+
lambda : b"This is the first line\nAnd the sec",
969+
self._raise_eintr,
970+
lambda : b"ond line is here\n",
971+
lambda : b"",
972+
lambda : b"", # XXX(gps): io library does an extra EOF read
973+
])
974+
expecting = (b"This is the first line\n"
975+
b"And the second line is here\n")
976+
fo = mock_sock._textiowrap_for_test(buffering=buffering)
977+
if buffering == 0:
978+
data = b''
979+
else:
980+
data = ''
981+
expecting = expecting.decode('utf8')
982+
while len(data) != len(expecting):
983+
part = fo.read(size)
984+
if not part:
985+
break
986+
data += part
987+
self.assertEquals(data, expecting)
988+
989+
def test_default(self):
990+
self._test_readline()
991+
self._test_readline(size=100)
992+
self._test_read()
993+
self._test_read(size=100)
994+
995+
def test_with_1k_buffer(self):
996+
self._test_readline(buffering=1024)
997+
self._test_readline(size=100, buffering=1024)
998+
self._test_read(buffering=1024)
999+
self._test_read(size=100, buffering=1024)
1000+
1001+
def _test_readline_no_buffer(self, size=-1):
1002+
mock_sock = self.MockSocket(recv_funcs=[
1003+
lambda : b"a",
1004+
lambda : b"\n",
1005+
lambda : b"B",
1006+
self._raise_eintr,
1007+
lambda : b"b",
1008+
lambda : b"",
1009+
])
1010+
fo = mock_sock._textiowrap_for_test(buffering=0)
1011+
self.assertEquals(fo.readline(size), b"a\n")
1012+
self.assertEquals(fo.readline(size), b"Bb")
1013+
1014+
def test_no_buffer(self):
1015+
self._test_readline_no_buffer()
1016+
self._test_readline_no_buffer(size=4)
1017+
self._test_read(buffering=0)
1018+
self._test_read(size=100, buffering=0)
1019+
1020+
9091021
class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase):
9101022

9111023
"""Repeat the tests from FileObjectClassTestCase with bufsize==0.
@@ -1310,6 +1422,7 @@ def test_main():
13101422
tests.extend([
13111423
NonBlockingTCPTests,
13121424
FileObjectClassTestCase,
1425+
FileObjectInterruptedTestCase,
13131426
UnbufferedFileObjectClassTestCase,
13141427
LineBufferedFileObjectClassTestCase,
13151428
SmallBufferedFileObjectClassTestCase,

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,10 @@ C-API
194194
Library
195195
-------
196196

197+
- Issue #1628205: Socket file objects returned by socket.socket.makefile() now
198+
properly handles EINTR within the read, readline, write & flush methods.
199+
The socket.sendall() method now properly handles interrupted system calls.
200+
197201
- Issue #7471: Improve the performance of GzipFile's buffering mechanism,
198202
and make it implement the `io.BufferedIOBase` ABC to allow for further
199203
speedups by wrapping it in an `io.BufferedReader`. Patch by Nir Aides.

0 commit comments

Comments
 (0)