summaryrefslogtreecommitdiffstats
path: root/Include
diff options
context:
space:
mode:
authorDino Viehland <dinoviehland@meta.com>2024-04-22 05:57:05 (GMT)
committerGitHub <noreply@github.com>2024-04-22 05:57:05 (GMT)
commit8b541c017ea92040add608b3e0ef8dc85e9e6060 (patch)
tree880ff7c97041f374d21197b1b486686f2d64c998 /Include
parent1446024124fb98c3051199760380685f8a2fd127 (diff)
downloadcpython-8b541c017ea92040add608b3e0ef8dc85e9e6060.zip
cpython-8b541c017ea92040add608b3e0ef8dc85e9e6060.tar.gz
cpython-8b541c017ea92040add608b3e0ef8dc85e9e6060.tar.bz2
gh-112075: Make instance attributes stored in inline "dict" thread safe (#114742)
Make instance attributes stored in inline "dict" thread safe on free-threaded builds
Diffstat (limited to 'Include')
-rw-r--r--Include/cpython/object.h1
-rw-r--r--Include/internal/pycore_dict.h19
-rw-r--r--Include/internal/pycore_object.h16
-rw-r--r--Include/internal/pycore_pyatomic_ft_wrappers.h14
4 files changed, 35 insertions, 15 deletions
diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index 2797051..a8f5782 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -493,6 +493,7 @@ do { \
PyAPI_FUNC(void *) PyObject_GetItemData(PyObject *obj);
PyAPI_FUNC(int) PyObject_VisitManagedDict(PyObject *obj, visitproc visit, void *arg);
+PyAPI_FUNC(void) _PyObject_SetManagedDict(PyObject *obj, PyObject *new_dict);
PyAPI_FUNC(void) PyObject_ClearManagedDict(PyObject *obj);
#define TYPE_MAX_WATCHERS 8
diff --git a/Include/internal/pycore_dict.h b/Include/internal/pycore_dict.h
index fba0dfc..f33026d 100644
--- a/Include/internal/pycore_dict.h
+++ b/Include/internal/pycore_dict.h
@@ -1,4 +1,3 @@
-
#ifndef Py_INTERNAL_DICT_H
#define Py_INTERNAL_DICT_H
#ifdef __cplusplus
@@ -9,9 +8,10 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_freelist.h" // _PyFreeListState
-#include "pycore_identifier.h" // _Py_Identifier
-#include "pycore_object.h" // PyManagedDictPointer
+#include "pycore_freelist.h" // _PyFreeListState
+#include "pycore_identifier.h" // _Py_Identifier
+#include "pycore_object.h" // PyManagedDictPointer
+#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_LOAD_SSIZE_ACQUIRE
// Unsafe flavor of PyDict_GetItemWithError(): no error checking
extern PyObject* _PyDict_GetItemWithError(PyObject *dp, PyObject *key);
@@ -249,7 +249,7 @@ _PyDict_NotifyEvent(PyInterpreterState *interp,
return DICT_NEXT_VERSION(interp) | (mp->ma_version_tag & DICT_WATCHER_AND_MODIFICATION_MASK);
}
-extern PyDictObject *_PyObject_MakeDictFromInstanceAttributes(PyObject *obj);
+extern PyDictObject *_PyObject_MaterializeManagedDict(PyObject *obj);
PyAPI_FUNC(PyObject *)_PyDict_FromItems(
PyObject *const *keys, Py_ssize_t keys_offset,
@@ -277,7 +277,6 @@ _PyDictValues_AddToInsertionOrder(PyDictValues *values, Py_ssize_t ix)
static inline size_t
shared_keys_usable_size(PyDictKeysObject *keys)
{
-#ifdef Py_GIL_DISABLED
// dk_usable will decrease for each instance that is created and each
// value that is added. dk_nentries will increase for each value that
// is added. We want to always return the right value or larger.
@@ -285,11 +284,9 @@ shared_keys_usable_size(PyDictKeysObject *keys)
// second, and conversely here we read dk_usable first and dk_entries
// second (to avoid the case where we read entries before the increment
// and read usable after the decrement)
- return (size_t)(_Py_atomic_load_ssize_acquire(&keys->dk_usable) +
- _Py_atomic_load_ssize_acquire(&keys->dk_nentries));
-#else
- return (size_t)keys->dk_nentries + (size_t)keys->dk_usable;
-#endif
+ Py_ssize_t dk_usable = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(keys->dk_usable);
+ Py_ssize_t dk_nentries = FT_ATOMIC_LOAD_SSIZE_ACQUIRE(keys->dk_nentries);
+ return dk_nentries + dk_usable;
}
static inline size_t
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 512f7a3..88b052f 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -12,6 +12,7 @@ extern "C" {
#include "pycore_gc.h" // _PyObject_GC_IS_TRACKED()
#include "pycore_emscripten_trampoline.h" // _PyCFunction_TrampolineCall()
#include "pycore_interp.h" // PyInterpreterState.gc
+#include "pycore_pyatomic_ft_wrappers.h" // FT_ATOMIC_STORE_PTR_RELAXED
#include "pycore_pystate.h" // _PyInterpreterState_GET()
/* Check if an object is consistent. For example, ensure that the reference
@@ -659,10 +660,10 @@ extern PyObject* _PyType_GetDocFromInternalDoc(const char *, const char *);
extern PyObject* _PyType_GetTextSignatureFromInternalDoc(const char *, const char *, int);
void _PyObject_InitInlineValues(PyObject *obj, PyTypeObject *tp);
-extern int _PyObject_StoreInstanceAttribute(PyObject *obj, PyDictValues *values,
- PyObject *name, PyObject *value);
-PyObject * _PyObject_GetInstanceAttribute(PyObject *obj, PyDictValues *values,
- PyObject *name);
+extern int _PyObject_StoreInstanceAttribute(PyObject *obj,
+ PyObject *name, PyObject *value);
+extern bool _PyObject_TryGetInstanceAttribute(PyObject *obj, PyObject *name,
+ PyObject **attr);
#ifdef Py_GIL_DISABLED
# define MANAGED_DICT_OFFSET (((Py_ssize_t)sizeof(PyObject *))*-1)
@@ -683,6 +684,13 @@ _PyObject_ManagedDictPointer(PyObject *obj)
return (PyManagedDictPointer *)((char *)obj + MANAGED_DICT_OFFSET);
}
+static inline PyDictObject *
+_PyObject_GetManagedDict(PyObject *obj)
+{
+ PyManagedDictPointer *dorv = _PyObject_ManagedDictPointer(obj);
+ return (PyDictObject *)FT_ATOMIC_LOAD_PTR_RELAXED(dorv->dict);
+}
+
static inline PyDictValues *
_PyObject_InlineValues(PyObject *obj)
{
diff --git a/Include/internal/pycore_pyatomic_ft_wrappers.h b/Include/internal/pycore_pyatomic_ft_wrappers.h
index fed5d6e..bbfc462 100644
--- a/Include/internal/pycore_pyatomic_ft_wrappers.h
+++ b/Include/internal/pycore_pyatomic_ft_wrappers.h
@@ -21,7 +21,10 @@ extern "C" {
#ifdef Py_GIL_DISABLED
#define FT_ATOMIC_LOAD_PTR(value) _Py_atomic_load_ptr(&value)
+#define FT_ATOMIC_STORE_PTR(value, new_value) _Py_atomic_store_ptr(&value, new_value)
#define FT_ATOMIC_LOAD_SSIZE(value) _Py_atomic_load_ssize(&value)
+#define FT_ATOMIC_LOAD_SSIZE_ACQUIRE(value) \
+ _Py_atomic_load_ssize_acquire(&value)
#define FT_ATOMIC_LOAD_SSIZE_RELAXED(value) \
_Py_atomic_load_ssize_relaxed(&value)
#define FT_ATOMIC_STORE_PTR(value, new_value) \
@@ -30,6 +33,12 @@ extern "C" {
_Py_atomic_load_ptr_acquire(&value)
#define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) \
_Py_atomic_load_uintptr_acquire(&value)
+#define FT_ATOMIC_LOAD_PTR_RELAXED(value) \
+ _Py_atomic_load_ptr_relaxed(&value)
+#define FT_ATOMIC_LOAD_UINT8(value) \
+ _Py_atomic_load_uint8(&value)
+#define FT_ATOMIC_STORE_UINT8(value, new_value) \
+ _Py_atomic_store_uint8(&value, new_value)
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) \
_Py_atomic_store_ptr_relaxed(&value, new_value)
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) \
@@ -43,11 +52,16 @@ extern "C" {
#else
#define FT_ATOMIC_LOAD_PTR(value) value
+#define FT_ATOMIC_STORE_PTR(value, new_value) value = new_value
#define FT_ATOMIC_LOAD_SSIZE(value) value
+#define FT_ATOMIC_LOAD_SSIZE_ACQUIRE(value) value
#define FT_ATOMIC_LOAD_SSIZE_RELAXED(value) value
#define FT_ATOMIC_STORE_PTR(value, new_value) value = new_value
#define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) value
#define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) value
+#define FT_ATOMIC_LOAD_PTR_RELAXED(value) value
+#define FT_ATOMIC_LOAD_UINT8(value) value
+#define FT_ATOMIC_STORE_UINT8(value, new_value) value = new_value
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value