Add RUBY_ATOMIC_{PTR_,}FETCH macros for atomic loads

This can already be emulated by doing an atomic fetch_add of zero, but
this is more explicit.

[Bug #19994]
This commit is contained in:
KJ Tsanaktsidis 2023-11-19 22:54:01 +11:00 коммит произвёл Koichi Sasada
Родитель 6e8ad7497e
Коммит aecbd66742
1 изменённых файлов: 51 добавлений и 0 удалений

Просмотреть файл

@ -138,6 +138,15 @@ typedef unsigned int rb_atomic_t;
#define RUBY_ATOMIC_CAS(var, oldval, newval) \
rbimpl_atomic_cas(&(var), (oldval), (newval))
/**
* Atomic load. This loads `var` with an atomic intrinsic and returns
* its value.
*
* @param var A variable of ::rb_atomic_t
* @return What was stored in `var`j
*/
#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var))
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except for the return type.
*
@ -279,6 +288,17 @@ typedef unsigned int rb_atomic_t;
#define RUBY_ATOMIC_PTR_EXCHANGE(var, val) \
RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val))
/**
* Identical to #RUBY_ATOMIC_LOAD, except it expects its arguments are `void*`.
* There are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This
* should be used for size related operations to support such platforms.
*
* @param var A variable of `void*`
* @return The value of `var` (without tearing)
*/
#define RUBY_ATOMIC_PTR_LOAD(var) \
RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var))
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `void*`.
* There are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This
@ -746,6 +766,21 @@ rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val)
return RBIMPL_CAST((VALUE)sret);
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
rbimpl_atomic_load(volatile rb_atomic_t *ptr)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
#else
return rbimpl_atomic_fetch_add(ptr, 0);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
@ -872,6 +907,22 @@ rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void *
rbimpl_atomic_ptr_load(void **ptr)
{
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
#else
void *val = *ptr;
return rbimpl_atomic_ptr_cas(ptr, val, val);
#endif
}
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))