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 <[email protected]> Authored: Wed Jan 11 14:20:14 2017 -0800 Committer: Clifford Jansen <[email protected]> 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: [email protected] For additional commands, e-mail: [email protected]
