forked from goodboy/tractor
1
0
Fork 0

Make SIGINT handler kill the process tree

The std lib's `pdb` internals override SIGINT handling whenever one
enters the debugger repl. Force a handler that kills the tree if SIGINT
is triggered from the root actor, otherwise igore it since supervised
children should be managed already. This resolves an issue with guest
mode where `pdb` causes SIGINTs to be swallowed resulting in the host
loop never terminating the process tree.
advanced_debugger_testing
Tyler Goodlet 2020-11-16 00:01:21 -05:00
parent 5f55c7ca00
commit 02b20dd97c
1 changed files with 14 additions and 8 deletions

View File

@ -11,7 +11,6 @@ from typing import Awaitable, Tuple, Optional, Callable, AsyncIterator
from async_generator import aclosing from async_generator import aclosing
import tractor import tractor
import trio import trio
from trio.testing import wait_all_tasks_blocked
from .log import get_logger from .log import get_logger
from . import _state from . import _state
@ -132,13 +131,20 @@ async def _acquire_debug_lock(uid: Tuple[str, str]) -> AsyncIterator[None]:
log.error(f"TTY lock released by {task_name}:{uid}") log.error(f"TTY lock released by {task_name}:{uid}")
def handler(signum, frame): def handler(signum, frame, *args):
"""Block SIGINT while in debug to avoid deadlocks with cancellation. """Specialized debugger compatible SIGINT handler.
In childred we always ignore to avoid deadlocks since cancellation
should always be managed by the parent supervising actor. The root
is always cancelled on ctrl-c.
""" """
print( if is_root_process():
"tractor ignores SIGINT while in debug mode\n" tractor.current_actor().cancel_soon()
"If you have a special need for it please open an issue.\n" else:
) print(
"tractor ignores SIGINT while in debug mode\n"
"If you have a special need for it please open an issue.\n"
)
# don't allow those stdlib mofos to mess with sigint handler # don't allow those stdlib mofos to mess with sigint handler
@ -261,6 +267,7 @@ def _breakpoint(debug_func) -> Awaitable[None]:
# may have the tty locked prior # may have the tty locked prior
if _debug_lock.locked(): # root process already has it; ignore if _debug_lock.locked(): # root process already has it; ignore
return return
await _debug_lock.acquire() await _debug_lock.acquire()
_pdb_release_hook = _debug_lock.release _pdb_release_hook = _debug_lock.release
@ -269,7 +276,6 @@ def _breakpoint(debug_func) -> Awaitable[None]:
log.debug("Entering the synchronous world of pdb") log.debug("Entering the synchronous world of pdb")
debug_func(actor) debug_func(actor)
# user code **must** await this! # user code **must** await this!
return _bp() return _bp()