Skip to content

Commit a777c3e

Browse files
committed
Add comment, inline _PyDict_SplitKeysInvalidated, remove print, fix race in specialize_instance_load_attr
1 parent 0ed84a1 commit a777c3e

4 files changed

Lines changed: 15 additions & 18 deletions

File tree

Include/internal/pycore_dict.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,6 @@ typedef struct {
9191

9292
extern PyDictKeysObject *_PyDict_NewKeysForClass(PyHeapTypeObject *);
9393
extern void _PyDict_RemoveKeysForClass(PyHeapTypeObject *);
94-
extern void _PyDict_SplitKeysInvalidated(PyDictKeysObject* keys);
9594
extern PyObject *_PyDict_FromKeys(PyObject *, PyObject *, PyObject *);
9695

9796
/* Implementations of the `|` and `|=` operators for dict, used by the

Lib/test/test_free_threading/test_type.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -236,10 +236,6 @@ def writer(tid):
236236
for t in writers:
237237
t.join()
238238

239-
print(
240-
"rounds=%d writers=%d stoppers=%d -> stale reads = %d"
241-
% (NROUNDS, NWRITERS, NSTOPPERS, len(bugs))
242-
)
243239
self.assertFalse(bugs)
244240

245241
def run_one(self, writer_func, reader_func):

Objects/dictobject.c

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1952,6 +1952,10 @@ insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
19521952
return ix;
19531953
}
19541954

1955+
// We need to acquire the type lock before the keys mutex. Another lock
1956+
// is never acquired below the keys mutex but a keys mutex can be acquired
1957+
// elsewhere while we hold the types lock. To avoid deadlocks we must always
1958+
// acquire the type lock first.
19551959
Py_BEGIN_CRITICAL_SECTION_MUTEX(&_PyInterpreterState_GET()->types.mutex);
19561960
#endif
19571961

@@ -1960,7 +1964,12 @@ insert_split_key(PyDictKeysObject *keys, PyObject *key, Py_hash_t hash)
19601964
if (ix == DKIX_EMPTY && keys->dk_usable > 0) {
19611965
// Insert into new slot
19621966
FT_ATOMIC_STORE_UINT32_RELAXED(keys->dk_version, 0);
1963-
_PyDict_SplitKeysInvalidated(keys);
1967+
struct _instancekeysobject *shared_keys = _PyDictKeys_AsSharedKeys(keys);
1968+
PyTypeObject *type = FT_ATOMIC_LOAD_PTR_ACQUIRE(shared_keys->dsk_owning_type);
1969+
if (type) {
1970+
// we acquired the type lock above
1971+
_PyType_Modified_Unlocked(type);
1972+
}
19641973
Py_ssize_t hashpos = find_empty_slot(keys, hash);
19651974
ix = keys->dk_nentries;
19661975
dictkeys_set_index(keys, hashpos, ix);
@@ -7293,16 +7302,6 @@ _PyDict_RemoveKeysForClass(PyHeapTypeObject *cls)
72937302
_PyDictKeys_DecRef(cls->ht_cached_keys);
72947303
}
72957304

7296-
void
7297-
_PyDict_SplitKeysInvalidated(PyDictKeysObject* keys)
7298-
{
7299-
struct _instancekeysobject *shared_keys = _PyDictKeys_AsSharedKeys(keys);
7300-
PyTypeObject *type = FT_ATOMIC_LOAD_PTR_ACQUIRE(shared_keys->dsk_owning_type);
7301-
if (type) {
7302-
_PyType_Modified_Unlocked(type);
7303-
}
7304-
}
7305-
73067305
void
73077306
_PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp)
73087307
{

Python/specialize.c

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -980,12 +980,15 @@ static int
980980
specialize_instance_load_attr(PyObject* owner, _Py_CODEUNIT* instr, PyObject* name)
981981
{
982982
// 0 is not a valid version
983-
uint32_t shared_keys_version = 0;
984-
bool shadow = instance_has_key(owner, name, &shared_keys_version);
985983
PyObject *descr = NULL;
986984
unsigned int tp_version = 0;
987985
PyTypeObject *type = Py_TYPE(owner);
986+
// Read the type version before the keys version, we could have a concurrent
987+
// modification of the split keys in which case we update the keys version and
988+
// then the type version, this ensures we will still deopt if that happens.
988989
DescriptorClassification kind = analyze_descriptor_load(type, name, &descr, &tp_version);
990+
uint32_t shared_keys_version = 0;
991+
bool shadow = instance_has_key(owner, name, &shared_keys_version);
989992
int result = do_specialize_instance_load_attr(owner, instr, name, shadow, shared_keys_version, kind, descr, tp_version);
990993
Py_XDECREF(descr);
991994
return result;

0 commit comments

Comments
 (0)