tractor/tractor
Gud Boi fc4fad0cc5 Refine `subint_forkserver` orphan-SIGINT diagnosis
Empirical follow-up to the xfail'd orphan-SIGINT test:
the hang is **not** "trio can't install a handler on a
non-main thread" (the original hypothesis from the
`child_sigint` scaffold commit). On py3.14:

- `threading.current_thread() is threading.main_thread()`
  IS True post-fork — CPython re-designates the
  fork-inheriting thread as "main" correctly
- trio's `KIManager` SIGINT handler IS installed in the
  subactor (`signal.getsignal(SIGINT)` confirms)
- the kernel DOES deliver SIGINT to the thread

But `faulthandler` dumps show the subactor wedged in
`trio/_core/_io_epoll.py::get_events` — trio's
wakeup-fd mechanism (which turns SIGINT into an epoll-wake)
isn't firing. So the `except KeyboardInterrupt` at
`tractor/spawn/_entry.py::_trio_main:164` — the runtime's
intentional "KBI-as-OS-cancel" path — never fires.

Deats,
- new `ai/conc-anal/subint_forkserver_orphan_sigint_hang_issue.md`
  (+385 LOC): full writeup — TL;DR, symptom reproducer,
  the "intentional cancel path" the bug defeats,
  diagnostic evidence (`faulthandler` output +
  `getsignal` probe), ruled-out hypotheses
  (non-main-thread issue, wakeup-fd inheritance,
  KBI-as-trio-check-exception), and fix directions
- `test_orphaned_subactor_sigint_cleanup_DRAFT` xfail
  `reason` + test docstring rewritten to match the
  refined understanding — old wording blamed the
  non-main-thread path, new wording points at the
  `epoll_wait` wedge + cross-refs the new conc-anal doc
- `_subint_forkserver` module docstring's
  `child_sigint='trio'` bullet updated: now notes trio's
  handler is already correctly installed, so the flag may
  end up a no-op / doc-only mode once the real root cause
  is fixed

Closing the gap aligns with existing design intent (make
the already-designed "KBI-as-OS-cancel" behavior actually
fire), not a new feature.

(this patch was generated in some part by [`claude-code`][claude-code-gh])
[claude-code-gh]: https://github.com/anthropics/claude-code

(cherry picked from commit a72deef709)
2026-06-22 14:55:34 -04:00
..
_testing Hoist proc-title prefix to `_def_prefix` const 2026-06-18 15:09:30 -04:00
devx Hoist proc-title prefix to `_def_prefix` const 2026-06-18 15:09:30 -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 Use `is not None` check for peer-connect `event` 2026-06-18 15:07:47 -04:00
msg Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00
runtime Code-style, couple newline/ws tweaks 2026-06-18 15:09:30 -04:00
spawn Refine `subint_forkserver` orphan-SIGINT diagnosis 2026-06-22 14:55:34 -04:00
trionics Add `supervise_run_process` to `trionics._subproc` 2026-06-18 15:07:47 -04:00
__init__.py Rename `discovery._discovery` to `._api` 2026-04-14 19:54:14 -04:00
_child.py Add per-actor `setproctitle` via `devx._proctitle` 2026-06-17 17:39:44 -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 Add `ActorTooSlowError` for cancel-cascade timeouts 2026-06-17 17:39:44 -04:00
_root.py Code-style, couple newline/ws tweaks 2026-06-18 15:09:30 -04:00
_streaming.py Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00
log.py Add `add_log_level()` factory + register `IO`=21 2026-06-18 15:09:30 -04:00
to_asyncio.py Add `maybe_signal_aio_task()` + cause-chain guard 2026-06-17 17:39:44 -04:00