tractor/tractor
Gud Boi 2d4995e08d Route `stackscope` SIGUSR1 onto trio loop
Signal handlers fire in a non-trio stack frame; calling
`stackscope.extract(recurse_child_tasks=True)` from there
only walks the `<init>` task and misses everything inside
`async_main`'s nurseries — exactly the part you want to
see during a hang.

Fix: capture `trio.lowlevel.current_trio_token()` at
`enable_stack_on_sig()` time and stash it as a module-
level `_trio_token`. The SIGUSR1 handler then dispatches
the dump *onto* the trio loop via
`_trio_token.run_sync_soon(_safe_dump_task_tree)`, so
`stackscope.extract` runs from a real trio-task context
and walks the full nursery tree.

Late-binding: pytest's `pytest_configure` calls
`enable_stack_on_sig()` outside any `trio.run`, so token
capture there is a `RuntimeError` — left at `None`. The
runtime re-calls `enable_stack_on_sig()` from inside
`async_main` (subactor side) where the token IS
available, so subactors get the full-tree path.
`dump_tree_on_sig` falls back to a direct call when
`_trio_token is None` (parent process pre-trio.run, or
signal delivered after `trio.run` returns).

`_safe_dump_task_tree()` is a `run_sync_soon`-friendly
wrapper that swallows any exception from
`dump_task_tree()` — trio prints + crashes on uncaught
exceptions in scheduled callbacks; better to log + keep
the run alive so the user can re-trigger.

Other,
- emit `capture-bypass tee: <fpath>` line + `tail -f`
  hint in the rendered dump header so users know where
  to find the artifact even when stdio is captured.
- swap the inline `f'     |_{actor}'` line for a
  `_pformat.nest_from_op` rendering of `actor_repr`
  (matches the rest of the runtime's nested-op style).
- log lines on handler install + already-installed
  branches now note `(trio_token captured: <bool>)`
  so it's obvious from the log whether the full-tree
  path is wired.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code
2026-04-29 12:01:03 -04:00
..
_testing Add `--enable-stackscope` pytest plugin flag 2026-04-29 10:32:23 -04:00
devx Route `stackscope` SIGUSR1 onto trio loop 2026-04-29 12:01:03 -04:00
discovery Fix misc bugs caught by Copilot review 2026-04-14 19:54:15 -04:00
experimental Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00
ipc Fix `SharedMemory` under `subint_forkserver` 2026-04-27 10:51:28 -04:00
msg Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00
runtime Add `--enable-stackscope` pytest plugin flag 2026-04-29 10:32:23 -04:00
spawn Refine fork-survival docs + `EBADF` handling 2026-04-29 10:34:33 -04:00
trionics Drop commented-out `tractor.pause()` debug hooks 2026-04-09 17:41:28 -04:00
__init__.py Rename `discovery._discovery` to `._api` 2026-04-14 19:54:14 -04:00
_child.py Impl min-viable `subint` spawn backend (B.2) 2026-04-23 18:47:49 -04:00
_clustering.py Use `.aid.uid` to avoid deprecation warns 2026-03-13 21:10:52 -04:00
_code_load.py Mv `load_module_from_path()` to a new `._code_load` submod 2026-02-11 21:03:29 -05:00
_context.py Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00
_exceptions.py Fix `Type[BaseException]` annots, guard `.src_type` resolve 2026-04-02 18:21:19 -04:00
_root.py Sweep `subint_forkserver` → `main_thread_forkserver` in code 2026-04-27 19:55:37 -04:00
_streaming.py Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00
log.py Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00
to_asyncio.py Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00