In add_callback, hold the lock while writing to the waker pipe.

This protects against a shutdown race condition seen occasionally in
the ThreadedResolver unittests.  This slightly increases contention
on the callback lock in multi-threaded scenarios, but the cost is
limited by the fact that we only write to the pipe once per IOLoop
iteration.

Closes #875.
This commit is contained in:
Ben Darnell 2013-08-18 23:54:59 -04:00
parent 6ec711cded
commit 8e7effdaef
1 changed files with 8 additions and 8 deletions

View File

@ -722,14 +722,14 @@ class PollIOLoop(IOLoop):
list_empty = not self._callbacks
self._callbacks.append(functools.partial(
stack_context.wrap(callback), *args, **kwargs))
if list_empty and thread.get_ident() != self._thread_ident:
# If we're in the IOLoop's thread, we know it's not currently
# polling. If we're not, and we added the first callback to an
# empty list, we may need to wake it up (it may wake up on its
# own, but an occasional extra wake is harmless). Waking
# up a polling IOLoop is relatively expensive, so we try to
# avoid it when we can.
self._waker.wake()
if list_empty and thread.get_ident() != self._thread_ident:
# If we're in the IOLoop's thread, we know it's not currently
# polling. If we're not, and we added the first callback to an
# empty list, we may need to wake it up (it may wake up on its
# own, but an occasional extra wake is harmless). Waking
# up a polling IOLoop is relatively expensive, so we try to
# avoid it when we can.
self._waker.wake()
def add_callback_from_signal(self, callback, *args, **kwargs):
with stack_context.NullContext():