tractor/tractor
Gud Boi 17d968723d Fix subint destroy race via dedicated OS thread
`trio.to_thread.run_sync(_interpreters.exec, ...)` runs `exec()` on
a cached worker thread — and when that thread is returned to the
cache after the subint's `trio.run()` exits, CPython still keeps
the subint's tstate attached to the (now idle) worker. Result: the
teardown `_interpreters.destroy(interp_id)` in the `finally` block
can block the parent's trio loop indefinitely, waiting for a tstate
release that only happens when the worker either picks up a new job
or exits.

Manifested as intermittent mid-suite hangs under
`--spawn-backend=subint` — caught by a
`faulthandler.dump_traceback_later()` showing the main thread stuck
in `_interpreters.destroy()` at `_subint.py:293` with only an idle
trio-cache worker as the other live thread.

Deats,
- drive the subint on a plain `threading.Thread` (not
  `trio.to_thread`) so the OS thread truly exits after
  `_interpreters.exec()` returns, releasing tstate and unblocking
  destroy
- signal `subint_exited.set()` back to the parent trio loop from
  the driver thread via `trio.from_thread.run_sync(...,
  trio_token=...)` — capture the token at `subint_proc` entry
- swallow `trio.RunFinishedError` in that signal path for the case
  where parent trio has already exited (proc teardown)
- in the teardown `finally`, off-load the sync
  `driver_thread.join()` to `trio.to_thread.run_sync` (cache thread
  w/ no subint tstate → safe) so we actually wait for the driver to
  exit before `_interpreters.destroy()`

(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 31cbd11a5b)
2026-06-22 14:53:31 -04:00
..
_testing Add autouse fixture to reset `_runtime_vars` per-test 2026-06-17 17:39:44 -04:00
devx Address Copilot review nits on PR #462 2026-06-18 13:37:55 -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 Address Copilot review nits on PR #462 2026-06-18 13:37:55 -04:00
msg Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00
runtime Address Copilot review nits on PR #462 2026-06-18 13:37:55 -04:00
spawn Fix subint destroy race via dedicated OS thread 2026-06-22 14:53:31 -04:00
trionics Add `tractor.trionics.patches` subpkg + first fix 2026-06-17 17:39:44 -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 Fix dead-code env-var override notice in `open_root_actor` 2026-06-17 19:46:43 -04:00
_streaming.py Mv core mods to `runtime/`, `spawn/`, `discovery/` subpkgs 2026-04-02 17:59:13 -04:00
log.py Fix `get_logger()` collapse of nested sub-pkgs 2026-06-17 17:39:44 -04:00
to_asyncio.py Add `maybe_signal_aio_task()` + cause-chain guard 2026-06-17 17:39:44 -04:00