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