Commit de3369f2 authored by Gregory P. Smith's avatar Gregory P. Smith

Fixes issue #3826 and #4791:

Have SocketIO objects update their reference count in the underlying
socket object on close() so that the underlying socket object is
closed immediately when the last user is done rather than at an
unknown later time when garbage collection can do it.
parent ce36962d
...@@ -225,11 +225,12 @@ class SocketIO(io.RawIOBase): ...@@ -225,11 +225,12 @@ class SocketIO(io.RawIOBase):
return self._writing and not self.closed return self._writing and not self.closed
def fileno(self): def fileno(self):
self._checkClosed()
return self._sock.fileno() return self._sock.fileno()
@property @property
def name(self): def name(self):
return self._sock.fileno() return self.fileno()
@property @property
def mode(self): def mode(self):
...@@ -239,9 +240,12 @@ class SocketIO(io.RawIOBase): ...@@ -239,9 +240,12 @@ class SocketIO(io.RawIOBase):
if self.closed: if self.closed:
return return
io.RawIOBase.close(self) io.RawIOBase.close(self)
self._sock._decref_socketios()
self._sock = None
def __del__(self): def __del__(self):
self._sock._decref_socketios() if not self.closed:
self._sock._decref_socketios()
def getfqdn(name=''): def getfqdn(name=''):
......
...@@ -856,6 +856,16 @@ class FileObjectClassTestCase(SocketConnectedTest): ...@@ -856,6 +856,16 @@ class FileObjectClassTestCase(SocketConnectedTest):
self.assertEqual(self.cli_file.mode, 'wb') self.assertEqual(self.cli_file.mode, 'wb')
self.assertEqual(self.cli_file.name, self.serv_conn.fileno()) self.assertEqual(self.cli_file.name, self.serv_conn.fileno())
def testRealClose(self):
self.serv_file.close()
self.assertRaises(ValueError, self.serv_file.fileno)
self.cli_conn.close()
self.assertRaises(socket.error, self.cli_conn.getsockname)
def _testRealClose(self):
pass
class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase): class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase):
"""Repeat the tests from FileObjectClassTestCase with bufsize==0. """Repeat the tests from FileObjectClassTestCase with bufsize==0.
...@@ -881,6 +891,29 @@ class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase): ...@@ -881,6 +891,29 @@ class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase):
self.cli_file.write(b"B. " + MSG) self.cli_file.write(b"B. " + MSG)
self.cli_file.flush() self.cli_file.flush()
def testMakefileClose(self):
# The file returned by makefile should keep the socket open...
self.cli_conn.close()
msg = self.cli_conn.recv(1024)
self.assertEqual(msg, MSG)
# ...until the file is itself closed
self.serv_file.close()
self.assertRaises(socket.error, self.cli_conn.recv, 1024)
def _testMakefileClose(self):
self.cli_file.write(MSG)
self.cli_file.flush()
def testMakefileCloseSocketDestroy(self):
refcount_before = sys.getrefcount(self.cli_conn)
self.serv_file.close()
refcount_after = sys.getrefcount(self.cli_conn)
self.assertEqual(refcount_before - 1, refcount_after)
def _testMakefileCloseSocketDestroy(self):
pass
class LineBufferedFileObjectClassTestCase(FileObjectClassTestCase): class LineBufferedFileObjectClassTestCase(FileObjectClassTestCase):
bufsize = 1 # Default-buffered for reading; line-buffered for writing bufsize = 1 # Default-buffered for reading; line-buffered for writing
......
...@@ -111,6 +111,10 @@ Core and Builtins ...@@ -111,6 +111,10 @@ Core and Builtins
Library Library
------- -------
- Issue #3826 and #4791: The socket module now closes the underlying socket
appropriately when it is being used via socket.makefile() objects
rather than delaying the close by waiting for garbage collection to do it.
- Issue #3860: GzipFile and BZ2File now support the context manager protocol. - Issue #3860: GzipFile and BZ2File now support the context manager protocol.
- Issue #4867: Fixed a crash in ctypes when passing a string to a - Issue #4867: Fixed a crash in ctypes when passing a string to a
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment