forked from goodboy/tractor
				
			Always restore at least `trio`'s sigint handler
We can get it during runtime startup and stash on a new `Lock._trio_handler`. Always at least revert to this handler to guarantee graceful kbi handling despite mucking about with our own handler in debug mode.egs_with_ctx_res_consumption
							parent
							
								
									8727c1e4c2
								
							
						
					
					
						commit
						f6ac0c2eb7
					
				| 
						 | 
					@ -75,8 +75,10 @@ class Lock:
 | 
				
			||||||
    # placeholder for function to set a ``trio.Event`` on debugger exit
 | 
					    # placeholder for function to set a ``trio.Event`` on debugger exit
 | 
				
			||||||
    # pdb_release_hook: Optional[Callable] = None
 | 
					    # pdb_release_hook: Optional[Callable] = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    _trio_handler: Callable | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # actor-wide variable pointing to current task name using debugger
 | 
					    # actor-wide variable pointing to current task name using debugger
 | 
				
			||||||
    local_task_in_debug: Optional[str] = None
 | 
					    local_task_in_debug: str | None = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # NOTE: set by the current task waiting on the root tty lock from
 | 
					    # NOTE: set by the current task waiting on the root tty lock from
 | 
				
			||||||
    # the CALLER side of the `lock_tty_for_child()` context entry-call
 | 
					    # the CALLER side of the `lock_tty_for_child()` context entry-call
 | 
				
			||||||
| 
						 | 
					@ -111,13 +113,10 @@ class Lock:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
    def unshield_sigint(cls):
 | 
					    def unshield_sigint(cls):
 | 
				
			||||||
        if cls._orig_sigint_handler is not None:
 | 
					        # always restore (some) sigint handler, either
 | 
				
			||||||
            # restore original sigint handler
 | 
					        # the prior or at least ``trio``'s.
 | 
				
			||||||
            signal.signal(
 | 
					        orig = cls._orig_sigint_handler or cls._trio_handler
 | 
				
			||||||
                signal.SIGINT,
 | 
					        signal.signal(signal.SIGINT, orig)
 | 
				
			||||||
                cls._orig_sigint_handler
 | 
					 | 
				
			||||||
            )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        cls._orig_sigint_handler = None
 | 
					        cls._orig_sigint_handler = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @classmethod
 | 
					    @classmethod
 | 
				
			||||||
| 
						 | 
					@ -544,7 +543,7 @@ def shield_sigint(
 | 
				
			||||||
 | 
					
 | 
				
			||||||
) -> None:
 | 
					) -> None:
 | 
				
			||||||
    '''
 | 
					    '''
 | 
				
			||||||
    Specialized debugger compatible SIGINT handler.
 | 
					    Specialized, debugger-aware SIGINT handler.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    In childred we always ignore to avoid deadlocks since cancellation
 | 
					    In childred we always ignore to avoid deadlocks since cancellation
 | 
				
			||||||
    should always be managed by the parent supervising actor. The root
 | 
					    should always be managed by the parent supervising actor. The root
 | 
				
			||||||
