ioloop: add_callback_from_signal() calls add_callback()

Now that add_callback checks thread.ident() and no longer deadlocks from
a signal handler, add_callback_from_signal can call it unconditionally.
This commit is contained in:
Ben Darnell 2015-09-27 16:03:54 -04:00
parent 8216a5e599
commit d8e069ef1e
1 changed files with 13 additions and 26 deletions

View File

@ -919,43 +919,30 @@ class PollIOLoop(IOLoop):
self._callbacks.append(functools.partial( self._callbacks.append(functools.partial(
stack_context.wrap(callback), *args, **kwargs)) stack_context.wrap(callback), *args, **kwargs))
if list_empty: if list_empty:
# If we're not in the IOLoop's thread, and we added the # If we're not in the IOLoop's thread, and we added the
# first callback to an empty list, we may need to wake it # first callback to an empty list, we may need to wake it
# up (it may wake up on its own, but an occasional extra # up (it may wake up on its own, but an occasional extra
# wake is harmless). Waking up a polling IOLoop is # wake is harmless). Waking up a polling IOLoop is
# relatively expensive, so we try to avoid it when we can. # relatively expensive, so we try to avoid it when we can.
self._waker.wake() self._waker.wake()
else: else:
if self._closing: if self._closing:
raise RuntimeError("IOLoop is closing") raise RuntimeError("IOLoop is closing")
# If we're on the IOLoop's thread, we don't need the lock, # If we're on the IOLoop's thread, we don't need the lock,
# since we don't need to wake anyone, just add the callback. # since we don't need to wake anyone, just add the
# Blindly insert into self._callbacks. # callback. Blindly insert into self._callbacks. This is
# This is safe because the GIL makes list.append atomic. # safe even from signal handlers because the GIL makes
# One subtlety is that if the thread is interrupting another # list.append atomic. One subtlety is that if the signal
# thread holding the _callback_lock block in IOLoop.start, # is interrupting another thread holding the
# we may modify either the old or new version of self._callbacks, # _callback_lock block in IOLoop.start, we may modify
# but either way will work. # either the old or new version of self._callbacks, but
# either way will work.
self._callbacks.append(functools.partial( self._callbacks.append(functools.partial(
stack_context.wrap(callback), *args, **kwargs)) stack_context.wrap(callback), *args, **kwargs))
def add_callback_from_signal(self, callback, *args, **kwargs): def add_callback_from_signal(self, callback, *args, **kwargs):
with stack_context.NullContext(): with stack_context.NullContext():
if thread.get_ident() != self._thread_ident: self.add_callback(callback, *args, **kwargs)
# if the signal is handled on another thread, we can add
# it normally (modulo the NullContext)
self.add_callback(callback, *args, **kwargs)
else:
# If we're on the IOLoop's thread, we cannot use
# the regular add_callback because it may deadlock on
# _callback_lock. Blindly insert into self._callbacks.
# This is safe because the GIL makes list.append atomic.
# One subtlety is that if the signal interrupted the
# _callback_lock block in IOLoop.start, we may modify
# either the old or new version of self._callbacks,
# but either way will work.
self._callbacks.append(functools.partial(
stack_context.wrap(callback), *args, **kwargs))
class _Timeout(object): class _Timeout(object):