[Python-3000] socket GC worries (original) (raw)

Bill Janssen janssen at parc.com
Tue Oct 30 20:49:21 CET 2007


But if we remove SocketCloser, there's no need for the cyclic GC to be involved. If the count (of the number of outstanding SocketIO instances pointing to this socket.socket) is just moved into the socket.socket object itself, there's no cyclic reference, and normal refcounting should work just fine. I don't even think a del method on socket.socket is necessary.

Here's a patch, for whenever you get back to this. You can ignore/remove the first hunk, which is about SSL. I've tried all the tests, and they work. I've looked for leaks in test_socket and test_ssl, no leaks.

Bill

Index: Lib/socket.py

--- Lib/socket.py (revision 58714) +++ Lib/socket.py (working copy) @@ -21,7 +21,6 @@ htons(), htonl() -- convert 16, 32 bit int from host to network byte order inet_aton() -- convert IP addr string (123.45.67.89) to 32-bit packed format inet_ntoa() -- convert 32-bit packed format IP to string (123.45.67.89) -ssl() -- secure socket layer support (only available if configured) socket.getdefaulttimeout() -- get the default timeout value socket.setdefaulttimeout() -- set the default timeout value create_connection() -- connects to an address, with an optional timeout @@ -46,36 +45,6 @@ import _socket from _socket import * -try: - import _ssl - import ssl as _realssl -except ImportError: - # no SSL support - pass -else: - def ssl(sock, keyfile=None, certfile=None): - # we do an internal import here because the ssl - # module imports the socket module - warnings.warn("socket.ssl() is deprecated. Use ssl.wrap_socket() instead.", - DeprecationWarning, stacklevel=2) - return _realssl.sslwrap_simple(sock, keyfile, certfile)

@@ -119,49 +88,11 @@ nfd = os.dup(fd) return socket(family, type, proto, fileno=nfd) -class SocketCloser:

@@ -170,16 +101,17 @@ _socket.socket.init(self, family, type, proto) else: _socket.socket.init(self, family, type, proto, fileno) - # Defer creating a SocketCloser until makefile() is actually called. - self._closer = None + self._io_refs = 0 + self._closed = False def repr(self): """Wrap repr() to reveal the real class name.""" s = _socket.socket.repr(self) if s.startswith("<socket object"): - s = "<%s.%s%s" % (self.__class__.__module__, - self.__class__.__name__, - s[7:]) + s = "<%s.%s%s%s" % (self.__class__.__module__, + self.__class__.__name__, + (self._closed and " [closed] ") or "", + s[7:]) return s def accept(self): @@ -196,6 +128,12 @@ conn.close() return wrapper, addr + def decref_socketios(self): + if self._io_refs > 0: + self._io_refs -= 1 + if self._closed: + self.close() + def makefile(self, mode="r", buffering=None, *, encoding=None, newline=None): """Return an I/O stream connected to the socket. @@ -216,9 +154,8 @@ rawmode += "r" if writing: rawmode += "w" - if self._closer is None: - self._closer = SocketCloser(self) - raw = SocketIO(self, rawmode, self._closer) + raw = SocketIO(self, rawmode) + self._io_refs += 1 if buffering is None: buffering = -1 if buffering < 0: @@ -246,10 +183,9 @@ return text def close(self): - if self._closer is None: + self._closed = True + if self._io_refs < 1: self._real_close() - else: - self._closer.socket_close() # _real_close calls close on the _socket.socket base class. @@ -275,16 +211,14 @@ # XXX More docs - def init(self, sock, mode, closer): + def init(self, sock, mode): if mode not in ("r", "w", "rw"): raise ValueError("invalid mode: %r" % mode) io.RawIOBase.init(self) self._sock = sock self._mode = mode - self._closer = closer self._reading = "r" in mode self._writing = "w" in mode - closer.makefile_open() def readinto(self, b): self._checkClosed() @@ -308,10 +242,12 @@ def close(self): if self.closed: return - self._closer.makefile_close() io.RawIOBase.close(self) + def del(self): + self._sock.decref_socketios() + def getfqdn(name=''): """Get fully qualified domain name from name.


More information about the Python-3000 mailing list