forked from goodboy/tractor
82 lines
2.0 KiB
Python
82 lines
2.0 KiB
Python
'''
|
|
Verify we can dump a `stackscope` tree on a hang.
|
|
|
|
'''
|
|
import os
|
|
import signal
|
|
|
|
import trio
|
|
import tractor
|
|
|
|
@tractor.context
|
|
async def start_n_shield_hang(
|
|
ctx: tractor.Context,
|
|
):
|
|
# actor: tractor.Actor = tractor.current_actor()
|
|
|
|
# sync to parent-side task
|
|
await ctx.started(os.getpid())
|
|
|
|
print('Entering shield sleep..')
|
|
with trio.CancelScope(shield=True):
|
|
await trio.sleep_forever() # in subactor
|
|
|
|
# XXX NOTE ^^^ since this shields, we expect
|
|
# the zombie reaper (aka T800) to engage on
|
|
# SIGINT from the user and eventually hard-kill
|
|
# this subprocess!
|
|
|
|
|
|
async def main(
|
|
from_test: bool = False,
|
|
) -> None:
|
|
|
|
async with (
|
|
tractor.open_nursery(
|
|
debug_mode=True,
|
|
enable_stack_on_sig=True,
|
|
# maybe_enable_greenback=False,
|
|
loglevel='devx',
|
|
) as an,
|
|
):
|
|
|
|
ptl: tractor.Portal = await an.start_actor(
|
|
'hanger',
|
|
enable_modules=[__name__],
|
|
debug_mode=True,
|
|
)
|
|
async with ptl.open_context(
|
|
start_n_shield_hang,
|
|
) as (ctx, cpid):
|
|
|
|
_, proc, _ = an._children[ptl.chan.uid]
|
|
assert cpid == proc.pid
|
|
|
|
print(
|
|
'Yo my child hanging..?\n'
|
|
'Sending SIGUSR1 to see a tree-trace!\n'
|
|
)
|
|
|
|
# XXX simulate the wrapping test's "user actions"
|
|
# (i.e. if a human didn't run this manually but wants to
|
|
# know what they should do to reproduce test behaviour)
|
|
if from_test:
|
|
os.kill(
|
|
cpid,
|
|
signal.SIGUSR1,
|
|
)
|
|
|
|
# simulate user cancelling program
|
|
await trio.sleep(0.5)
|
|
os.kill(
|
|
os.getpid(),
|
|
signal.SIGINT,
|
|
)
|
|
else:
|
|
# actually let user send the ctl-c
|
|
await trio.sleep_forever() # in root
|
|
|
|
|
|
if __name__ == '__main__':
|
|
trio.run(main)
|