forked from goodboy/tractor
Factor sigint overriding into lock methods
parent
91f034a136
commit
937ed99e39
|
@ -33,7 +33,6 @@ from typing import (
|
||||||
)
|
)
|
||||||
from types import FrameType
|
from types import FrameType
|
||||||
|
|
||||||
from msgspec import Struct
|
|
||||||
import tractor
|
import tractor
|
||||||
import trio
|
import trio
|
||||||
from trio_typing import TaskStatus
|
from trio_typing import TaskStatus
|
||||||
|
@ -88,12 +87,55 @@ class Lock:
|
||||||
# otherwise deadlocks with the parent actor may ensure
|
# otherwise deadlocks with the parent actor may ensure
|
||||||
_debugger_request_cs: Optional[trio.CancelScope] = None
|
_debugger_request_cs: Optional[trio.CancelScope] = None
|
||||||
|
|
||||||
|
_orig_sigint_handler: Optional[Callable] = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def shield_sigint(cls):
|
||||||
|
cls._orig_sigint_handler = signal.signal(
|
||||||
|
signal.SIGINT,
|
||||||
|
shield_sigint,
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def unshield_sigint(cls):
|
||||||
|
if cls._orig_sigint_handler is not None:
|
||||||
|
# restore original sigint handler
|
||||||
|
signal.signal(
|
||||||
|
signal.SIGINT,
|
||||||
|
cls._orig_sigint_handler
|
||||||
|
)
|
||||||
|
|
||||||
|
cls._orig_sigint_handler = None
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def maybe_release(cls):
|
def maybe_release(cls):
|
||||||
cls.local_task_in_debug = None
|
cls.local_task_in_debug = None
|
||||||
if cls.pdb_release_hook:
|
if cls.pdb_release_hook:
|
||||||
cls.pdb_release_hook()
|
cls.pdb_release_hook()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def root_release(cls):
|
||||||
|
try:
|
||||||
|
cls._debug_lock.release()
|
||||||
|
except RuntimeError:
|
||||||
|
# uhhh makes no sense but been seeing the non-owner
|
||||||
|
# release error even though this is definitely the task
|
||||||
|
# that locked?
|
||||||
|
owner = cls._debug_lock.statistics().owner
|
||||||
|
if owner:
|
||||||
|
raise
|
||||||
|
|
||||||
|
cls.global_actor_in_debug = None
|
||||||
|
cls.local_task_in_debug = None
|
||||||
|
|
||||||
|
try:
|
||||||
|
# sometimes the ``trio`` might already be terminated in
|
||||||
|
# which case this call will raise.
|
||||||
|
cls.local_pdb_complete.set()
|
||||||
|
finally:
|
||||||
|
# restore original sigint handler
|
||||||
|
cls.unshield_sigint()
|
||||||
|
|
||||||
|
|
||||||
class TractorConfig(pdbpp.DefaultConfig):
|
class TractorConfig(pdbpp.DefaultConfig):
|
||||||
"""Custom ``pdbpp`` goodness.
|
"""Custom ``pdbpp`` goodness.
|
||||||
|
@ -274,11 +316,8 @@ async def _hijack_stdin_for_child(
|
||||||
)
|
)
|
||||||
|
|
||||||
log.debug(f"Actor {subactor_uid} is WAITING on stdin hijack lock")
|
log.debug(f"Actor {subactor_uid} is WAITING on stdin hijack lock")
|
||||||
|
Lock.shield_sigint()
|
||||||
|
|
||||||
orig_handler = signal.signal(
|
|
||||||
signal.SIGINT,
|
|
||||||
shield_sigint,
|
|
||||||
)
|
|
||||||
try:
|
try:
|
||||||
with (
|
with (
|
||||||
trio.CancelScope(shield=True),
|
trio.CancelScope(shield=True),
|
||||||
|
@ -330,10 +369,7 @@ async def _hijack_stdin_for_child(
|
||||||
return "pdb_unlock_complete"
|
return "pdb_unlock_complete"
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
signal.signal(
|
Lock.unshield_sigint()
|
||||||
signal.SIGINT,
|
|
||||||
orig_handler
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
async def wait_for_parent_stdin_hijack(
|
async def wait_for_parent_stdin_hijack(
|
||||||
|
@ -399,10 +435,8 @@ def mk_mpdb() -> tuple[MultiActorPdb, Callable]:
|
||||||
|
|
||||||
pdb = MultiActorPdb()
|
pdb = MultiActorPdb()
|
||||||
# signal.signal = pdbpp.hideframe(signal.signal)
|
# signal.signal = pdbpp.hideframe(signal.signal)
|
||||||
orig_handler = signal.signal(
|
|
||||||
signal.SIGINT,
|
Lock.shield_sigint()
|
||||||
partial(shield_sigint, pdb_obj=pdb),
|
|
||||||
)
|
|
||||||
|
|
||||||
# XXX: These are the important flags mentioned in
|
# XXX: These are the important flags mentioned in
|
||||||
# https://github.com/python-trio/trio/issues/1155
|
# https://github.com/python-trio/trio/issues/1155
|
||||||
|
@ -410,15 +444,7 @@ def mk_mpdb() -> tuple[MultiActorPdb, Callable]:
|
||||||
pdb.allow_kbdint = True
|
pdb.allow_kbdint = True
|
||||||
pdb.nosigint = True
|
pdb.nosigint = True
|
||||||
|
|
||||||
# TODO: add this as method on our pdb obj?
|
return pdb, Lock.unshield_sigint
|
||||||
def undo_sigint():
|
|
||||||
# restore original sigint handler
|
|
||||||
signal.signal(
|
|
||||||
signal.SIGINT,
|
|
||||||
orig_handler
|
|
||||||
)
|
|
||||||
|
|
||||||
return pdb, undo_sigint
|
|
||||||
|
|
||||||
|
|
||||||
async def _breakpoint(
|
async def _breakpoint(
|
||||||
|
@ -484,7 +510,6 @@ async def _breakpoint(
|
||||||
|
|
||||||
# assign unlock callback for debugger teardown hooks
|
# assign unlock callback for debugger teardown hooks
|
||||||
Lock.pdb_release_hook = child_release
|
Lock.pdb_release_hook = child_release
|
||||||
# _pdb_release_hook = child_release
|
|
||||||
|
|
||||||
# this **must** be awaited by the caller and is done using the
|
# this **must** be awaited by the caller and is done using the
|
||||||
# root nursery so that the debugger can continue to run without
|
# root nursery so that the debugger can continue to run without
|
||||||
|
@ -502,7 +527,6 @@ async def _breakpoint(
|
||||||
)
|
)
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
Lock.pdb_release_hook()
|
Lock.pdb_release_hook()
|
||||||
# _pdb_release_hook()
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
elif is_root_process():
|
elif is_root_process():
|
||||||
|
@ -534,30 +558,7 @@ async def _breakpoint(
|
||||||
Lock.local_task_in_debug = task_name
|
Lock.local_task_in_debug = task_name
|
||||||
|
|
||||||
# the lock must be released on pdb completion
|
# the lock must be released on pdb completion
|
||||||
def root_release():
|
Lock.pdb_release_hook = Lock.root_release
|
||||||
try:
|
|
||||||
Lock._debug_lock.release()
|
|
||||||
except RuntimeError:
|
|
||||||
# uhhh makes no sense but been seeing the non-owner
|
|
||||||
# release error even though this is definitely the task
|
|
||||||
# that locked?
|
|
||||||
owner = Lock._debug_lock.statistics().owner
|
|
||||||
if owner:
|
|
||||||
raise
|
|
||||||
|
|
||||||
Lock.global_actor_in_debug = None
|
|
||||||
Lock.local_task_in_debug = None
|
|
||||||
|
|
||||||
try:
|
|
||||||
# sometimes the ``trio`` might already be termianated in
|
|
||||||
# which case this call will raise.
|
|
||||||
Lock.local_pdb_complete.set()
|
|
||||||
finally:
|
|
||||||
# restore original sigint handler
|
|
||||||
undo_sigint()
|
|
||||||
|
|
||||||
# _pdb_release_hook = root_release
|
|
||||||
Lock.pdb_release_hook = root_release
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# block here one (at the appropriate frame *up*) where
|
# block here one (at the appropriate frame *up*) where
|
||||||
|
|
Loading…
Reference in New Issue