Skip to content

Commit bd6b306

Browse files
committed
Lock shared keys in Py_dict_lookup and use thread-safe lookup in insertdict
1 parent 0edde64 commit bd6b306

File tree

1 file changed

+58
-1
lines changed

1 file changed

+58
-1
lines changed

Objects/dictobject.c

Lines changed: 58 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,16 @@ ASSERT_DICT_LOCKED(PyObject *op)
162162
assert(_Py_IsOwnedByCurrentThread((PyObject *)mp) || IS_DICT_SHARED(mp));
163163
#define LOAD_KEYS_NENTRIES(d)
164164

165+
#define LOCK_KEYS_IF_SPLIT(keys, kind) \
166+
if (kind == DICT_KEYS_SPLIT) { \
167+
LOCK_KEYS(dk); \
168+
}
169+
170+
#define UNLOCK_KEYS_IF_SPLIT(keys, kind) \
171+
if (kind == DICT_KEYS_SPLIT) { \
172+
UNLOCK_KEYS(dk); \
173+
}
174+
165175
static inline Py_ssize_t
166176
load_keys_nentries(PyDictObject *mp)
167177
{
@@ -195,6 +205,9 @@ set_values(PyDictObject *mp, PyDictValues *values)
195205
#define DECREF_KEYS(dk) _Py_atomic_add_ssize(&dk->dk_refcnt, -1)
196206
#define LOAD_KEYS_NENTIRES(keys) _Py_atomic_load_ssize_relaxed(&keys->dk_nentries)
197207

208+
#define INCREF_KEYS_FT(dk) dictkeys_incref(dk)
209+
#define DECREF_KEYS_FT(dk, shared) dictkeys_decref(_PyInterpreterState_GET(), dk, shared)
210+
198211
static inline void split_keys_entry_added(PyDictKeysObject *keys)
199212
{
200213
ASSERT_KEYS_LOCKED(keys);
@@ -216,6 +229,10 @@ static inline void split_keys_entry_added(PyDictKeysObject *keys)
216229
#define INCREF_KEYS(dk) dk->dk_refcnt++
217230
#define DECREF_KEYS(dk) dk->dk_refcnt--
218231
#define LOAD_KEYS_NENTIRES(keys) keys->dk_nentries
232+
#define INCREF_KEYS_FT(dk)
233+
#define DECREF_KEYS_FT(dk, shared)
234+
#define LOCK_KEYS_IF_SPLIT(keys, kind)
235+
#define UNLOCK_KEYS_IF_SPLIT(keys, kind)
219236
#define IS_DICT_SHARED(mp) (false)
220237
#define SET_DICT_SHARED(mp)
221238
#define LOAD_INDEX(keys, size, idx) ((const int##size##_t*)(keys->dk_indices))[idx]
@@ -1199,10 +1216,18 @@ _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **valu
11991216

12001217
if (kind != DICT_KEYS_GENERAL) {
12011218
if (PyUnicode_CheckExact(key)) {
1219+
LOCK_KEYS_IF_SPLIT(dk, kind);
12021220
ix = unicodekeys_lookup_unicode(dk, key, hash);
1221+
UNLOCK_KEYS_IF_SPLIT(dk, kind);
12031222
}
12041223
else {
1224+
INCREF_KEYS_FT(dk);
1225+
LOCK_KEYS_IF_SPLIT(dk, kind);
1226+
12051227
ix = unicodekeys_lookup_generic(mp, dk, key, hash);
1228+
1229+
UNLOCK_KEYS_IF_SPLIT(dk, kind);
1230+
DECREF_KEYS_FT(dk, IS_DICT_SHARED(mp));
12061231
if (ix == DKIX_KEY_CHANGED) {
12071232
goto start;
12081233
}
@@ -1443,6 +1468,7 @@ _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyOb
14431468
Py_DECREF(value);
14441469
goto read_failed;
14451470
}
1471+
14461472
}
14471473
}
14481474
else {
@@ -1719,7 +1745,38 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
17191745
assert(mp->ma_keys->dk_kind == DICT_KEYS_GENERAL);
17201746
}
17211747

1722-
Py_ssize_t ix = _Py_dict_lookup(mp, key, hash, &old_value);
1748+
Py_ssize_t ix;
1749+
#ifdef Py_GIL_DISABLED
1750+
PyDictKeysObject *dk = mp->ma_keys;
1751+
DictKeysKind kind = dk->dk_kind;
1752+
1753+
if (kind == DICT_KEYS_SPLIT) {
1754+
// Split keys can be mutated by other dictionaries, so we need
1755+
// to do a threadsafe lookup here. This is basically the split-key
1756+
// half of _Py_dict_lookup_threadsafe and avoids locking the
1757+
// shared keys if we can
1758+
if (PyUnicode_CheckExact(key)) {
1759+
ix = unicodekeys_lookup_unicode_threadsafe(dk, key, hash);
1760+
}
1761+
else {
1762+
ix = unicodekeys_lookup_generic_threadsafe(mp, dk, key, hash);
1763+
}
1764+
1765+
if (ix >= 0) {
1766+
old_value = mp->ma_values->values[ix];
1767+
}
1768+
else if (ix == DKIX_KEY_CHANGED) {
1769+
ix = _Py_dict_lookup(mp, key, hash, &old_value);
1770+
}
1771+
else {
1772+
old_value = NULL;
1773+
}
1774+
} else {
1775+
ix = _Py_dict_lookup(mp, key, hash, &old_value);
1776+
}
1777+
#else
1778+
ix = _Py_dict_lookup(mp, key, hash, &old_value);
1779+
#endif
17231780
if (ix == DKIX_ERROR)
17241781
goto Fail;
17251782

0 commit comments

Comments
 (0)