[project @ Arch-1:robey@lag.net--2005-master-shake%paramiko--dev--1--patch-45]
yeah! figured out the last things that were causing GC cycles and got rid of them: Channels, Transports, SFTPClients, and SFTPFiles can all have __del__ methods now, which auto-close themselves :)
This commit is contained in:
parent
f27e625926
commit
e9ccd7ea20
|
@ -88,6 +88,9 @@ class Channel (object):
|
|||
self.combine_stderr = False
|
||||
self.exit_status = -1
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Return a string representation of this object, for debugging.
|
||||
|
@ -455,11 +458,7 @@ class Channel (object):
|
|||
Close the channel. All future read/write operations on the channel
|
||||
will fail. The remote end will receive no more data (after queued data
|
||||
is flushed). Channels are automatically closed when their L{Transport}
|
||||
is closed.
|
||||
|
||||
Note that because of peculiarities with the way python's garbage
|
||||
collection works on cycles, channels will B{not} be automatically
|
||||
closed by the garbage collector.
|
||||
is closed or when they are garbage collected.
|
||||
"""
|
||||
self.lock.acquire()
|
||||
try:
|
||||
|
|
|
@ -63,6 +63,9 @@ class SFTPClient (BaseSFTP):
|
|||
self.sock.get_name() + '.sftp')
|
||||
self.ultra_debug = transport.get_hexdump()
|
||||
self._send_version()
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def from_transport(selfclass, t):
|
||||
"""
|
||||
|
|
|
@ -41,6 +41,9 @@ class SFTPFile (BufferedFile):
|
|||
self.handle = handle
|
||||
BufferedFile._set_mode(self, mode, bufsize)
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def close(self):
|
||||
BufferedFile.close(self)
|
||||
try:
|
||||
|
|
|
@ -21,6 +21,7 @@ L{BaseTransport} handles the core SSH2 protocol.
|
|||
"""
|
||||
|
||||
import sys, os, string, threading, socket, struct, time
|
||||
import weakref
|
||||
|
||||
from common import *
|
||||
from ssh_exception import SSHException
|
||||
|
@ -205,7 +206,7 @@ class BaseTransport (threading.Thread):
|
|||
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
sock.connect((hostname, port))
|
||||
# okay, normal socket-ish flow here...
|
||||
threading.Thread.__init__(self, target=self._run)
|
||||
threading.Thread.__init__(self)
|
||||
self.randpool = randpool
|
||||
self.sock = sock
|
||||
# Python < 2.3 doesn't have the settimeout method - RogerB
|
||||
|
@ -229,7 +230,7 @@ class BaseTransport (threading.Thread):
|
|||
self.initial_kex_done = False
|
||||
self.in_kex = False
|
||||
self.lock = threading.Lock() # synchronization (always higher level than write_lock)
|
||||
self.channels = { } # (id -> Channel)
|
||||
self.channels = weakref.WeakValueDictionary() # (id -> Channel)
|
||||
self.channel_events = { } # (id -> Event)
|
||||
self.channel_counter = 1
|
||||
self.window_size = 65536
|
||||
|
@ -249,6 +250,9 @@ class BaseTransport (threading.Thread):
|
|||
self.server_accept_cv = threading.Condition(self.lock)
|
||||
self.subsystem_table = { }
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
Returns a string representation of this object, for debugging.
|
||||
|
@ -969,7 +973,12 @@ class BaseTransport (threading.Thread):
|
|||
raise SSHException('Unknown client cipher ' + name)
|
||||
return self._cipher_info[name]['class'].new(key, self._cipher_info[name]['mode'], iv)
|
||||
|
||||
def _run(self):
|
||||
def run(self):
|
||||
# (use the exposed "run" method, because if we specify a thread target
|
||||
# of a private method, threading.Thread will keep a reference to it
|
||||
# indefinitely, creating a GC cycle and not letting Transport ever be
|
||||
# GC'd. it's a bug in Thread.)
|
||||
|
||||
# active=True occurs before the thread is launched, to avoid a race
|
||||
_active_threads.append(self)
|
||||
if self.server_mode:
|
||||
|
@ -1281,6 +1290,7 @@ class BaseTransport (threading.Thread):
|
|||
# can also free a bunch of stuff here
|
||||
self.local_kex_init = self.remote_kex_init = None
|
||||
self.K = None
|
||||
self.kex_engine = None
|
||||
if not self.initial_kex_done:
|
||||
# this was the first key exchange
|
||||
self.initial_kex_done = True
|
||||
|
|
Loading…
Reference in New Issue