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:
parent
8216a5e599
commit
d8e069ef1e
|
@ -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):
|
||||||
|
|
Loading…
Reference in New Issue