Deadlock when using `start_blocking_portal("trio")` on trio
- Langage dominant
- Python
- Étoiles
- 2.5k
- Forks
- 260
- Merge moyen
- 1 j 8 h
- PR mergées (30 j)
- 17
Description
reproducer: cd9deb1e20dcb3e84bf6adcd8d9d22266ce31d0e.
this is because the trio implementation of `BlockingPortal._spawn_task_from_thread` uses `trio.from_thread.run_sync`. `trio.from_thread.run_sync` is not allowed to be called from trio threads because it can cause deadlocks[^1].
[^1]: https://github.com/python-trio/trio/blob/4286063466aade470d531ddfb42664f07ae38583/trio/_threads.py#L248-L254
one way to fix this is by switching the trio implementation of `BlockingPortal._spawn_task_from_thread` from using `trio.from_thread.run_sync(BlockingPortal._task_group.start_soon, ..., trio_token=...)` to using `TrioToken.run_sync_soon(BlockingPortal._task_group.start_soon, ...)`. the downside of this change is that it would change what happens if `TaskGroup.start_soon` fails:
* with `trio.from_thread.run_sync(BlockingPortal._task_group.start_soon, ..., trio_token=...)`, if `TaskGroup.start_soon` raises it gets propagated to the `anyio.from_thread.run(_sync)?` call site.
* with `TrioToken.run_sync_soon(BlockingPortal._task_group.start_soon, ...)`, if `TaskGroup.start_soon` raises it gets propagated up and crashes the portal's event loop.
that isn't ideal, so better options for fixing this, i _think_, are:
1. switch `_trio.BlockingPortal._spawn_task_from_thread` from using `trio.from_thread.run_sync(BlockingPortal._task_group.start_soon, ..., trio_token=...)` to using `TrioToken.run_sync_soon(wrapper, ...)`, where `wrapper` is essentially just `disable_ki_protection(AsyncioBackend.run_sync_from_thread..wrapper)`.
this is more-or-less equivalent to writing a version of `TrioBackend.run_sync_from_thread` that has a relaxed deadlock heuristic.
1. (in trio) relax the deadlock heuristic: see https://github.com/python-trio/trio/issues/2534
Guide de contribution
Ouvrir le guide de contribution
Évaluation
Cette issue n'a pas encore été évaluée.