# include "pycore_gc.h" // PyGC_Head
# include "pycore_runtime.h" // _Py_ID()
#endif
+#include "pycore_critical_section.h"// Py_BEGIN_CRITICAL_SECTION()
#include "pycore_modsupport.h" // _PyArg_UnpackKeywords()
PyDoc_STRVAR(OrderedDict_fromkeys__doc__,
return return_value;
}
+PyDoc_STRVAR(OrderedDict___sizeof____doc__,
+"__sizeof__($self, /)\n"
+"--\n"
+"\n");
+
+#define ORDEREDDICT___SIZEOF___METHODDEF \
+ {"__sizeof__", (PyCFunction)OrderedDict___sizeof__, METH_NOARGS, OrderedDict___sizeof____doc__},
+
+static Py_ssize_t
+OrderedDict___sizeof___impl(PyODictObject *self);
+
+static PyObject *
+OrderedDict___sizeof__(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ PyObject *return_value = NULL;
+ Py_ssize_t _return_value;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ _return_value = OrderedDict___sizeof___impl((PyODictObject *)self);
+ Py_END_CRITICAL_SECTION();
+ if ((_return_value == -1) && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = PyLong_FromSsize_t(_return_value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(OrderedDict___reduce____doc__,
+"__reduce__($self, /)\n"
+"--\n"
+"\n"
+"Return state information for pickling");
+
+#define ORDEREDDICT___REDUCE___METHODDEF \
+ {"__reduce__", (PyCFunction)OrderedDict___reduce__, METH_NOARGS, OrderedDict___reduce____doc__},
+
+static PyObject *
+OrderedDict___reduce___impl(PyODictObject *od);
+
+static PyObject *
+OrderedDict___reduce__(PyObject *od, PyObject *Py_UNUSED(ignored))
+{
+ return OrderedDict___reduce___impl((PyODictObject *)od);
+}
+
PyDoc_STRVAR(OrderedDict_setdefault__doc__,
"setdefault($self, /, key, default=None)\n"
"--\n"
}
default_value = args[1];
skip_optional_pos:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = OrderedDict_setdefault_impl((PyODictObject *)self, key, default_value);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
}
default_value = args[1];
skip_optional_pos:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = OrderedDict_pop_impl((PyODictObject *)self, key, default_value);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
goto exit;
}
skip_optional_pos:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = OrderedDict_popitem_impl((PyODictObject *)self, last);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
}
+PyDoc_STRVAR(OrderedDict_clear__doc__,
+"clear($self, /)\n"
+"--\n"
+"\n"
+"Remove all items from ordered dict.");
+
+#define ORDEREDDICT_CLEAR_METHODDEF \
+ {"clear", (PyCFunction)OrderedDict_clear, METH_NOARGS, OrderedDict_clear__doc__},
+
+static PyObject *
+OrderedDict_clear_impl(PyODictObject *self);
+
+static PyObject *
+OrderedDict_clear(PyObject *self, PyObject *Py_UNUSED(ignored))
+{
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(self);
+ return_value = OrderedDict_clear_impl((PyODictObject *)self);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
+}
+
+PyDoc_STRVAR(OrderedDict_copy__doc__,
+"copy($self, /)\n"
+"--\n"
+"\n"
+"A shallow copy of ordered dict.");
+
+#define ORDEREDDICT_COPY_METHODDEF \
+ {"copy", (PyCFunction)OrderedDict_copy, METH_NOARGS, OrderedDict_copy__doc__},
+
+static PyObject *
+OrderedDict_copy_impl(PyObject *od);
+
+static PyObject *
+OrderedDict_copy(PyObject *od, PyObject *Py_UNUSED(ignored))
+{
+ PyObject *return_value = NULL;
+
+ Py_BEGIN_CRITICAL_SECTION(od);
+ return_value = OrderedDict_copy_impl(od);
+ Py_END_CRITICAL_SECTION();
+
+ return return_value;
+}
+
PyDoc_STRVAR(OrderedDict_move_to_end__doc__,
"move_to_end($self, /, key, last=True)\n"
"--\n"
goto exit;
}
skip_optional_pos:
+ Py_BEGIN_CRITICAL_SECTION(self);
return_value = OrderedDict_move_to_end_impl((PyODictObject *)self, key, last);
+ Py_END_CRITICAL_SECTION();
exit:
return return_value;
}
-/*[clinic end generated code: output=7d8206823bb1f419 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=7bc997ca7900f06f input=a9049054013a1b77]*/
static Py_ssize_t
_odict_get_index_raw(PyODictObject *od, PyObject *key, Py_hash_t hash)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
PyObject *value = NULL;
PyDictKeysObject *keys = ((PyDictObject *)od)->ma_keys;
Py_ssize_t ix;
static int
_odict_resize(PyODictObject *od)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
Py_ssize_t size, i;
_ODictNode **fast_nodes, *node;
static Py_ssize_t
_odict_get_index(PyODictObject *od, PyObject *key, Py_hash_t hash)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
PyDictKeysObject *keys;
assert(key != NULL);
static _ODictNode *
_odict_find_node_hash(PyODictObject *od, PyObject *key, Py_hash_t hash)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
Py_ssize_t index;
if (_odict_EMPTY(od))
static _ODictNode *
_odict_find_node(PyODictObject *od, PyObject *key)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
Py_ssize_t index;
Py_hash_t hash;
static void
_odict_add_head(PyODictObject *od, _ODictNode *node)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
_odictnode_PREV(node) = NULL;
_odictnode_NEXT(node) = _odict_FIRST(od);
if (_odict_FIRST(od) == NULL)
static void
_odict_add_tail(PyODictObject *od, _ODictNode *node)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
_odictnode_PREV(node) = _odict_LAST(od);
_odictnode_NEXT(node) = NULL;
if (_odict_LAST(od) == NULL)
static int
_odict_add_new_node(PyODictObject *od, PyObject *key, Py_hash_t hash)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
Py_ssize_t i;
_ODictNode *node;
static void
_odict_remove_node(PyODictObject *od, _ODictNode *node)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
if (_odict_FIRST(od) == node)
_odict_FIRST(od) = _odictnode_NEXT(node);
else if (_odictnode_PREV(node) != NULL)
_odict_clear_node(PyODictObject *od, _ODictNode *node, PyObject *key,
Py_hash_t hash)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
Py_ssize_t i;
assert(key != NULL);
return _PyDict_FromKeys((PyObject *)type, seq, value);
}
-/* __sizeof__() */
-
-/* OrderedDict.__sizeof__() does not have a docstring. */
-PyDoc_STRVAR(odict_sizeof__doc__, "");
+/*[clinic input]
+@critical_section
+OrderedDict.__sizeof__ -> Py_ssize_t
+[clinic start generated code]*/
-static PyObject *
-odict_sizeof(PyObject *op, PyObject *Py_UNUSED(ignored))
+static Py_ssize_t
+OrderedDict___sizeof___impl(PyODictObject *self)
+/*[clinic end generated code: output=1a8560db8cf83ac5 input=655e989ae24daa6a]*/
{
- PyODictObject *od = _PyODictObject_CAST(op);
- Py_ssize_t res = _PyDict_SizeOf((PyDictObject *)od);
- res += sizeof(_ODictNode *) * od->od_fast_nodes_size; /* od_fast_nodes */
- if (!_odict_EMPTY(od)) {
- res += sizeof(_ODictNode) * PyODict_SIZE(od); /* linked-list */
+ Py_ssize_t res = _PyDict_SizeOf_LockHeld((PyDictObject *)self);
+ res += sizeof(_ODictNode *) * self->od_fast_nodes_size; /* od_fast_nodes */
+ if (!_odict_EMPTY(self)) {
+ res += sizeof(_ODictNode) * PyODict_SIZE(self); /* linked-list */
}
- return PyLong_FromSsize_t(res);
+ return res;
}
-/* __reduce__() */
+/*[clinic input]
+OrderedDict.__reduce__
+ self as od: self(type="PyODictObject *")
-PyDoc_STRVAR(odict_reduce__doc__, "Return state information for pickling");
+Return state information for pickling
+[clinic start generated code]*/
static PyObject *
-odict_reduce(PyObject *op, PyObject *Py_UNUSED(ignored))
+OrderedDict___reduce___impl(PyODictObject *od)
+/*[clinic end generated code: output=71eeb81f760a6a8e input=b0467c7ec400fe5e]*/
{
- register PyODictObject *od = _PyODictObject_CAST(op);
PyObject *state, *result = NULL;
PyObject *items_iter, *items, *args = NULL;
/* setdefault(): Skips __missing__() calls. */
+static int PyODict_SetItem_LockHeld(PyObject *self, PyObject *key, PyObject *value);
/*[clinic input]
+@critical_section
OrderedDict.setdefault
key: object
static PyObject *
OrderedDict_setdefault_impl(PyODictObject *self, PyObject *key,
PyObject *default_value)
-/*[clinic end generated code: output=97537cb7c28464b6 input=38e098381c1efbc6]*/
+/*[clinic end generated code: output=97537cb7c28464b6 input=d7b93e92734f99b5]*/
{
PyObject *result = NULL;
if (PyErr_Occurred())
return NULL;
assert(_odict_find_node(self, key) == NULL);
- if (PyODict_SetItem((PyObject *)self, key, default_value) >= 0) {
+ if (PyODict_SetItem_LockHeld((PyObject *)self, key, default_value) >= 0) {
result = Py_NewRef(default_value);
}
}
_odict_popkey_hash(PyObject *od, PyObject *key, PyObject *failobj,
Py_hash_t hash)
{
- PyObject *value = NULL;
-
- Py_BEGIN_CRITICAL_SECTION(od);
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
+ PyObject *value = NULL;
_ODictNode *node = _odict_find_node_hash(_PyODictObject_CAST(od), key, hash);
if (node != NULL) {
/* Pop the node first to avoid a possible dict resize (due to
PyErr_SetObject(PyExc_KeyError, key);
}
}
- Py_END_CRITICAL_SECTION();
done:
return value;
/* Skips __missing__() calls. */
/*[clinic input]
+@critical_section
OrderedDict.pop
key: object
static PyObject *
OrderedDict_pop_impl(PyODictObject *self, PyObject *key,
PyObject *default_value)
-/*[clinic end generated code: output=7a6447d104e7494b input=7efe36601007dff7]*/
+/*[clinic end generated code: output=7a6447d104e7494b input=a79988887b4a651f]*/
{
Py_hash_t hash = PyObject_Hash(key);
if (hash == -1)
/* popitem() */
/*[clinic input]
+@critical_section
OrderedDict.popitem
last: bool = True
static PyObject *
OrderedDict_popitem_impl(PyODictObject *self, int last)
-/*[clinic end generated code: output=98e7d986690d49eb input=d992ac5ee8305e1a]*/
+/*[clinic end generated code: output=98e7d986690d49eb input=8aafc7433e0a40e7]*/
{
PyObject *key, *value, *item = NULL;
_ODictNode *node;
PyDoc_STRVAR(odict_keys__doc__, "");
static PyObject * odictkeys_new(PyObject *od, PyObject *Py_UNUSED(ignored)); /* forward */
+static int
+_PyODict_SetItem_KnownHash_LockHeld(PyObject *od, PyObject *key, PyObject *value,
+ Py_hash_t hash); /* forward */
/* values() */
#define odict_update mutablemapping_update
-/* clear() */
+/*[clinic input]
+@critical_section
+OrderedDict.clear
-PyDoc_STRVAR(odict_clear__doc__,
- "od.clear() -> None. Remove all items from od.");
+Remove all items from ordered dict.
+[clinic start generated code]*/
static PyObject *
-odict_clear(PyObject *op, PyObject *Py_UNUSED(ignored))
+OrderedDict_clear_impl(PyODictObject *self)
+/*[clinic end generated code: output=a1a76d1322f556c5 input=08b12322e74c535c]*/
{
- register PyODictObject *od = _PyODictObject_CAST(op);
- PyDict_Clear(op);
- _odict_clear_nodes(od);
+ _PyDict_Clear_LockHeld((PyObject *)self);
+ _odict_clear_nodes(self);
Py_RETURN_NONE;
}
/* copy() */
-/* forward */
-static int _PyODict_SetItem_KnownHash(PyObject *, PyObject *, PyObject *,
- Py_hash_t);
+/*[clinic input]
+@critical_section
+OrderedDict.copy
+ self as od: self
-PyDoc_STRVAR(odict_copy__doc__, "od.copy() -> a shallow copy of od");
+A shallow copy of ordered dict.
+[clinic start generated code]*/
static PyObject *
-odict_copy(PyObject *op, PyObject *Py_UNUSED(ignored))
+OrderedDict_copy_impl(PyObject *od)
+/*[clinic end generated code: output=9cdbe7394aecc576 input=e329951ae617ed48]*/
{
- register PyODictObject *od = _PyODictObject_CAST(op);
_ODictNode *node;
PyObject *od_copy;
PyErr_SetObject(PyExc_KeyError, key);
goto fail;
}
- if (_PyODict_SetItem_KnownHash((PyObject *)od_copy, key, value,
- _odictnode_HASH(node)) != 0)
+ if (_PyODict_SetItem_KnownHash_LockHeld((PyObject *)od_copy, key, value,
+ _odictnode_HASH(node)) != 0)
goto fail;
}
}
/* move_to_end() */
/*[clinic input]
+@critical_section
OrderedDict.move_to_end
key: object
static PyObject *
OrderedDict_move_to_end_impl(PyODictObject *self, PyObject *key, int last)
-/*[clinic end generated code: output=fafa4c5cc9b92f20 input=d6ceff7132a2fcd7]*/
+/*[clinic end generated code: output=fafa4c5cc9b92f20 input=09f8bc7053c0f6d4]*/
{
_ODictNode *node;
/* overridden dict methods */
ORDEREDDICT_FROMKEYS_METHODDEF
- {"__sizeof__", odict_sizeof, METH_NOARGS,
- odict_sizeof__doc__},
- {"__reduce__", odict_reduce, METH_NOARGS,
- odict_reduce__doc__},
+ ORDEREDDICT___SIZEOF___METHODDEF
+ ORDEREDDICT___REDUCE___METHODDEF
ORDEREDDICT_SETDEFAULT_METHODDEF
ORDEREDDICT_POP_METHODDEF
ORDEREDDICT_POPITEM_METHODDEF
odict_items__doc__},
{"update", _PyCFunction_CAST(odict_update), METH_VARARGS | METH_KEYWORDS,
odict_update__doc__},
- {"clear", odict_clear, METH_NOARGS,
- odict_clear__doc__},
- {"copy", odict_copy, METH_NOARGS,
- odict_copy__doc__},
-
+ ORDEREDDICT_CLEAR_METHODDEF
+ ORDEREDDICT_COPY_METHODDEF
/* new methods */
{"__reversed__", odict_reversed, METH_NOARGS,
odict_reversed__doc__},
{
PyODictObject *od = _PyODictObject_CAST(op);
Py_CLEAR(od->od_inst_dict);
- PyDict_Clear((PyObject *)od);
+ // cannot use lock held variant as critical section is not held here
+ PyDict_Clear(op);
_odict_clear_nodes(od);
return 0;
}
/* tp_richcompare */
static PyObject *
-odict_richcompare(PyObject *v, PyObject *w, int op)
+odict_richcompare_lock_held(PyObject *v, PyObject *w, int op)
{
if (!PyODict_Check(v) || !PyDict_Check(w)) {
Py_RETURN_NOTIMPLEMENTED;
}
}
+static PyObject *
+odict_richcompare(PyObject *v, PyObject *w, int op)
+{
+ PyObject *res;
+ Py_BEGIN_CRITICAL_SECTION2(v, w);
+ res = odict_richcompare_lock_held(v, w, op);
+ Py_END_CRITICAL_SECTION2();
+ return res;
+}
+
/* tp_iter */
static PyObject *
}
static int
-_PyODict_SetItem_KnownHash(PyObject *od, PyObject *key, PyObject *value,
- Py_hash_t hash)
+_PyODict_SetItem_KnownHash_LockHeld(PyObject *od, PyObject *key, PyObject *value,
+ Py_hash_t hash)
{
- int res = _PyDict_SetItem_KnownHash(od, key, value, hash);
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
+ int res = _PyDict_SetItem_KnownHash_LockHeld((PyDictObject *)od, key, value, hash);
if (res == 0) {
res = _odict_add_new_node(_PyODictObject_CAST(od), key, hash);
if (res < 0) {
return res;
}
-int
-PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value)
+
+static int
+PyODict_SetItem_LockHeld(PyObject *od, PyObject *key, PyObject *value)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
Py_hash_t hash = PyObject_Hash(key);
- if (hash == -1)
+ if (hash == -1) {
return -1;
- return _PyODict_SetItem_KnownHash(od, key, value, hash);
+ }
+ return _PyODict_SetItem_KnownHash_LockHeld(od, key, value, hash);
}
int
-PyODict_DelItem(PyObject *od, PyObject *key)
+PyODict_SetItem(PyObject *od, PyObject *key, PyObject *value)
+{
+ int res;
+ Py_BEGIN_CRITICAL_SECTION(od);
+ res = PyODict_SetItem_LockHeld(od, key, value);
+ Py_END_CRITICAL_SECTION();
+ return res;
+}
+
+int
+PyODict_DelItem_LockHeld(PyObject *od, PyObject *key)
{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(od);
int res;
Py_hash_t hash = PyObject_Hash(key);
if (hash == -1)
res = _odict_clear_node(_PyODictObject_CAST(od), NULL, key, hash);
if (res < 0)
return -1;
- return _PyDict_DelItem_KnownHash(od, key, hash);
+ return _PyDict_DelItem_KnownHash_LockHeld(od, key, hash);
}
+int
+PyODict_DelItem(PyObject *od, PyObject *key)
+{
+ int res;
+ Py_BEGIN_CRITICAL_SECTION(od);
+ res = PyODict_DelItem_LockHeld(od, key);
+ Py_END_CRITICAL_SECTION();
+ return res;
+}
/* -------------------------------------------
* The OrderedDict views (keys/values/items)
/* In order to protect against modifications during iteration, we track
* the current key instead of the current node. */
static PyObject *
-odictiter_nextkey(odictiterobject *di)
+odictiter_nextkey_lock_held(odictiterobject *di)
{
+ assert(di->di_odict != NULL);
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(di->di_odict);
PyObject *key = NULL;
_ODictNode *node;
int reversed = di->kind & _odict_ITER_REVERSED;
- if (di->di_odict == NULL)
- return NULL;
if (di->di_current == NULL)
goto done; /* We're already done. */
return key;
}
+
+static PyObject *
+odictiter_nextkey(odictiterobject *di)
+{
+ _Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(di);
+ if (di->di_odict == NULL) {
+ return NULL;
+ }
+ PyObject *res;
+ Py_BEGIN_CRITICAL_SECTION(di->di_odict);
+ res = odictiter_nextkey_lock_held(di);
+ Py_END_CRITICAL_SECTION();
+ return res;
+}
+
static PyObject *
-odictiter_iternext(PyObject *op)
+odictiter_iternext_lock_held(PyObject *op)
{
odictiterobject *di = (odictiterobject*)op;
PyObject *result, *value;
return key;
}
- value = PyODict_GetItem((PyObject *)di->di_odict, key); /* borrowed */
- if (value == NULL) {
+ if (PyDict_GetItemRef((PyObject *)di->di_odict, key, &value) != 1) {
if (!PyErr_Occurred())
PyErr_SetObject(PyExc_KeyError, key);
Py_DECREF(key);
goto done;
}
- Py_INCREF(value);
/* Handle the values case. */
if (!(di->kind & _odict_ITER_KEYS)) {
/* Handle the items case. */
result = di->di_result;
- if (Py_REFCNT(result) == 1) {
+ if (_PyObject_IsUniquelyReferenced(result)) {
/* not in use so we can reuse it
* (the common case during iteration) */
Py_INCREF(result);
return NULL;
}
+static PyObject *
+odictiter_iternext(PyObject *op)
+{
+ PyObject *res;
+ Py_BEGIN_CRITICAL_SECTION(op);
+ res = odictiter_iternext_lock_held(op);
+ Py_END_CRITICAL_SECTION();
+ return res;
+}
+
+
/* No need for tp_clear because odictiterobject is not mutable. */
PyDoc_STRVAR(reduce_doc, "Return state information for pickling");