Factor sigint overriding into lock methods
							parent
							
								
									e6ad7a117b
								
							
						
					
					
						commit
						fa21083b51
					
				|  | @ -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