2024-02-14 12:15:05 -08:00
|
|
|
// This header file provides wrappers around the atomic operations found in
|
|
|
|
|
// `pyatomic.h` that are only atomic in free-threaded builds.
|
|
|
|
|
//
|
|
|
|
|
// These are intended to be used in places where atomics are required in
|
|
|
|
|
// free-threaded builds, but not in the default build, and we don't want to
|
|
|
|
|
// introduce the potential performance overhead of an atomic operation in the
|
|
|
|
|
// default build.
|
|
|
|
|
//
|
|
|
|
|
// All usages of these macros should be replaced with unconditionally atomic or
|
|
|
|
|
// non-atomic versions, and this file should be removed, once the dust settles
|
|
|
|
|
// on free threading.
|
|
|
|
|
#ifndef Py_ATOMIC_FT_WRAPPERS_H
|
|
|
|
|
#define Py_ATOMIC_FT_WRAPPERS_H
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
extern "C" {
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifndef Py_BUILD_CORE
|
|
|
|
|
#error "this header requires Py_BUILD_CORE define"
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef Py_GIL_DISABLED
|
2024-04-08 07:58:38 -07:00
|
|
|
#define FT_ATOMIC_LOAD_PTR(value) _Py_atomic_load_ptr(&value)
|
2024-04-21 22:57:05 -07:00
|
|
|
#define FT_ATOMIC_STORE_PTR(value, new_value) _Py_atomic_store_ptr(&value, new_value)
|
2024-02-15 00:22:47 -08:00
|
|
|
#define FT_ATOMIC_LOAD_SSIZE(value) _Py_atomic_load_ssize(&value)
|
2024-04-21 22:57:05 -07:00
|
|
|
#define FT_ATOMIC_LOAD_SSIZE_ACQUIRE(value) \
|
|
|
|
|
_Py_atomic_load_ssize_acquire(&value)
|
2024-02-14 12:15:05 -08:00
|
|
|
#define FT_ATOMIC_LOAD_SSIZE_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_ssize_relaxed(&value)
|
2024-04-08 07:58:38 -07:00
|
|
|
#define FT_ATOMIC_STORE_PTR(value, new_value) \
|
|
|
|
|
_Py_atomic_store_ptr(&value, new_value)
|
2024-04-19 14:47:42 -07:00
|
|
|
#define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) \
|
|
|
|
|
_Py_atomic_load_ptr_acquire(&value)
|
2025-12-11 16:23:19 -05:00
|
|
|
#define FT_ATOMIC_LOAD_PTR_CONSUME(value) \
|
|
|
|
|
_Py_atomic_load_ptr_consume(&value)
|
2024-04-19 14:47:42 -07:00
|
|
|
#define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) \
|
|
|
|
|
_Py_atomic_load_uintptr_acquire(&value)
|
2024-04-21 22:57:05 -07:00
|
|
|
#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)
|
2025-12-19 14:10:37 -05:00
|
|
|
#define FT_ATOMIC_LOAD_INT8_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_int8_relaxed(&value)
|
2024-04-30 11:38:05 -07:00
|
|
|
#define FT_ATOMIC_LOAD_UINT8_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_uint8_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_uint16_relaxed(&value)
|
2024-04-30 12:37:38 -07:00
|
|
|
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_uint32_relaxed(&value)
|
2024-06-13 17:29:19 +08:00
|
|
|
#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_ulong_relaxed(&value)
|
2024-02-21 10:38:09 +09:00
|
|
|
#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) \
|
|
|
|
|
_Py_atomic_store_ptr_release(&value, new_value)
|
2024-04-19 14:47:42 -07:00
|
|
|
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) \
|
|
|
|
|
_Py_atomic_store_uintptr_release(&value, new_value)
|
2025-12-19 14:10:37 -05:00
|
|
|
#define FT_ATOMIC_STORE_INT8_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_int8_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_STORE_INT8_RELEASE(value, new_value) \
|
|
|
|
|
_Py_atomic_store_int8_release(&value, new_value)
|
2024-02-14 12:15:05 -08:00
|
|
|
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_ssize_relaxed(&value, new_value)
|
gh-132657: Add lock-free set contains implementation (#132290)
This roughly follows what was done for dictobject to make a lock-free
lookup operation. With this change, the set contains operation scales much
better when used from multiple-threads. The frozenset contains performance
seems unchanged (as already lock-free).
Summary of changes:
* refactor set_lookkey() into set_do_lookup() which now takes a function
pointer that does the entry comparison. This is similar to dictobject and
do_lookup(). In an optimized build, the comparison function is inlined and
there should be no performance cost to this.
* change set_do_lookup() to return a status separately from the entry value
* add set_compare_frozenset() and use if the object is a frozenset. For the
free-threaded build, this avoids some overhead (locking, atomic operations,
incref/decref on key)
* use FT_ATOMIC_* macros as needed for atomic loads and stores
* use a deferred free on the set table array, if shared (only on free-threaded
build, normal build always does an immediate free)
* for free-threaded build, use explicit for loop to zero the table, rather than memcpy()
* when mutating the set, assign so->table to NULL while the change is a
happening. Assign the real table array after the change is done.
2025-12-13 01:50:23 -08:00
|
|
|
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) \
|
|
|
|
|
_Py_atomic_store_ssize_release(&value, new_value)
|
2024-04-19 14:47:42 -07:00
|
|
|
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_uint8_relaxed(&value, new_value)
|
2024-04-30 11:38:05 -07:00
|
|
|
#define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_uint16_relaxed(&value, new_value)
|
2024-04-30 12:37:38 -07:00
|
|
|
#define FT_ATOMIC_STORE_UINT32_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_uint32_relaxed(&value, new_value)
|
2024-12-03 15:41:53 +01:00
|
|
|
#define FT_ATOMIC_STORE_CHAR_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_char_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_CHAR_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_char_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_UCHAR_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_uchar_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_UCHAR_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_uchar_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_SHORT_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_short_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_SHORT_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_short_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_USHORT_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_ushort_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_USHORT_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_ushort_relaxed(&value)
|
2025-11-26 12:40:45 -08:00
|
|
|
#define FT_ATOMIC_LOAD_INT(value) \
|
|
|
|
|
_Py_atomic_load_int(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_INT(value, new_value) \
|
|
|
|
|
_Py_atomic_store_int(&value, new_value)
|
2024-12-03 15:41:53 +01:00
|
|
|
#define FT_ATOMIC_STORE_INT_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_int_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_INT_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_int_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_UINT_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_uint_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_UINT_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_uint_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_LONG_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_long_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_LONG_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_long_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_ULONG_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_ulong_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_ssize_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_STORE_FLOAT_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_float_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_FLOAT_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_float_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_DOUBLE_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_double_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_DOUBLE_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_double_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_LLONG_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_llong_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_LLONG_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_llong_relaxed(&value)
|
|
|
|
|
#define FT_ATOMIC_STORE_ULLONG_RELAXED(value, new_value) \
|
|
|
|
|
_Py_atomic_store_ullong_relaxed(&value, new_value)
|
|
|
|
|
#define FT_ATOMIC_LOAD_ULLONG_RELAXED(value) \
|
|
|
|
|
_Py_atomic_load_ullong_relaxed(&value)
|
2025-04-14 12:31:19 -04:00
|
|
|
#define FT_ATOMIC_ADD_SSIZE(value, new_value) \
|
|
|
|
|
(void)_Py_atomic_add_ssize(&value, new_value)
|
2025-08-07 11:24:50 -04:00
|
|
|
#define FT_MUTEX_LOCK(lock) PyMutex_Lock(lock)
|
|
|
|
|
#define FT_MUTEX_UNLOCK(lock) PyMutex_Unlock(lock)
|
2024-04-30 12:37:38 -07:00
|
|
|
|
2024-02-14 12:15:05 -08:00
|
|
|
#else
|
2024-04-08 07:58:38 -07:00
|
|
|
#define FT_ATOMIC_LOAD_PTR(value) value
|
2024-04-21 22:57:05 -07:00
|
|
|
#define FT_ATOMIC_STORE_PTR(value, new_value) value = new_value
|
2024-02-15 00:22:47 -08:00
|
|
|
#define FT_ATOMIC_LOAD_SSIZE(value) value
|
2024-04-21 22:57:05 -07:00
|
|
|
#define FT_ATOMIC_LOAD_SSIZE_ACQUIRE(value) value
|
2024-02-14 12:15:05 -08:00
|
|
|
#define FT_ATOMIC_LOAD_SSIZE_RELAXED(value) value
|
2024-04-19 14:47:42 -07:00
|
|
|
#define FT_ATOMIC_LOAD_PTR_ACQUIRE(value) value
|
2025-12-11 16:23:19 -05:00
|
|
|
#define FT_ATOMIC_LOAD_PTR_CONSUME(value) value
|
2024-04-19 14:47:42 -07:00
|
|
|
#define FT_ATOMIC_LOAD_UINTPTR_ACQUIRE(value) value
|
2024-04-21 22:57:05 -07:00
|
|
|
#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
|
2025-12-19 14:10:37 -05:00
|
|
|
#define FT_ATOMIC_LOAD_INT8_RELAXED(value) value
|
2024-04-30 11:38:05 -07:00
|
|
|
#define FT_ATOMIC_LOAD_UINT8_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) value
|
2024-04-30 12:37:38 -07:00
|
|
|
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) value
|
2024-06-13 17:29:19 +08:00
|
|
|
#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) value
|
2024-02-21 10:38:09 +09:00
|
|
|
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_STORE_PTR_RELEASE(value, new_value) value = new_value
|
2024-04-19 14:47:42 -07:00
|
|
|
#define FT_ATOMIC_STORE_UINTPTR_RELEASE(value, new_value) value = new_value
|
2025-12-19 14:10:37 -05:00
|
|
|
#define FT_ATOMIC_STORE_INT8_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_STORE_INT8_RELEASE(value, new_value) value = new_value
|
2024-02-14 12:15:05 -08:00
|
|
|
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) value = new_value
|
gh-132657: Add lock-free set contains implementation (#132290)
This roughly follows what was done for dictobject to make a lock-free
lookup operation. With this change, the set contains operation scales much
better when used from multiple-threads. The frozenset contains performance
seems unchanged (as already lock-free).
Summary of changes:
* refactor set_lookkey() into set_do_lookup() which now takes a function
pointer that does the entry comparison. This is similar to dictobject and
do_lookup(). In an optimized build, the comparison function is inlined and
there should be no performance cost to this.
* change set_do_lookup() to return a status separately from the entry value
* add set_compare_frozenset() and use if the object is a frozenset. For the
free-threaded build, this avoids some overhead (locking, atomic operations,
incref/decref on key)
* use FT_ATOMIC_* macros as needed for atomic loads and stores
* use a deferred free on the set table array, if shared (only on free-threaded
build, normal build always does an immediate free)
* for free-threaded build, use explicit for loop to zero the table, rather than memcpy()
* when mutating the set, assign so->table to NULL while the change is a
happening. Assign the real table array after the change is done.
2025-12-13 01:50:23 -08:00
|
|
|
#define FT_ATOMIC_STORE_SSIZE_RELEASE(value, new_value) value = new_value
|
2024-04-19 14:47:42 -07:00
|
|
|
#define FT_ATOMIC_STORE_UINT8_RELAXED(value, new_value) value = new_value
|
2024-04-30 11:38:05 -07:00
|
|
|
#define FT_ATOMIC_STORE_UINT16_RELAXED(value, new_value) value = new_value
|
2024-04-30 12:37:38 -07:00
|
|
|
#define FT_ATOMIC_STORE_UINT32_RELAXED(value, new_value) value = new_value
|
2024-12-03 15:41:53 +01:00
|
|
|
#define FT_ATOMIC_LOAD_CHAR_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_CHAR_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_LOAD_UCHAR_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_UCHAR_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_LOAD_SHORT_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_SHORT_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_LOAD_USHORT_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_USHORT_RELAXED(value, new_value) value = new_value
|
2025-11-26 12:40:45 -08:00
|
|
|
#define FT_ATOMIC_LOAD_INT(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_INT(value, new_value) value = new_value
|
2024-12-03 15:41:53 +01:00
|
|
|
#define FT_ATOMIC_LOAD_INT_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_INT_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_LOAD_UINT_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_UINT_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_LOAD_LONG_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_LONG_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_STORE_ULONG_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_STORE_SSIZE_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_LOAD_FLOAT_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_FLOAT_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_LOAD_DOUBLE_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_DOUBLE_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_LOAD_LLONG_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_LLONG_RELAXED(value, new_value) value = new_value
|
|
|
|
|
#define FT_ATOMIC_LOAD_ULLONG_RELAXED(value) value
|
|
|
|
|
#define FT_ATOMIC_STORE_ULLONG_RELAXED(value, new_value) value = new_value
|
2025-04-14 12:31:19 -04:00
|
|
|
#define FT_ATOMIC_ADD_SSIZE(value, new_value) (void)(value += new_value)
|
2025-08-07 11:24:50 -04:00
|
|
|
#define FT_MUTEX_LOCK(lock) do {} while (0)
|
|
|
|
|
#define FT_MUTEX_UNLOCK(lock) do {} while (0)
|
2024-04-30 12:37:38 -07:00
|
|
|
|
2024-02-14 12:15:05 -08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef __cplusplus
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
#endif /* !Py_ATOMIC_FT_WRAPPERS_H */
|