Skip to content

Commit 433aadf

Browse files
Merge branch 'main' into io
2 parents b26d89f + e7eaed5 commit 433aadf

4 files changed

Lines changed: 38 additions & 1 deletion

File tree

Doc/library/threading.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,7 +515,7 @@ since it is impossible to detect the termination of alien threads.
515515
This constructor should always be called with keyword arguments. Arguments
516516
are:
517517

518-
*group* should be ``None``; reserved for future extension when a
518+
*group* must be ``None`` as it is reserved for future extension when a
519519
:class:`!ThreadGroup` class is implemented.
520520

521521
*target* is the callable object to be invoked by the :meth:`run` method.

Lib/test/test_type_cache.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
""" Tests for the internal type cache in CPython. """
2+
import collections.abc
23
import dis
34
import unittest
45
import warnings
@@ -114,6 +115,25 @@ class HolderSub(Holder):
114115
Holder.set_value()
115116
HolderSub.value
116117

118+
def test_abc_register_invalidates_subclass_versions(self):
119+
class Parent:
120+
pass
121+
122+
class Child(Parent):
123+
pass
124+
125+
type_assign_version(Parent)
126+
type_assign_version(Child)
127+
parent_version = type_get_version(Parent)
128+
child_version = type_get_version(Child)
129+
if parent_version == 0 or child_version == 0:
130+
self.skipTest("Could not assign valid type versions")
131+
132+
collections.abc.Mapping.register(Parent)
133+
134+
self.assertEqual(type_get_version(Parent), 0)
135+
self.assertEqual(type_get_version(Child), 0)
136+
117137
@support.cpython_only
118138
class TypeCacheWithSpecializationTests(unittest.TestCase):
119139
def tearDown(self):
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix ``abc.register()`` so it invalidates type version tags for registered classes.

Objects/typeobject.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6490,9 +6490,25 @@ set_flags_recursive(PyTypeObject *self, unsigned long mask, unsigned long flags)
64906490
void
64916491
_PyType_SetFlagsRecursive(PyTypeObject *self, unsigned long mask, unsigned long flags)
64926492
{
6493+
BEGIN_TYPE_LOCK();
6494+
/* Ideally, changing flags and invalidating the old version tag would
6495+
happen in one step. But type_modified_unlocked() is re-entrant and
6496+
cannot run with the world stopped, so we must invalidate first.
6497+
Immutable/static-builtin types are skipped because
6498+
set_flags_recursive() does not modify them. */
6499+
if (!PyType_HasFeature(self, Py_TPFLAGS_IMMUTABLETYPE) &&
6500+
(self->tp_flags & mask) != flags)
6501+
{
6502+
type_modified_unlocked(self);
6503+
}
6504+
/* Keep TYPE_LOCK held while waiting for stop-the-world so no thread
6505+
can reassign a version tag before the flag update. */
6506+
type_lock_prevent_release();
64936507
types_stop_world();
64946508
set_flags_recursive(self, mask, flags);
64956509
types_start_world();
6510+
type_lock_allow_release();
6511+
END_TYPE_LOCK();
64966512
}
64976513

64986514
/* This is similar to PyObject_GenericGetAttr(),

0 commit comments

Comments
 (0)