From c3d4f2784c6fe7a7f555127a22ff7d9bc16aad19 Mon Sep 17 00:00:00 2001 From: David Welling Date: Mon, 2 Nov 2026 16:28:42 +0000 Subject: [PATCH] gh-156910: Add free-threading regression test for type_set_abstractmethods() deadlock --- Lib/test/test_free_threading/test_type.py | 36 +++++++++++++++++++ ...-11-02-16-28-30.gh-issue-156910.wGcXXy.rst | 2 ++ 2 files changed, 38 insertions(+) create mode 100644 Misc/NEWS.d/next/Tests/2026-11-02-16-28-30.gh-issue-156910.wGcXXy.rst diff --git a/Lib/test/test_free_threading/test_type.py b/Lib/test/test_free_threading/test_type.py index 6e750e0bc6084e..07ca76ffed9a63 100644 --- a/Lib/test/test_free_threading/test_type.py +++ b/Lib/test/test_free_threading/test_type.py @@ -1,3 +1,5 @@ +import abc +import collections.abc import gc import threading import unittest @@ -569,6 +571,40 @@ def subsetter(): self.assertIn(C, A.__subclasses__()) self.assertNotIn(C, B.__subclasses__()) + def test_abstractmethods_and_register(self): + # gh-156910: creating an ABC sets __abstractmethods__ and + # Sequence.register() sets type flags recursively. Both take the type + # lock and stop the world, and racing them used to deadlock between + # the type lock and the stop-the-world mutex. The gc.collect() thread + # adds contention on the stop-the-world mutex, which is needed to hit + # the deadlock. + done = threading.Event() + + def make_abcs(): + for _ in range(ITERS): + class C(abc.ABC): + @abc.abstractmethod + def f(self): + pass + + def register(): + for _ in range(ITERS): + collections.abc.Sequence.register(type("S", (), {})) + + def collect(): + while not done.is_set(): + gc.collect() + + workers = [Thread(target=make_abcs) for _ in range(NTHREADS)] + workers += [Thread(target=register) for _ in range(NTHREADS)] + collector = Thread(target=collect) + with threading_helper.start_threads([collector]): + try: + with threading_helper.start_threads(workers): + pass + finally: + done.set() + def test_class_creation_with_concurrent_setattr(self): # Creating a class resolves its slots from the dicts along the MRO # while holding the type lock, before the class is reachable from diff --git a/Misc/NEWS.d/next/Tests/2026-11-02-16-28-30.gh-issue-156910.wGcXXy.rst b/Misc/NEWS.d/next/Tests/2026-11-02-16-28-30.gh-issue-156910.wGcXXy.rst new file mode 100644 index 00000000000000..3b03247fdc76d3 --- /dev/null +++ b/Misc/NEWS.d/next/Tests/2026-11-02-16-28-30.gh-issue-156910.wGcXXy.rst @@ -0,0 +1,2 @@ +Add a free-threading regression test for the deadlock between creating an +abstract base class and :meth:`ABCMeta.register `.