From fc72d7506145bfd26c5582efa899bdfeb6237d9e Mon Sep 17 00:00:00 2001 From: Tyler Goodlet Date: Thu, 22 Feb 2024 15:08:10 -0500 Subject: [PATCH] Support `maybe_wait_for_debugger(header_msg: str)` Allow callers to stick in a header to the `.pdb()` level emitted msg(s) such that any "waiting status" content is only shown if the caller actually get's blocked waiting for the debug lock; use it inside the `._spawn` sub-process reaper call. Also, return early if `Lock.global_actor_in_debug == None` and thus only enter the poll loop when actually needed, consequently raise if we fall through the loop without acquisition. --- tractor/_spawn.py | 7 +++-- tractor/devx/_debug.py | 71 +++++++++++++++++++++++++++--------------- 2 files changed, 50 insertions(+), 28 deletions(-) diff --git a/tractor/_spawn.py b/tractor/_spawn.py index 141d7c8..7f50b9e 100644 --- a/tractor/_spawn.py +++ b/tractor/_spawn.py @@ -541,13 +541,14 @@ async def trio_proc( with trio.move_on_after(0.5): await proc.wait() - log.pdb( - 'Delaying subproc reaper while debugger locked..' - ) await maybe_wait_for_debugger( child_in_debug=_runtime_vars.get( '_debug_mode', False ), + header_msg=( + 'Delaying subproc reaper while debugger locked..\n' + ), + # TODO: need a diff value then default? # poll_steps=9999999, ) diff --git a/tractor/devx/_debug.py b/tractor/devx/_debug.py index 43fd901..d3bf4fe 100644 --- a/tractor/devx/_debug.py +++ b/tractor/devx/_debug.py @@ -999,6 +999,8 @@ async def maybe_wait_for_debugger( poll_delay: float = 0.1, child_in_debug: bool = False, + header_msg: str = '', + ) -> None: if ( @@ -1007,6 +1009,8 @@ async def maybe_wait_for_debugger( ): return + + msg: str = header_msg if ( is_root_process() ): @@ -1016,48 +1020,59 @@ async def maybe_wait_for_debugger( # will make the pdb repl unusable. # Instead try to wait for pdb to be released before # tearing down. - sub_in_debug: tuple[str, str] | None = None + sub_in_debug: tuple[str, str]|None = Lock.global_actor_in_debug + debug_complete: trio.Event|None = Lock.no_remote_has_tty + + if sub_in_debug := Lock.global_actor_in_debug: + msg += ( + 'Debug `Lock` in use by subactor\n' + f'|_{sub_in_debug}\n' + ) + # TODO: could this make things more deterministic? + # wait to see if a sub-actor task will be + # scheduled and grab the tty lock on the next + # tick? + # XXX => but it doesn't seem to work.. + # await trio.testing.wait_all_tasks_blocked(cushion=0) + else: + log.pdb( + msg + + + 'Root immediately acquired debug TTY LOCK' + ) + return for istep in range(poll_steps): - if sub_in_debug := Lock.global_actor_in_debug: - log.pdb( - f'Lock in use by {sub_in_debug}' - ) - # TODO: could this make things more deterministic? - # wait to see if a sub-actor task will be - # scheduled and grab the tty lock on the next - # tick? - # XXX => but it doesn't seem to work.. - # await trio.testing.wait_all_tasks_blocked(cushion=0) - debug_complete: trio.Event|None = Lock.no_remote_has_tty if ( debug_complete and not debug_complete.is_set() and sub_in_debug is not None ): log.pdb( - 'Root has errored but pdb is in use by child\n' - 'Waiting on tty lock to release..\n' - f'uid: {sub_in_debug}\n' + msg + + + 'Root is waiting on tty lock to release..\n' ) await debug_complete.wait() log.pdb( - f'Child subactor released debug lock!\n' - f'uid: {sub_in_debug}\n' + f'Child subactor released debug lock:' + f'|_{sub_in_debug}\n' ) - if debug_complete.is_set(): - break # is no subactor locking debugger currently? - elif ( - debug_complete is None - or sub_in_debug is None + if ( + sub_in_debug is None + and ( + debug_complete is None + or debug_complete.is_set() + ) ): log.pdb( - 'Root acquired debug TTY LOCK from child\n' - f'uid: {sub_in_debug}' + msg + + + 'Root acquired tty lock!' ) break @@ -1073,8 +1088,14 @@ async def maybe_wait_for_debugger( with trio.CancelScope(shield=True): await trio.sleep(poll_delay) continue + + # fallthrough on failure to acquire.. else: - log.pdb('Root acquired debug TTY LOCK') + raise RuntimeError( + msg + + + 'Root actor failed to acquire debug lock?' + ) # else: # # TODO: non-root call for #320?