Skip to content

Commit

Permalink
Fix memory leak with gen.engine, RequestHandler.flush, and closed con…
Browse files Browse the repository at this point in the history
…nections.

This was unfortunately difficult to reproduce in a unit test, even though
the test program attached to bug 660 easily reproduces it.

Closes #660.
  • Loading branch information
bdarnell committed Jan 20, 2013
1 parent 45b2c30 commit 769bc52
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 1 deletion.
12 changes: 12 additions & 0 deletions tornado/httpserver.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,18 @@ def __init__(self, stream, address, request_callback, no_keep_alive=False,
self._header_callback = stack_context.wrap(self._on_headers)
self.stream.read_until(b"\r\n\r\n", self._header_callback)
self._write_callback = None
self._close_callback = None

def set_close_callback(self, callback):
self._close_callback = stack_context.wrap(callback)
self.stream.set_close_callback(self._on_connection_close)

def _on_connection_close(self):
callback = self._close_callback
self._close_callback = None
callback()
# Delete any unfinished callbacks to break up reference cycles.
self._write_callback = None

def close(self):
self.stream.close()
Expand Down
2 changes: 2 additions & 0 deletions tornado/iostream.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,8 @@ def _maybe_run_close_callback(self):
cb = self._close_callback
self._close_callback = None
self._run_callback(cb)
# Delete any unfinished callbacks to break up reference cycles.
self._read_callback = self._write_callback = None

def reading(self):
"""Returns true if we are currently reading from the stream."""
Expand Down
2 changes: 1 addition & 1 deletion tornado/web.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ def __init__(self, application, request, **kwargs):
self.clear()
# Check since connection is not available in WSGI
if getattr(self.request, "connection", None):
self.request.connection.stream.set_close_callback(
self.request.connection.set_close_callback(
self.on_connection_close)
self.initialize(**kwargs)

Expand Down
5 changes: 5 additions & 0 deletions website/sphinx/releases/next.rst
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,8 @@ In progress
* Python 2.5 is no longer supported.
* Installation under Python 3 no longer uses ``2to3``.
* `tornado.util.b` (which was only intended for internal use) is gone.
* Fixed a memory leak involving ``gen.engine``, `RequestHandler.flush`,
and clients closing connections while output is being written.
* `tornado.httpserver.HTTPConnection` now has a `set_close_callback`
method that should be used instead of reaching into its ``stream``
attribute.

0 comments on commit 769bc52

Please sign in to comment.