You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@qpid.apache.org by ac...@apache.org on 2017/01/18 01:16:18 UTC

[02/10] qpid-proton git commit: PROTON-1312: fix memory leak on BlockingConnection.close()

PROTON-1312: fix memory leak on BlockingConnection.close()


Project: http://git-wip-us.apache.org/repos/asf/qpid-proton/repo
Commit: http://git-wip-us.apache.org/repos/asf/qpid-proton/commit/98e26f69
Tree: http://git-wip-us.apache.org/repos/asf/qpid-proton/tree/98e26f69
Diff: http://git-wip-us.apache.org/repos/asf/qpid-proton/diff/98e26f69

Branch: refs/heads/go1
Commit: 98e26f69995e6628c4b6c97b1826a761d9168d8c
Parents: 431c00d
Author: Clifford Jansen <cl...@apache.org>
Authored: Wed Jan 11 14:20:14 2017 -0800
Committer: Clifford Jansen <cl...@apache.org>
Committed: Wed Jan 11 14:20:14 2017 -0800

----------------------------------------------------------------------
 proton-c/bindings/python/proton/__init__.py |  3 +++
 proton-c/bindings/python/proton/reactor.py  |  5 -----
 proton-c/bindings/python/proton/utils.py    | 14 ++++++++++++++
 3 files changed, 17 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/98e26f69/proton-c/bindings/python/proton/__init__.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton/__init__.py b/proton-c/bindings/python/proton/__init__.py
index cfac01e..2b354df 100644
--- a/proton-c/bindings/python/proton/__init__.py
+++ b/proton-c/bindings/python/proton/__init__.py
@@ -2581,6 +2581,9 @@ and SASL layers to identify the peer.
     """
     self._update_cond()
     pn_connection_close(self._impl)
+    if hasattr(self, '_session_policy'):
+      # break circular ref
+      del self._session_policy
 
   @property
   def state(self):

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/98e26f69/proton-c/bindings/python/proton/reactor.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton/reactor.py b/proton-c/bindings/python/proton/reactor.py
index e4dab95..269ed9e 100644
--- a/proton-c/bindings/python/proton/reactor.py
+++ b/proton-c/bindings/python/proton/reactor.py
@@ -494,13 +494,8 @@ class SessionPerConnection(object):
     def session(self, connection):
         if not self._default_session:
             self._default_session = _create_session(connection)
-            self._default_session.context = self
         return self._default_session
 
-    def on_session_remote_close(self, event):
-        event.connection.close()
-        self._default_session = None
-
 class GlobalOverrides(object):
     """
     Internal handler that triggers the necessary socket connect for an

http://git-wip-us.apache.org/repos/asf/qpid-proton/blob/98e26f69/proton-c/bindings/python/proton/utils.py
----------------------------------------------------------------------
diff --git a/proton-c/bindings/python/proton/utils.py b/proton-c/bindings/python/proton/utils.py
index 9cd7cf3..05ef80d 100644
--- a/proton-c/bindings/python/proton/utils.py
+++ b/proton-c/bindings/python/proton/utils.py
@@ -132,10 +132,15 @@ class BlockingReceiver(BlockingLink):
             raise LinkException("Failed to open receiver %s, source does not match" % self.link.name)
         if credit: receiver.flow(credit)
         self.fetcher = fetcher
+        self.container = connection.container
 
     def __del__(self):
         self.fetcher = None
+        # The next line causes a core dump if the Proton-C reactor finalizes
+        # first.  The self.container reference prevents reactor finalization
+        # until after it is set to None.
         self.link.handler = None
+        self.container = None
 
     def receive(self, timeout=False):
         if not self.fetcher:
@@ -222,12 +227,19 @@ class BlockingConnection(Handler):
             self, self.container.create_receiver(self.conn, address, name=name, dynamic=dynamic, handler=handler or fetcher, options=options), fetcher, credit=prefetch)
 
     def close(self):
+        if not self.conn:
+            return
         self.conn.close()
         try:
             self.wait(lambda: not (self.conn.state & Endpoint.REMOTE_ACTIVE),
                       msg="Closing connection")
         finally:
+            self.conn.free()
+            # For cleanup, reactor needs to process PN_CONNECTION_FINAL
+            # and all events with embedded contexts must be drained.
+            self.run() # will not block any more
             self.conn = None
+            self.container.global_handler = None # break circular ref: container to cadapter.on_error
             self.container = None
 
     def _is_closed(self):
@@ -236,6 +248,8 @@ class BlockingConnection(Handler):
     def run(self):
         """ Hand control over to the event loop (e.g. if waiting indefinitely for incoming messages) """
         while self.container.process(): pass
+        self.container.stop()
+        self.container.process()
 
     def wait(self, condition, timeout=False, msg=None):
         """Call process until condition() is true"""


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