From 4c5884001a3542cbb4671de643ae20c014adf4bb Mon Sep 17 00:00:00 2001 From: A5rocks Date: Mon, 27 Jul 2026 00:47:27 +0900 Subject: [PATCH 1/2] Run GC on PyPy more for test_worker_thread_context_not_leaked --- src/trio/_tests/test_threads.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/trio/_tests/test_threads.py b/src/trio/_tests/test_threads.py index 532a20d36..f349850ff 100644 --- a/src/trio/_tests/test_threads.py +++ b/src/trio/_tests/test_threads.py @@ -1,7 +1,6 @@ from __future__ import annotations import contextvars -import gc import queue as stdlib_queue import re import sys @@ -29,7 +28,7 @@ sleep_forever, ) from .._core._tests.test_ki import ki_self -from .._core._tests.tutil import slow +from .._core._tests.tutil import gc_collect_harder, slow from .._threads import ( active_thread_count, current_default_thread_limiter, @@ -705,7 +704,8 @@ def sync_fn() -> None: cvar.set(Foo()) del contextval - gc.collect() + if sys.implementation.name == "pypy": + gc_collect_harder() assert ref() is None From 33e2594ff512948a8b1bdbfe3ae8d0c27130c82f Mon Sep 17 00:00:00 2001 From: A5rocks Date: Tue, 28 Jul 2026 21:20:06 +0900 Subject: [PATCH 2/2] Actually, simply make sure any referrers are deleted --- src/trio/_core/_thread_cache.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/trio/_core/_thread_cache.py b/src/trio/_core/_thread_cache.py index f48aa8eab..3d044d6de 100644 --- a/src/trio/_core/_thread_cache.py +++ b/src/trio/_core/_thread_cache.py @@ -188,6 +188,13 @@ def _handle_job(self) -> None: if set_os_thread_name: set_os_thread_name(self._thread.ident, self._default_name) + # Without this, this thread may get rescheduled after `deliver` + # and only return after the kernel gets around to it. That's an + # arbitrary amount of time during which we keep anything + # referred to in the function alive, like contextvars. That's + # surprising! + del fn + # Tell the cache that we're available to be assigned a new # job. We do this *before* calling 'deliver', so that if # 'deliver' triggers a new job, it can be assigned to us