@@ -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]
@@ -1192,17 +1209,24 @@ _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **valu
1192
1209
PyDictKeysObject * dk ;
1193
1210
DictKeysKind kind ;
1194
1211
Py_ssize_t ix ;
1195
- // TODO: Thread safety
1196
1212
start :
1197
1213
dk = mp -> ma_keys ;
1198
1214
kind = dk -> dk_kind ;
1199
1215
1200
1216
if (kind != DICT_KEYS_GENERAL ) {
1201
1217
if (PyUnicode_CheckExact (key )) {
1218
+ LOCK_KEYS_IF_SPLIT (dk , kind );
1202
1219
ix = unicodekeys_lookup_unicode (dk , key , hash );
1220
+ UNLOCK_KEYS_IF_SPLIT (dk , kind );
1203
1221
}
1204
1222
else {
1223
+ INCREF_KEYS_FT (dk );
1224
+ LOCK_KEYS_IF_SPLIT (dk , kind );
1225
+
1205
1226
ix = unicodekeys_lookup_generic (mp , dk , key , hash );
1227
+
1228
+ UNLOCK_KEYS_IF_SPLIT (dk , kind );
1229
+ DECREF_KEYS_FT (dk , IS_DICT_SHARED (mp ));
1206
1230
if (ix == DKIX_KEY_CHANGED ) {
1207
1231
goto start ;
1208
1232
}
@@ -1443,6 +1467,7 @@ _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyOb
1443
1467
Py_DECREF (value );
1444
1468
goto read_failed ;
1445
1469
}
1470
+
1446
1471
}
1447
1472
}
1448
1473
else {
@@ -1709,7 +1734,38 @@ insertdict(PyInterpreterState *interp, PyDictObject *mp,
1709
1734
assert (mp -> ma_keys -> dk_kind == DICT_KEYS_GENERAL );
1710
1735
}
1711
1736
1712
- Py_ssize_t ix = _Py_dict_lookup (mp , key , hash , & old_value );
1737
+ Py_ssize_t ix ;
1738
+ #ifdef Py_GIL_DISABLED
1739
+ PyDictKeysObject * dk = mp -> ma_keys ;
1740
+ DictKeysKind kind = dk -> dk_kind ;
1741
+
1742
+ if (kind == DICT_KEYS_SPLIT ) {
1743
+ // Split keys can be mutated by other dictionaries, so we need
1744
+ // to do a threadsafe lookup here. This is basically the split-key
1745
+ // half of _Py_dict_lookup_threadsafe and avoids locking the
1746
+ // shared keys if we can
1747
+ if (PyUnicode_CheckExact (key )) {
1748
+ ix = unicodekeys_lookup_unicode_threadsafe (dk , key , hash );
1749
+ }
1750
+ else {
1751
+ ix = unicodekeys_lookup_generic_threadsafe (mp , dk , key , hash );
1752
+ }
1753
+
1754
+ if (ix >= 0 ) {
1755
+ old_value = mp -> ma_values -> values [ix ];
1756
+ }
1757
+ else if (ix == DKIX_KEY_CHANGED ) {
1758
+ ix = _Py_dict_lookup (mp , key , hash , & old_value );
1759
+ }
1760
+ else {
1761
+ old_value = NULL ;
1762
+ }
1763
+ } else {
1764
+ ix = _Py_dict_lookup (mp , key , hash , & old_value );
1765
+ }
1766
+ #else
1767
+ ix = _Py_dict_lookup (mp , key , hash , & old_value );
1768
+ #endif
1713
1769
if (ix == DKIX_ERROR )
1714
1770
goto Fail ;
1715
1771
0 commit comments