gh-112075: Add critical sections for most dict APIs (#114508)

Starts adding thread safety to dict objects.


Use @critical_section for APIs which are exposed via argument clinic and don't directly correlate with a public C API which needs to acquire the lock
Use a _lock_held suffix for keeping changes to complicated functions simple and just wrapping them with a critical section
Acquire and release the lock in an existing function where it won't be overly disruptive to the existing logic
This commit is contained in:
Dino Viehland 2024-02-06 14:03:43 -08:00 committed by GitHub
parent b6228b521b
commit 92abb01240
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 782 additions and 284 deletions

View file

@ -465,12 +465,13 @@ Potential Optimizations
*/
#include "Python.h"
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_ceval.h" // _PyEval_GetBuiltin()
#include "pycore_dict.h" // _Py_dict_lookup()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include <stddef.h> // offsetof()
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_ceval.h" // _PyEval_GetBuiltin()
#include "pycore_critical_section.h" //_Py_BEGIN_CRITICAL_SECTION
#include "pycore_dict.h" // _Py_dict_lookup()
#include "pycore_object.h" // _PyObject_GC_UNTRACK()
#include "pycore_pyerrors.h" // _PyErr_ChainExceptions1()
#include <stddef.h> // offsetof()
#include "clinic/odictobject.c.h"
@ -1039,6 +1040,8 @@ _odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj,
{
PyObject *value = NULL;
Py_BEGIN_CRITICAL_SECTION(od);
_ODictNode *node = _odict_find_node_hash((PyODictObject *)od, key, hash);
if (node != NULL) {
/* Pop the node first to avoid a possible dict resize (due to
@ -1046,7 +1049,7 @@ _odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj,
resolution. */
int res = _odict_clear_node((PyODictObject *)od, node, key, hash);
if (res < 0) {
return NULL;
goto done;
}
/* Now delete the value from the dict. */
if (_PyDict_Pop_KnownHash((PyDictObject *)od, key, hash,
@ -1063,6 +1066,8 @@ _odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj,
PyErr_SetObject(PyExc_KeyError, key);
}
}
Py_END_CRITICAL_SECTION();
done:
return value;
}