// --- aliases ---------------------------------------------------------------
+// Compilers don't really support "consume" semantics, so we fake it. Use
+// "acquire" with TSan to support false positives. Use "relaxed" otherwise,
+// because CPUs on all platforms we support respect address dependencies without
+// extra barriers.
+// See 2.6.7 in https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p2055r0.pdf
+#if defined(_Py_THREAD_SANITIZER)
+# define _Py_atomic_load_ptr_consume _Py_atomic_load_ptr_acquire
+#else
+# define _Py_atomic_load_ptr_consume _Py_atomic_load_ptr_relaxed
+#endif
+
#if SIZEOF_LONG == 8
# define _Py_atomic_load_ulong(p) \
_Py_atomic_load_uint64((uint64_t *)p)
_Py_atomic_store_ptr(&value, new_value)
#define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) \
_Py_atomic_load_ptr_acquire(&value)
+#define FT_ATOMIC_LOAD_PTR_CONSUME(value) \
+ _Py_atomic_load_ptr_consume(&value)
#define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) \
_Py_atomic_load_uintptr_acquire(&value)
#define FT_ATOMIC_LOAD_PTR_RELAXED(value) \
#define FT_ATOMIC_LOAD_SSIZE_ACQUIRE(value) value
#define FT_ATOMIC_LOAD_SSIZE_RELAXED(value) value
#define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) value
+#define FT_ATOMIC_LOAD_PTR_CONSUME(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
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
- PyObject *ep_key = FT_ATOMIC_LOAD_PTR_RELAXED(ep->me_key);
+ PyObject *ep_key = FT_ATOMIC_LOAD_PTR_CONSUME(ep->me_key);
assert(ep_key != NULL);
assert(PyUnicode_CheckExact(ep_key));
if (ep_key == key ||
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
- PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
+ PyObject *startkey = _Py_atomic_load_ptr_consume(&ep->me_key);
assert(startkey == NULL || PyUnicode_CheckExact(ep->me_key));
assert(!PyUnicode_CheckExact(key));
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{
PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
- PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
+ PyObject *startkey = _Py_atomic_load_ptr_consume(&ep->me_key);
if (startkey == key) {
assert(PyUnicode_CheckExact(startkey));
return 1;
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
{
PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix];
- PyObject *startkey = _Py_atomic_load_ptr_relaxed(&ep->me_key);
+ PyObject *startkey = _Py_atomic_load_ptr_consume(&ep->me_key);
if (startkey == key) {
return 1;
}
k = _Py_atomic_load_ptr_acquire(&d->ma_keys);
assert(i >= 0);
if (_PyDict_HasSplitTable(d)) {
- PyDictValues *values = _Py_atomic_load_ptr_relaxed(&d->ma_values);
+ PyDictValues *values = _Py_atomic_load_ptr_consume(&d->ma_values);
if (values == NULL) {
goto concurrent_modification;
}
Py_BEGIN_CRITICAL_SECTION(dict);
if (dict->ma_values == values && FT_ATOMIC_LOAD_UINT8(values->valid)) {
- value = _Py_atomic_load_ptr_relaxed(&values->values[ix]);
+ value = _Py_atomic_load_ptr_consume(&values->values[ix]);
*attr = _Py_XNewRefWithLock(value);
success = true;
} else {