Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions Lib/test/test_free_threading/test_type.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import abc
import collections.abc
import gc
import threading
import unittest
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Add a free-threading regression test for the deadlock between creating an
abstract base class and :meth:`ABCMeta.register <abc.ABCMeta.register>`.