forked from goodboy/tractor
Factor lock-state release logic into helper
The common logic to both remove our custom SIGINT handler as well as signal the actor global event that pdb is complete. Call this whenever we exit a post mortem call and thus any time some rpc task get's debugged inside `._actor._invoke()`. Further, we have to manually print the REPL prompt on 3.9 for some wack reason, so stick a version guard in the sigint handler for that..signint_saviour
parent
bd362a05f0
commit
b01daa5319
|
@ -97,34 +97,23 @@ class MultiActorPdb(pdbpp.Pdb):
|
||||||
# override the pdbpp config with our coolio one
|
# override the pdbpp config with our coolio one
|
||||||
DefaultConfig = TractorConfig
|
DefaultConfig = TractorConfig
|
||||||
|
|
||||||
|
# def preloop(self):
|
||||||
|
# print('IN PRELOOP')
|
||||||
|
# super().preloop()
|
||||||
|
|
||||||
# TODO: figure out how to disallow recursive .set_trace() entry
|
# TODO: figure out how to disallow recursive .set_trace() entry
|
||||||
# since that'll cause deadlock for us.
|
# since that'll cause deadlock for us.
|
||||||
def set_continue(self):
|
def set_continue(self):
|
||||||
try:
|
try:
|
||||||
super().set_continue()
|
super().set_continue()
|
||||||
finally:
|
finally:
|
||||||
global _local_task_in_debug, _pdb_release_hook
|
maybe_release()
|
||||||
_local_task_in_debug = None
|
|
||||||
if _pdb_release_hook:
|
|
||||||
_pdb_release_hook()
|
|
||||||
|
|
||||||
def set_quit(self):
|
def set_quit(self):
|
||||||
try:
|
try:
|
||||||
super().set_quit()
|
super().set_quit()
|
||||||
finally:
|
finally:
|
||||||
global _local_task_in_debug, _pdb_release_hook
|
maybe_release()
|
||||||
_local_task_in_debug = None
|
|
||||||
if _pdb_release_hook:
|
|
||||||
_pdb_release_hook()
|
|
||||||
|
|
||||||
def set_next(self, frame):
|
|
||||||
try:
|
|
||||||
super().set_next(frame)
|
|
||||||
finally:
|
|
||||||
global _local_task_in_debug, _pdb_release_hook
|
|
||||||
_local_task_in_debug = None
|
|
||||||
if _pdb_release_hook:
|
|
||||||
_pdb_release_hook()
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: will be needed whenever we get to true remote debugging.
|
# TODO: will be needed whenever we get to true remote debugging.
|
||||||
|
@ -163,6 +152,13 @@ class MultiActorPdb(pdbpp.Pdb):
|
||||||
# log.info("Closing stdin hijack")
|
# log.info("Closing stdin hijack")
|
||||||
# break
|
# break
|
||||||
|
|
||||||
|
# TODO: make this method on a global lock type!
|
||||||
|
def maybe_release():
|
||||||
|
global _local_task_in_debug, _pdb_release_hook
|
||||||
|
_local_task_in_debug = None
|
||||||
|
if _pdb_release_hook:
|
||||||
|
_pdb_release_hook()
|
||||||
|
|
||||||
|
|
||||||
@acm
|
@acm
|
||||||
async def _acquire_debug_lock(
|
async def _acquire_debug_lock(
|
||||||
|
@ -392,10 +388,10 @@ async def wait_for_parent_stdin_hijack(
|
||||||
log.warning('Root actor cancelled debug lock')
|
log.warning('Root actor cancelled debug lock')
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
log.debug(f"Exiting debugger for actor {actor_uid}")
|
log.pdb(f"Exiting debugger for actor {actor_uid}")
|
||||||
global _local_task_in_debug
|
global _local_task_in_debug
|
||||||
_local_task_in_debug = None
|
_local_task_in_debug = None
|
||||||
log.debug(f"Child {actor_uid} released parent stdio lock")
|
log.pdb(f"Child {actor_uid} released parent stdio lock")
|
||||||
|
|
||||||
|
|
||||||
def mk_mpdb() -> tuple[MultiActorPdb, Callable]:
|
def mk_mpdb() -> tuple[MultiActorPdb, Callable]:
|
||||||
|
@ -477,7 +473,7 @@ async def _breakpoint(
|
||||||
# entries/requests to the root process
|
# entries/requests to the root process
|
||||||
_local_task_in_debug = task_name
|
_local_task_in_debug = task_name
|
||||||
|
|
||||||
def child_release_hook():
|
def child_release():
|
||||||
try:
|
try:
|
||||||
# sometimes the ``trio`` might already be termianated in
|
# sometimes the ``trio`` might already be termianated in
|
||||||
# which case this call will raise.
|
# which case this call will raise.
|
||||||
|
@ -489,8 +485,7 @@ async def _breakpoint(
|
||||||
# _local_task_in_debug = None
|
# _local_task_in_debug = None
|
||||||
|
|
||||||
# assign unlock callback for debugger teardown hooks
|
# assign unlock callback for debugger teardown hooks
|
||||||
# _pdb_release_hook = _local_pdb_complete.set
|
_pdb_release_hook = child_release
|
||||||
_pdb_release_hook = child_release_hook
|
|
||||||
|
|
||||||
# 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
|
||||||
|
@ -507,7 +502,7 @@ async def _breakpoint(
|
||||||
actor.uid,
|
actor.uid,
|
||||||
)
|
)
|
||||||
except RuntimeError:
|
except RuntimeError:
|
||||||
child_release_hook()
|
_pdb_release_hook()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
elif is_root_process():
|
elif is_root_process():
|
||||||
|
@ -541,7 +536,7 @@ async def _breakpoint(
|
||||||
_local_task_in_debug = task_name
|
_local_task_in_debug = task_name
|
||||||
|
|
||||||
# the lock must be released on pdb completion
|
# the lock must be released on pdb completion
|
||||||
def teardown():
|
def root_release():
|
||||||
global _local_pdb_complete, _debug_lock
|
global _local_pdb_complete, _debug_lock
|
||||||
global _global_actor_in_debug, _local_task_in_debug
|
global _global_actor_in_debug, _local_task_in_debug
|
||||||
|
|
||||||
|
@ -566,11 +561,7 @@ async def _breakpoint(
|
||||||
# restore original sigint handler
|
# restore original sigint handler
|
||||||
undo_sigint()
|
undo_sigint()
|
||||||
|
|
||||||
_pdb_release_hook = teardown
|
_pdb_release_hook = root_release
|
||||||
|
|
||||||
# frame = sys._getframe()
|
|
||||||
# last_f = frame.f_back
|
|
||||||
# last_f.f_globals['__tracebackhide__'] = True
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# block here one (at the appropriate frame *up*) where
|
# block here one (at the appropriate frame *up*) where
|
||||||
|
@ -579,15 +570,13 @@ async def _breakpoint(
|
||||||
debug_func(actor, pdb)
|
debug_func(actor, pdb)
|
||||||
|
|
||||||
except bdb.BdbQuit:
|
except bdb.BdbQuit:
|
||||||
if _pdb_release_hook:
|
maybe_release()
|
||||||
_pdb_release_hook()
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# XXX: apparently we can't do this without showing this frame
|
# XXX: apparently we can't do this without showing this frame
|
||||||
# in the backtrace on first entry to the REPL? Seems like an odd
|
# in the backtrace on first entry to the REPL? Seems like an odd
|
||||||
# behaviour that should have been fixed by now. This is also why
|
# behaviour that should have been fixed by now. This is also why
|
||||||
# we scrapped all the @cm approaches that were tried previously.
|
# we scrapped all the @cm approaches that were tried previously.
|
||||||
|
|
||||||
# finally:
|
# finally:
|
||||||
# __tracebackhide__ = True
|
# __tracebackhide__ = True
|
||||||
# # frame = sys._getframe()
|
# # frame = sys._getframe()
|
||||||
|
@ -711,8 +700,10 @@ def shield_sigint(
|
||||||
# will be repeated by default.
|
# will be repeated by default.
|
||||||
|
|
||||||
# TODO: maybe redraw/print last REPL output to console
|
# TODO: maybe redraw/print last REPL output to console
|
||||||
# if pdb_obj:
|
if (
|
||||||
|
pdb_obj
|
||||||
|
and sys.version_info <= (3, 10)
|
||||||
|
):
|
||||||
# TODO: make this work like sticky mode where if there is output
|
# TODO: make this work like sticky mode where if there is output
|
||||||
# detected as written to the tty we redraw this part underneath
|
# detected as written to the tty we redraw this part underneath
|
||||||
# and erase the past draw of this same bit above?
|
# and erase the past draw of this same bit above?
|
||||||
|
@ -732,7 +723,7 @@ def shield_sigint(
|
||||||
# pdb_obj.do_longlist(None)
|
# pdb_obj.do_longlist(None)
|
||||||
|
|
||||||
# XXX: we were doing this but it shouldn't be required..
|
# XXX: we were doing this but it shouldn't be required..
|
||||||
# print(pdb_obj.prompt, end='', flush=True)
|
print(pdb_obj.prompt, end='', flush=True)
|
||||||
|
|
||||||
|
|
||||||
def _set_trace(
|
def _set_trace(
|
||||||
|
@ -838,6 +829,7 @@ async def _maybe_enter_pm(err):
|
||||||
):
|
):
|
||||||
log.debug("Actor crashed, entering debug mode")
|
log.debug("Actor crashed, entering debug mode")
|
||||||
await post_mortem()
|
await post_mortem()
|
||||||
|
maybe_release()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
else:
|
else:
|
||||||
|
@ -897,9 +889,11 @@ async def maybe_wait_for_debugger(
|
||||||
|
|
||||||
if _global_actor_in_debug:
|
if _global_actor_in_debug:
|
||||||
sub_in_debug = tuple(_global_actor_in_debug)
|
sub_in_debug = tuple(_global_actor_in_debug)
|
||||||
|
# alive = tractor.current_actor().child_alive(sub_in_debug)
|
||||||
|
# if not alive:
|
||||||
|
# break
|
||||||
|
|
||||||
log.debug(
|
log.debug('Root polling for debug')
|
||||||
'Root polling for debug')
|
|
||||||
|
|
||||||
with trio.CancelScope(shield=True):
|
with trio.CancelScope(shield=True):
|
||||||
await trio.sleep(poll_delay)
|
await trio.sleep(poll_delay)
|
||||||
|
|
Loading…
Reference in New Issue