@@ -162,6 +162,16 @@ ASSERT_DICT_LOCKED(PyObject *op)
162
162
assert(_Py_IsOwnedByCurrentThread((PyObject *)mp) || IS_DICT_SHARED(mp));
163
163
#define LOAD_KEYS_NENTRIES (d )
164
164
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
+
165
175
static inline Py_ssize_t
166
176
load_keys_nentries (PyDictObject * mp )
167
177
{
@@ -195,6 +205,9 @@ set_values(PyDictObject *mp, PyDictValues *values)
195
205
#define DECREF_KEYS (dk ) _Py_atomic_add_ssize(&dk->dk_refcnt, -1)
196
206
#define LOAD_KEYS_NENTIRES (keys ) _Py_atomic_load_ssize_relaxed(&keys->dk_nentries)
197
207
208
+ #define INCREF_KEYS_FT (dk ) dictkeys_incref(dk)
209
+ #define DECREF_KEYS_FT (dk , shared ) dictkeys_decref(_PyInterpreterState_GET(), dk, shared)
210
+
198
211
static inline void split_keys_entry_added (PyDictKeysObject * keys )
199
212
{
200
213
ASSERT_KEYS_LOCKED (keys );
@@ -216,6 +229,10 @@ static inline void split_keys_entry_added(PyDictKeysObject *keys)
216
229
#define INCREF_KEYS (dk ) dk->dk_refcnt++
217
230
#define DECREF_KEYS (dk ) dk->dk_refcnt--
218
231
#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 )
219
236
#define IS_DICT_SHARED (mp ) (false)
220
237
#define SET_DICT_SHARED (mp )
221
238
#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
1199
1216
1200
1217
if (kind != DICT_KEYS_GENERAL ) {
1201
1218
if (PyUnicode_CheckExact (key )) {
1219
+ LOCK_KEYS_IF_SPLIT (dk , kind );
1202
1220
ix = unicodekeys_lookup_unicode (dk , key , hash );
1221
+ UNLOCK_KEYS_IF_SPLIT (dk , kind );
1203
1222
}
1204
1223
else {
1224
+ INCREF_KEYS_FT (dk );
1225
+ LOCK_KEYS_IF_SPLIT (dk , kind );
1226
+
1205
1227
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 ));
1206
1231
if (ix == DKIX_KEY_CHANGED ) {
1207
1232
goto start ;
1208
1233
}
@@ -1443,6 +1468,7 @@ _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyOb
1443
1468
Py_DECREF (value );
1444
1469
goto read_failed ;
1445
1470
}
1471
+
1446
1472
}
1447
1473
}
1448
1474
else {
@@ -1719,7 +1745,38 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
1719
1745
assert (mp -> ma_keys -> dk_kind == DICT_KEYS_GENERAL );
1720
1746
}
1721
1747
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
1723
1780
if (ix == DKIX_ERROR )
1724
1781
goto Fail ;
1725
1782
0 commit comments