You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by kw...@apache.org on 2015/04/03 17:51:57 UTC

svn commit: r1671094 - in /qpid/trunk/qpid/python/qpid: client.py connection08.py peer.py

Author: kwall
Date: Fri Apr  3 15:51:57 2015
New Revision: 1671094

URL: http://svn.apache.org/r1671094
Log:
QPID-6474: [Python Client] Prevent client connection thread leaks on the 08..09 code path

Modified:
    qpid/trunk/qpid/python/qpid/client.py
    qpid/trunk/qpid/python/qpid/connection08.py
    qpid/trunk/qpid/python/qpid/peer.py

Modified: qpid/trunk/qpid/python/qpid/client.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/python/qpid/client.py?rev=1671094&r1=1671093&r2=1671094&view=diff
==============================================================================
--- qpid/trunk/qpid/python/qpid/client.py (original)
+++ qpid/trunk/qpid/python/qpid/client.py Fri Apr  3 15:51:57 2015
@@ -126,7 +126,8 @@ class Client:
       return self.channel(id)
 
   def close(self):
-    self.socket.close()
+    if self.peer:
+      self.peer.stop()
 
 class ClientDelegate(Delegate):
 

Modified: qpid/trunk/qpid/python/qpid/connection08.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/python/qpid/connection08.py?rev=1671094&r1=1671093&r2=1671094&view=diff
==============================================================================
--- qpid/trunk/qpid/python/qpid/connection08.py (original)
+++ qpid/trunk/qpid/python/qpid/connection08.py Fri Apr  3 15:51:57 2015
@@ -118,6 +118,7 @@ class Connection:
     self.FRAME_END = self.spec.constants.byname["frame_end"].id
     self.write = getattr(self, "write_%s_%s" % (self.spec.major, self.spec.minor))
     self.read = getattr(self, "read_%s_%s" % (self.spec.major, self.spec.minor))
+    self.io = io
 
   def flush(self):
     self.codec.flush()
@@ -250,6 +251,9 @@ class Connection:
   def read_99_0(self):
     return self.read_0_10()
 
+  def close(self):
+    self.io.close();
+
 class Frame:
 
   DECODERS = {}

Modified: qpid/trunk/qpid/python/qpid/peer.py
URL: http://svn.apache.org/viewvc/qpid/trunk/qpid/python/qpid/peer.py?rev=1671094&r1=1671093&r2=1671094&view=diff
==============================================================================
--- qpid/trunk/qpid/python/qpid/peer.py (original)
+++ qpid/trunk/qpid/python/qpid/peer.py Fri Apr  3 15:51:57 2015
@@ -24,7 +24,7 @@ sorts incoming frames to their intended
 incoming method frames to a delegate.
 """
 
-import thread, threading, traceback, socket, sys, logging
+import threading, traceback, socket, sys
 from connection08 import EOF, Method, Header, Body, Request, Response, VersionError
 from message import Message
 from queue import Queue, Closed as QueueClosed
@@ -32,6 +32,9 @@ from content import Content
 from cStringIO import StringIO
 from time import time
 from exceptions import Closed
+from logging import getLogger
+
+log = getLogger("qpid.peer")
 
 class Sequence:
 
@@ -39,7 +42,7 @@ class Sequence:
     # we should keep start for wrap around
     self._next = start
     self.step = step
-    self.lock = thread.allocate_lock()
+    self.lock = threading.Lock()
 
   def next(self):
     self.lock.acquire()
@@ -58,7 +61,7 @@ class Peer:
     self.outgoing = Queue(0)
     self.work = Queue(0)
     self.channels = {}
-    self.lock = thread.allocate_lock()
+    self.lock = threading.Lock()
     if channel_factory:
       self.channel_factory = channel_factory
     else:
@@ -77,13 +80,20 @@ class Peer:
     return ch
 
   def start(self):
-    thread.start_new_thread(self.writer, ())
-    thread.start_new_thread(self.reader, ())
-    thread.start_new_thread(self.worker, ())
+    self.writer_thread = threading.Thread(target=self.writer)
+    self.writer_thread.daemon = True
+    self.writer_thread.start()
+
+    self.reader_thread = threading.Thread(target=self.reader)
+    self.reader_thread.daemon = True
+    self.reader_thread.start()
+
+    self.worker_thread = threading.Thread(target=self.worker)
+    self.worker_thread.daemon = True
+    self.worker_thread.start()
 
   def fatal(self, message=None):
     """Call when an unexpected exception occurs that will kill a thread."""
-    if message: print >> sys.stderr, message
     self.closed("Fatal error: %s\n%s" % (message or "", traceback.format_exc()))
 
   def reader(self):
@@ -119,6 +129,8 @@ class Peer:
           self.closed(e)
           break
         self.conn.flush()
+    except QueueClosed:
+      pass
     except:
       self.fatal()
 
@@ -139,6 +151,23 @@ class Peer:
     except:
       self.fatal()
 
+  def stop(self):
+    try:
+      self.work.close();
+      self.outgoing.close();
+      self.conn.close();
+    finally:
+      timeout = 1;
+      self.worker_thread.join(timeout);
+      if self.worker_thread.isAlive():
+        log.warn("Worker thread failed to shutdown within timeout")
+      self.reader_thread.join(timeout);
+      if self.reader_thread.isAlive():
+        log.warn("Reader thread failed to shutdown within timeout")
+      self.writer_thread.join(timeout);
+      if self.writer_thread.isAlive():
+        log.warn("Writer thread failed to shutdown within timeout")
+
 class Requester:
 
   def __init__(self, writer):



---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@qpid.apache.org
For additional commands, e-mail: commits-help@qpid.apache.org