_Py_atomic_store_ptr_release(&mp->ma_values, values);
}
+// gh-151593: The _Py_LOCK_DONT_DETACH flag ensures that the outer critical
+// section is not dropped if there is some contention on the keys lock.
+// It also means that it will be important that LOCK_KEYS() is essentially the
+// "inner-most" code and that we don't call Py_DECREF() or similar while
+// holding the keys lock.
+//
+// We are not allowed to acquire other locks within LOCK_KEYS(). For example,
+// PyType_Modified() must not be called within LOCK_KEYS() since it acquires
+// the type lock.
#define LOCK_KEYS(keys) PyMutex_LockFlags(&keys->dk_mutex, _Py_LOCK_DONT_DETACH)
#define UNLOCK_KEYS(keys) PyMutex_Unlock(&keys->dk_mutex)
}
#endif
+ bool inserted = false;
LOCK_KEYS(keys);
ix = unicodekeys_lookup_unicode(keys, key, hash);
if (ix == DKIX_EMPTY && keys->dk_usable > 0) {
// Insert into new slot
+ inserted = true;
FT_ATOMIC_STORE_UINT32_RELAXED(keys->dk_version, 0);
- _PyDict_SplitKeysInvalidated(keys);
Py_ssize_t hashpos = find_empty_slot(keys, hash);
ix = keys->dk_nentries;
dictkeys_set_index(keys, hashpos, ix);
}
assert (ix < SHARED_KEYS_MAX_SIZE);
UNLOCK_KEYS(keys);
+
+ if (inserted) {
+ // gh-151593: Calling PyType_Modified() with LOCK_KEYS() creates a
+ // deadlock. So only call the function after UNLOCK_KEYS().
+ _PyDict_SplitKeysInvalidated(keys);
+ }
+
return ix;
}