Browse files

Simplify StackContext logic and behavior.

Previously, there was an optimization to avoid recreating contexts
that were already on the stack.  This optimization rarely mattered
(especially given the movement to run all callbacks through
IOLoop.add_callback), and sometimes caused surprising behavior as
other exception handlers could be inserted between stack contexts that
expected to be adjacent to each other or to the wrapped function.  Now
each wrapped function recreates its full stack of contexts, even if
some of those contexts were already on the stack.

This change allows a use of NullContext in to be
  • Loading branch information...
1 parent 69e4492 commit 2ded26610f9f3f7962129617bc2b60d1856708da @bdarnell bdarnell committed Sep 29, 2012
Showing with 9 additions and 31 deletions.
  1. +7 −25 tornado/
  2. +2 −6 tornado/
@@ -70,7 +70,6 @@ def die_on_error():
import contextlib
import functools
-import itertools
import operator
import sys
import threading
@@ -198,31 +197,14 @@ def wrap(fn):
def wrapped(*args, **kwargs):
callback, contexts, args = args[0], args[1], args[2:]
- if contexts is _state.contexts:
- callback(*args, **kwargs)
- return
- if not _state.contexts:
- new_contexts = [cls(arg, active_cell)
- for (cls, arg, active_cell) in contexts
- if active_cell[0]]
- # If we're moving down the stack, _state.contexts is a prefix
- # of contexts. For each element of contexts not in that prefix,
- # create a new StackContext object.
- # If we're moving up the stack (or to an entirely different stack),
- # _state.contexts will have elements not in contexts. Use
- # NullContext to clear the state and then recreate from contexts.
- elif (len(_state.contexts) > len(contexts) or
- any(a[1] is not b[1]
- for a, b in itertools.izip(_state.contexts, contexts))):
- # contexts have been removed or changed, so start over
- new_contexts = ([NullContext()] +
- [cls(arg, active_cell)
- for (cls, arg, active_cell) in contexts
- if active_cell[0]])
+ if _state.contexts:
+ new_contexts = [NullContext()]
- new_contexts = [cls(arg, active_cell)
- for (cls, arg, active_cell) in contexts[len(_state.contexts):]
- if active_cell[0]]
+ new_contexts = []
+ if contexts:
+ new_contexts.extend(cls(arg, active_cell)
+ for (cls, arg, active_cell) in contexts
+ if active_cell[0])
if len(new_contexts) > 1:
with _nested(*new_contexts):
callback(*args, **kwargs)
@@ -36,7 +36,7 @@
netutil = None
SimpleAsyncHTTPClient = None
from tornado.log import gen_log
-from tornado.stack_context import StackContext, NullContext
+from tornado.stack_context import StackContext
from tornado.util import raise_exc_info
import contextlib
import logging
@@ -223,11 +223,7 @@ def timeout_func():
self.__timeout = self.io_loop.add_timeout(time.time() + timeout, timeout_func)
while True:
self.__running = True
- with NullContext():
- # Wipe out the StackContext that was established in
- # so that all callbacks executed inside the
- # IOLoop will re-run it.
- self.io_loop.start()
+ self.io_loop.start()
if (self.__failure is not None or
condition is None or condition()):

0 comments on commit 2ded266

Please sign in to comment.