| 
						 | 
					@ -601,6 +600,8 @@ def shield_sigint(
 | 
				
			||||||
        # which has already terminated to unlock.
 | 
					        # which has already terminated to unlock.
 | 
				
			||||||
        and any_connected
 | 
					        and any_connected
 | 
				
			||||||
    ):
 | 
					    ):
 | 
				
			||||||
 | 
					        # we are root and some actor is in debug mode
 | 
				
			||||||
 | 
					        # if uid_in_debug is not None:
 | 
				
			||||||
        name = uid_in_debug[0]
 | 
					        name = uid_in_debug[0]
 | 
				
			||||||
        if name != 'root':
 | 
					        if name != 'root':
 | 
				
			||||||
            log.pdb(
 | 
					            log.pdb(
 | 
				
			||||||
| 
						 | 
					@ -611,6 +612,22 @@ def shield_sigint(
 | 
				
			||||||
            log.pdb(
 | 
					            log.pdb(
 | 
				
			||||||
                "Ignoring SIGINT while in debug mode"
 | 
					                "Ignoring SIGINT while in debug mode"
 | 
				
			||||||
            )
 | 
					            )
 | 
				
			||||||
 | 
					    elif (
 | 
				
			||||||
 | 
					        is_root_process()
 | 
				
			||||||
 | 
					    ):
 | 
				
			||||||
 | 
					        log.pdb(
 | 
				
			||||||
 | 
					            "Ignoring SIGINT since debug mode is enabled"
 | 
				
			||||||
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # revert back to ``trio`` handler asap!
 | 
				
			||||||
 | 
					        Lock.unshield_sigint()
 | 
				
			||||||
 | 
					        if (
 | 
				
			||||||
 | 
					            Lock._root_local_task_cs_in_debug
 | 
				
			||||||
 | 
					            and not Lock._root_local_task_cs_in_debug.cancel_called
 | 
				
			||||||
 | 
					        ):
 | 
				
			||||||
 | 
					            Lock._root_local_task_cs_in_debug.cancel()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        # raise KeyboardInterrupt
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # child actor that has locked the debugger
 | 
					    # child actor that has locked the debugger
 | 
				
			||||||
    elif not is_root_process():
 | 
					    elif not is_root_process():
 | 
				
			||||||
| 
						 | 
					@ -636,10 +653,9 @@ def shield_sigint(
 | 
				
			||||||
        # https://github.com/goodboy/tractor/issues/320
 | 
					        # https://github.com/goodboy/tractor/issues/320
 | 
				
			||||||
        # elif debug_mode():
 | 
					        # elif debug_mode():
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    else:
 | 
					    else:  # XXX: shouldn't ever get here?
 | 
				
			||||||
        log.pdb(
 | 
					        print("WTFWTFWTF")
 | 
				
			||||||
            "Ignoring SIGINT since debug mode is enabled"
 | 
					        raise KeyboardInterrupt
 | 
				
			||||||
        )
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # NOTE: currently (at least on ``fancycompleter`` 0.9.2)
 | 
					    # NOTE: currently (at least on ``fancycompleter`` 0.9.2)
 | 
				
			||||||
    # it lookks to be that the last command that was run (eg. ll)
 | 
					    # it lookks to be that the last command that was run (eg. ll)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -23,6 +23,7 @@ from functools import partial
 | 
				
			||||||
import importlib
 | 
					import importlib
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
 | 
					import signal
 | 
				
			||||||
from typing import (
 | 
					from typing import (
 | 
				
			||||||
    Optional,
 | 
					    Optional,
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					@ -76,14 +77,19 @@ async def open_root_actor(
 | 
				
			||||||
    rpc_module_paths: Optional[list] = None,
 | 
					    rpc_module_paths: Optional[list] = None,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
) -> typing.Any:
 | 
					) -> typing.Any:
 | 
				
			||||||
    """Async entry point for ``tractor``.
 | 
					    '''
 | 
				
			||||||
 | 
					    Runtime init entry point for ``tractor``.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    """
 | 
					    '''
 | 
				
			||||||
    # Override the global debugger hook to make it play nice with
 | 
					    # Override the global debugger hook to make it play nice with
 | 
				
			||||||
    # ``trio``, see:
 | 
					    # ``trio``, see:
 | 
				
			||||||
    # https://github.com/python-trio/trio/issues/1155#issuecomment-742964018
 | 
					    # https://github.com/python-trio/trio/issues/1155#issuecomment-742964018
 | 
				
			||||||
    os.environ['PYTHONBREAKPOINT'] = 'tractor._debug._set_trace'
 | 
					    os.environ['PYTHONBREAKPOINT'] = 'tractor._debug._set_trace'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # attempt to retreive ``trio``'s sigint handler and stash it
 | 
				
			||||||
 | 
					    # on our debugger lock state.
 | 
				
			||||||
 | 
					    _debug.Lock._trio_handler = signal.getsignal(signal.SIGINT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # mark top most level process as root actor
 | 
					    # mark top most level process as root actor
 | 
				
			||||||
    _state._runtime_vars['_is_root'] = True
 | 
					    _state._runtime_vars['_is_root'] = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue