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.
This commit is contained in:
parent
ce36962d12
commit
de3369f2ca
|
@ -225,11 +225,12 @@ class SocketIO(io.RawIOBase):
|
|||
return self._writing and not self.closed
|
||||
|
||||
def fileno(self):
|
||||
self._checkClosed()
|
||||
return self._sock.fileno()
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self._sock.fileno()
|
||||
return self.fileno()
|
||||
|
||||
@property
|
||||
def mode(self):
|
||||
|
@ -239,9 +240,12 @@ class SocketIO(io.RawIOBase):
|
|||
if self.closed:
|
||||
return
|
||||
io.RawIOBase.close(self)
|
||||
self._sock._decref_socketios()
|
||||
self._sock = None
|
||||
|
||||
def __del__(self):
|
||||
self._sock._decref_socketios()
|
||||
if not self.closed:
|
||||
self._sock._decref_socketios()
|
||||
|
||||
|
||||
def getfqdn(name=''):
|
||||
|
|
|
@ -856,6 +856,16 @@ class FileObjectClassTestCase(SocketConnectedTest):
|
|||
self.assertEqual(self.cli_file.mode, 'wb')
|
||||
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):
|
||||
|
||||
"""Repeat the tests from FileObjectClassTestCase with bufsize==0.
|
||||
|
@ -881,6 +891,29 @@ class UnbufferedFileObjectClassTestCase(FileObjectClassTestCase):
|
|||
self.cli_file.write(b"B. " + MSG)
|
||||
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):
|
||||
|
||||
bufsize = 1 # Default-buffered for reading; line-buffered for writing
|
||||
|
|
|
@ -111,6 +111,10 @@ Core and Builtins
|
|||
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 #4867: Fixed a crash in ctypes when passing a string to a
|
||||
|
|
Loading…
Reference in New Issue