forked from goodboy/tractor
Always restore the `trio` SIGINT handler
Pretty sure this is the final touch to alleviate all our debug lock headaches! Instead of trying to revert to the "last" handler (as `pdb` does internally in the stdlib) we always just revert to the handler `trio` registers during startup. Further this seems to allow cancelling the root-side locking task if it's detected as stale IFF we only do this when the root actor is in a "no more IPC peers" state. Deatz: - always `._debug.Lock._trio_handler` as the `trio` version, not some last used handler to make sure we're getting the ctrl-c handling we want when not in debug mode. - assign the trio handler in `open_root_actor()` `._runtime._async_main()` to be sure it's applied in subactors as well as the root. - only do debug lock blocking and root-side-locking-task cancels when a "no peers" condition is detected in the root actor: i.e. no IPC channels are detected by the root meaning it's impossible any actor has a sane lock-state ongoing for debug mode.egs_with_ctx_res_consumption
parent
f6ac0c2eb7
commit
c5091afa38
|
@ -107,16 +107,16 @@ class Lock:
|
|||
@classmethod
|
||||
def shield_sigint(cls):
|
||||
cls._orig_sigint_handler = signal.signal(
|
||||
signal.SIGINT,
|
||||
shield_sigint,
|
||||
)
|
||||
signal.SIGINT,
|
||||
shield_sigint,
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def unshield_sigint(cls):
|
||||
# always restore (some) sigint handler, either
|
||||
# the prior or at least ``trio``'s.
|
||||
orig = cls._orig_sigint_handler or cls._trio_handler
|
||||
signal.signal(signal.SIGINT, orig)
|
||||
# always restore ``trio``'s sigint handler. see notes below in
|
||||
# the pdb factory about the nightmare that is that code swapping
|
||||
# out the handler when the repl activates...
|
||||
signal.signal(signal.SIGINT, cls._trio_handler)
|
||||
cls._orig_sigint_handler = None
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -34,7 +34,11 @@ import warnings
|
|||
from exceptiongroup import BaseExceptionGroup
|
||||
import trio
|
||||
|
||||
from ._runtime import Actor, Arbiter, async_main
|
||||
from ._runtime import (
|
||||
Actor,
|
||||
Arbiter,
|
||||
async_main,
|
||||
)
|
||||
from . import _debug
|
||||
from . import _spawn
|
||||
from . import _state
|
||||
|
@ -88,7 +92,7 @@ async def open_root_actor(
|
|||
|
||||
# attempt to retreive ``trio``'s sigint handler and stash it
|
||||
# on our debugger lock state.
|
||||
_debug.Lock._trio_handler = signal.getsignal(signal.SIGINT)
|
||||
_debug.Lock._trio_handler = signal.getsignal(signal.SIGINT)
|
||||
|
||||
# mark top most level process as root actor
|
||||
_state._runtime_vars['_is_root'] = True
|
||||
|
|
|
@ -25,14 +25,15 @@ from itertools import chain
|
|||
import importlib
|
||||
import importlib.util
|
||||
import inspect
|
||||
import uuid
|
||||
import signal
|
||||
import sys
|
||||
from typing import (
|
||||
Any, Optional,
|
||||
Union, TYPE_CHECKING,
|
||||
Callable,
|
||||
)
|
||||
import uuid
|
||||
from types import ModuleType
|
||||
import sys
|
||||
import os
|
||||
from contextlib import ExitStack
|
||||
import warnings
|
||||
|
@ -709,6 +710,14 @@ class Actor:
|
|||
log.runtime(f"No more channels for {chan.uid}")
|
||||
self._peers.pop(uid, None)
|
||||
|
||||
log.runtime(f"Peers is {self._peers}")
|
||||
|
||||
# No more channels to other actors (at all) registered
|
||||
# as connected.
|
||||
if not self._peers:
|
||||
log.runtime("Signalling no more peer channel connections")
|
||||
self._no_more_peers.set()
|
||||
|
||||
# NOTE: block this actor from acquiring the
|
||||
# debugger-TTY-lock since we have no way to know if we
|
||||
# cancelled it and further there is no way to ensure the
|
||||
|
@ -722,23 +731,16 @@ class Actor:
|
|||
# if a now stale local task has the TTY lock still
|
||||
# we cancel it to allow servicing other requests for
|
||||
# the lock.
|
||||
db_cs = pdb_lock._root_local_task_cs_in_debug
|
||||
if (
|
||||
pdb_lock._root_local_task_cs_in_debug
|
||||
and not pdb_lock._root_local_task_cs_in_debug.cancel_called
|
||||
db_cs
|
||||
and not db_cs.cancel_called
|
||||
):
|
||||
log.warning(
|
||||
f'STALE DEBUG LOCK DETECTED FOR {uid}'
|
||||
)
|
||||
# TODO: figure out why this breaks tests..
|
||||
# pdb_lock._root_local_task_cs_in_debug.cancel()
|
||||
|
||||
log.runtime(f"Peers is {self._peers}")
|
||||
|
||||
# No more channels to other actors (at all) registered
|
||||
# as connected.
|
||||
if not self._peers:
|
||||
log.runtime("Signalling no more peer channel connections")
|
||||
self._no_more_peers.set()
|
||||
pdb_lock._root_local_task_cs_in_debug.cancel()
|
||||
|
||||
# XXX: is this necessary (GC should do it)?
|
||||
if chan.connected():
|
||||
|
@ -1229,6 +1231,10 @@ async def async_main(
|
|||
and when cancelled effectively cancels the actor.
|
||||
|
||||
'''
|
||||
# attempt to retreive ``trio``'s sigint handler and stash it
|
||||
# on our debugger lock state.
|
||||
_debug.Lock._trio_handler = signal.getsignal(signal.SIGINT)
|
||||
|
||||
registered_with_arbiter = False
|
||||
try:
|
||||
|
||||
|
|
Loading…
Reference in New Issue