Skip to content

Commit dcd7ede

Browse files
committed
Make _PyDict_LoadGlobal threadsafe
1 parent b4fe02f commit dcd7ede

File tree

6 files changed

+27
-9
lines changed

6 files changed

+27
-9
lines changed

Include/internal/pycore_dict.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ extern void _PyDictKeys_DecRef(PyDictKeysObject *keys);
9797
* -1 when no entry found, -3 when compare raises error.
9898
*/
9999
extern Py_ssize_t _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
100+
extern Py_ssize_t _Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr);
100101

101102
extern Py_ssize_t _PyDict_LookupIndex(PyDictObject *, PyObject *);
102103
extern Py_ssize_t _PyDictKeys_StringLookup(PyDictKeysObject* dictkeys, PyObject *key);

Objects/dictobject.c

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,7 +1192,8 @@ _Py_dict_lookup(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **valu
11921192
PyDictKeysObject *dk;
11931193
DictKeysKind kind;
11941194
Py_ssize_t ix;
1195-
// TODO: Thread safety
1195+
1196+
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(mp);
11961197
start:
11971198
dk = mp->ma_keys;
11981199
kind = dk->dk_kind;
@@ -1390,7 +1391,7 @@ dictkeys_generic_lookup_threadsafe(PyDictObject *mp, PyDictKeysObject* dk, PyObj
13901391
return do_lookup(mp, dk, key, hash, compare_generic_threadsafe);
13911392
}
13921393

1393-
static Py_ssize_t
1394+
Py_ssize_t
13941395
_Py_dict_lookup_threadsafe(PyDictObject *mp, PyObject *key, Py_hash_t hash, PyObject **value_addr)
13951396
{
13961397
PyDictKeysObject *dk;
@@ -2343,11 +2344,12 @@ _PyDict_GetItemStringWithError(PyObject *v, const char *key)
23432344
* Raise an exception and return NULL if an error occurred (ex: computing the
23442345
* key hash failed, key comparison failed, ...). Return NULL if the key doesn't
23452346
* exist. Return the value if the key exists.
2347+
*
2348+
* Returns a new reference.
23462349
*/
23472350
PyObject *
23482351
_PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
23492352
{
2350-
// TODO: Thread safety
23512353
Py_ssize_t ix;
23522354
Py_hash_t hash;
23532355
PyObject *value;
@@ -2358,17 +2360,31 @@ _PyDict_LoadGlobal(PyDictObject *globals, PyDictObject *builtins, PyObject *key)
23582360
return NULL;
23592361
}
23602362

2363+
#ifdef Py_GIL_DISABLED
23612364
/* namespace 1: globals */
2362-
ix = _Py_dict_lookup(globals, key, hash, &value);
2365+
ix = _Py_dict_lookup_threadsafe(globals, key, hash, &value);
23632366
if (ix == DKIX_ERROR)
23642367
return NULL;
23652368
if (ix != DKIX_EMPTY && value != NULL)
23662369
return value;
23672370

23682371
/* namespace 2: builtins */
2369-
ix = _Py_dict_lookup(builtins, key, hash, &value);
2372+
ix = _Py_dict_lookup_threadsafe(builtins, key, hash, &value);
23702373
assert(ix >= 0 || value == NULL);
23712374
return value;
2375+
#else
2376+
/* namespace 1: globals */
2377+
ix = _Py_dict_lookup(globals, key, hash, &value);
2378+
if (ix == DKIX_ERROR)
2379+
return NULL;
2380+
if (ix != DKIX_EMPTY && value != NULL)
2381+
return Py_NewRef(value);
2382+
2383+
/* namespace 2: builtins */
2384+
ix = _Py_dict_lookup(builtins, key, hash, &value);
2385+
assert(ix >= 0 || value == NULL);
2386+
return Py_XNewRef(value);
2387+
#endif
23722388
}
23732389

23742390
/* Consumes references to key and value */

Objects/odictobject.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -535,8 +535,12 @@ _odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
535535
PyObject *value = NULL;
536536
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
537537
Py_ssize_t ix;
538-
538+
#ifdef Py_GIL_DISABLED
539+
ix = _Py_dict_lookup_threadsafe((PyDictObject *)od, key, hash, &value);
540+
Py_XDECREF(value);
541+
#else
539542
ix = _Py_dict_lookup((PyDictObject *)od, key, hash, &value);
543+
#endif
540544
if (ix == DKIX_EMPTY) {
541545
return keys->dk_nentries; /* index of new entry */
542546
}

Python/bytecodes.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1426,7 +1426,6 @@ dummy_func(
14261426
}
14271427
ERROR_IF(true, error);
14281428
}
1429-
Py_INCREF(res);
14301429
}
14311430
else {
14321431
/* Slow-path if globals or builtins is not a dict */

Python/executor_cases.c.h

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Python/generated_cases.c.h

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)