[前][次][番号順一覧][スレッド一覧]

ruby-changes:68075

From: =E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3 <ko1@a...>
Date: Wed, 22 Sep 2021 16:37:29 +0900 (JST)
Subject: [ruby-changes:68075] ecaf3a391d (master): include/ruby/atomic.h: rework

https://git.ruby-lang.org/ruby.git/commit/?id=ecaf3a391d

From ecaf3a391d7f84ea8893d75940c1958aa2374b68 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=8D=9C=E9=83=A8=E6=98=8C=E5=B9=B3?=
 <shyouhei@r...>
Date: Wed, 15 Sep 2021 16:46:47 +0900
Subject: include/ruby/atomic.h: rework

Reduce macros to do the same things in inline functions instead.  This
way assertions can be made granular.
---
 include/ruby/atomic.h | 942 +++++++++++++++++++++++++++++++++++---------------
 1 file changed, 664 insertions(+), 278 deletions(-)

diff --git a/include/ruby/atomic.h b/include/ruby/atomic.h
index 8665de6..07aa10c 100644
--- a/include/ruby/atomic.h
+++ b/include/ruby/atomic.h
@@ -24,182 +24,82 @@ https://github.com/ruby/ruby/blob/trunk/include/ruby/atomic.h#L24
  * redundant.  Sadly we cannot.  We have to do them ourselves.
  */
 
-/*
- * - RUBY_ATOMIC_CAS, RUBY_ATOMIC_EXCHANGE, RUBY_ATOMIC_FETCH_*:
- *   return the old value.
- * - RUBY_ATOMIC_ADD, RUBY_ATOMIC_SUB, RUBY_ATOMIC_INC, RUBY_ATOMIC_DEC, RUBY_ATOMIC_OR, RUBY_ATOMIC_SET:
- *   may be void.
- */
-#if 0
-#elif defined HAVE_GCC_ATOMIC_BUILTINS
-typedef unsigned int rb_atomic_t;
-# define RUBY_ATOMIC_FETCH_ADD(var, val) __atomic_fetch_add(&(var), (val), __ATOMIC_SEQ_CST)
-# define RUBY_ATOMIC_FETCH_SUB(var, val) __atomic_fetch_sub(&(var), (val), __ATOMIC_SEQ_CST)
-# define RUBY_ATOMIC_OR(var, val) __atomic_fetch_or(&(var), (val), __ATOMIC_SEQ_CST)
-# define RUBY_ATOMIC_EXCHANGE(var, val) __atomic_exchange_n(&(var), (val), __ATOMIC_SEQ_CST)
-# define RUBY_ATOMIC_CAS(var, oldval, newval) RB_GNUC_EXTENSION_BLOCK( \
-   __typeof__(var) oldvaldup = (oldval); /* oldval should not be modified */ \
-   __atomic_compare_exchange_n(&(var), &oldvaldup, (newval), 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); \
-   oldvaldup )
-
-# define RUBY_ATOMIC_GENERIC_MACRO 1
-
-#elif defined HAVE_GCC_SYNC_BUILTINS
-/* @shyouhei hack to support atomic operations in case of gcc. Gcc
- * has its own pseudo-insns to support them.  See info, or
- * http://gcc.gnu.org/onlinedocs/gcc/Atomic-Builtins.html */
-
-typedef unsigned int rb_atomic_t; /* Anything OK */
-# define RUBY_ATOMIC_FETCH_ADD(var, val) __sync_fetch_and_add(&(var), (val))
-# define RUBY_ATOMIC_FETCH_SUB(var, val) __sync_fetch_and_sub(&(var), (val))
-# define RUBY_ATOMIC_OR(var, val) __sync_fetch_and_or(&(var), (val))
-# define RUBY_ATOMIC_EXCHANGE(var, val) __sync_lock_test_and_set(&(var), (val))
-# define RUBY_ATOMIC_CAS(var, oldval, newval) __sync_val_compare_and_swap(&(var), (oldval), (newval))
-
-# define RUBY_ATOMIC_GENERIC_MACRO 1
+#include "ruby/internal/config.h"
 
-#elif defined _WIN32
-#if RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
-#pragma intrinsic(_InterlockedOr)
+#ifdef STDC_HEADERS
+# include <stddef.h>            /* size_t */
 #endif
-typedef LONG rb_atomic_t;
 
-# define RUBY_ATOMIC_SET(var, val) InterlockedExchange(&(var), (val))
-# define RUBY_ATOMIC_INC(var) InterlockedIncrement(&(var))
-# define RUBY_ATOMIC_DEC(var) InterlockedDecrement(&(var))
-# define RUBY_ATOMIC_FETCH_ADD(var, val) InterlockedExchangeAdd(&(var), (val))
-# define RUBY_ATOMIC_FETCH_SUB(var, val) InterlockedExchangeAdd(&(var), -(LONG)(val))
-#if defined __GNUC__
-# define RUBY_ATOMIC_OR(var, val) __asm__("lock\n\t" "orl\t%1, %0" : "=m"(var) : "Ir"(val))
-#elif RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
-# define RUBY_ATOMIC_OR(var, val) rb_w32_atomic_or(&(var), (val))
-static inline void
-rb_w32_atomic_or(volatile rb_atomic_t *var, rb_atomic_t val)
-{
-#ifdef _M_IX86
-    __asm mov eax, var;
-    __asm mov ecx, val;
-    __asm lock or [eax], ecx;
-#else
-#error unsupported architecture
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>         /* ssize_t */
 #endif
-}
-#else
-# define RUBY_ATOMIC_OR(var, val) _InterlockedOr(&(var), (val))
-#endif
-# define RUBY_ATOMIC_EXCHANGE(var, val) InterlockedExchange(&(var), (val))
-# define RUBY_ATOMIC_CAS(var, oldval, newval) InterlockedCompareExchange(&(var), (newval), (oldval))
-# if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
-static inline rb_atomic_t
-rb_w32_atomic_cas(volatile rb_atomic_t *var, rb_atomic_t oldval, rb_atomic_t newval)
-{
-    return (rb_atomic_t)InterlockedCompareExchange((PVOID *)var, (PVOID)newval, (PVOID)oldval);
-}
-#   undef RUBY_ATOMIC_CAS
-#   define RUBY_ATOMIC_CAS(var, oldval, newval) rb_w32_atomic_cas(&(var), (oldval), (newval))
-# endif
-# ifdef _M_AMD64
-#  define RUBY_ATOMIC_SIZE_ADD(var, val) InterlockedExchangeAdd64((LONG_LONG *)&(var), (val))
-#  define RUBY_ATOMIC_SIZE_SUB(var, val) InterlockedExchangeAdd64((LONG_LONG *)&(var), -(LONG)(val))
-#  define RUBY_ATOMIC_SIZE_INC(var) InterlockedIncrement64(&(var))
-#  define RUBY_ATOMIC_SIZE_DEC(var) InterlockedDecrement64(&(var))
-#  define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) InterlockedExchange64(&(var), (val))
-#  define RUBY_ATOMIC_SIZE_CAS(var, oldval, newval) InterlockedCompareExchange64(&(var), (newval), (oldval))
-# else
-#  define RUBY_ATOMIC_SIZE_ADD(var, val) InterlockedExchangeAdd((LONG *)&(var), (val))
-#  define RUBY_ATOMIC_SIZE_SUB(var, val) InterlockedExchangeAdd((LONG *)&(var), -(LONG)(val))
-#  define RUBY_ATOMIC_SIZE_INC(var) InterlockedIncrement((LONG *)&(var))
-#  define RUBY_ATOMIC_SIZE_DEC(var) InterlockedDecrement((LONG *)&(var))
-#  define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) InterlockedExchange((LONG *)&(var), (val))
-# endif
-
-# ifdef InterlockedExchangePointer
-#   define RUBY_ATOMIC_PTR_EXCHANGE(var, val) InterlockedExchangePointer((PVOID volatile *)&(var), (PVOID)(val))
-# endif /* See below for definitions of other situations */
 
+#if RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+# pragma intrinsic(_InterlockedOr)
 #elif defined(__sun) && defined(HAVE_ATOMIC_H)
-#include <atomic.h>
-typedef unsigned int rb_atomic_t;
-
-# define RUBY_ATOMIC_INC(var) atomic_inc_uint(&(var))
-# define RUBY_ATOMIC_DEC(var) atomic_dec_uint(&(var))
-# define RUBY_ATOMIC_FETCH_ADD(var, val) rb_atomic_fetch_add(&(var), (val))
-# define RUBY_ATOMIC_FETCH_SUB(var, val) rb_atomic_fetch_sub(&(var), (val))
-# define RUBY_ATOMIC_ADD(var, val) atomic_add_uint(&(var), (val))
-# define RUBY_ATOMIC_SUB(var, val) atomic_sub_uint(&(var), (val))
-# define RUBY_ATOMIC_OR(var, val) atomic_or_uint(&(var), (val))
-# define RUBY_ATOMIC_EXCHANGE(var, val) atomic_swap_uint(&(var), (val))
-# define RUBY_ATOMIC_CAS(var, oldval, newval) atomic_cas_uint(&(var), (oldval), (newval))
-
-static inline rb_atomic_t
-rb_atomic_fetch_add(volatile rb_atomic_t *var, rb_atomic_t val)
-{
-    return atomic_add_int_nv(var, val) - val;
-}
+# include <atomic.h>
+#endif
 
-static inline rb_atomic_t
-rb_atomic_fetch_sub(volatile rb_atomic_t *var, rb_atomic_t val)
-{
-    return atomic_add_int_nv(var, (rb_atomic_t)(-(int)val)) + val;
-}
+#include "ruby/assert.h"
+#include "ruby/backward/2/limits.h"
+#include "ruby/internal/attr/artificial.h"
+#include "ruby/internal/attr/noalias.h"
+#include "ruby/internal/attr/nonnull.h"
+#include "ruby/internal/compiler_since.h"
+#include "ruby/internal/cast.h"
+#include "ruby/internal/value.h"
+#include "ruby/internal/static_assert.h"
+#include "ruby/internal/stdbool.h"
 
-# if defined(_LP64) || defined(_I32LPx)
-#  define RUBY_ATOMIC_SIZE_ADD(var, val) atomic_add_long(&(var), (val))
-#  define RUBY_ATOMIC_SIZE_SUB(var, val) atomic_add_long(&(var), -(val))
-#  define RUBY_ATOMIC_SIZE_INC(var) atomic_inc_ulong(&(var))
-#  define RUBY_ATOMIC_SIZE_DEC(var) atomic_dec_ulong(&(var))
-#  define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) atomic_swap_ulong(&(var), (val))
-#  define RUBY_ATOMIC_SIZE_CAS(var, oldval, val) atomic_cas_ulong(&(var), (oldval), (val))
-# else
-#  define RUBY_ATOMIC_SIZE_ADD(var, val) atomic_add_int(&(var), (val))
-#  define RUBY_ATOMIC_SIZE_SUB(var, val) atomic_add_int(&(var), -(val))
-#  define RUBY_ATOMIC_SIZE_INC(var) atomic_inc_uint(&(var))
-#  define RUBY_ATOMIC_SIZE_DEC(var) atomic_dec_uint(&(var))
-#  define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) atomic_swap_uint(&(var), (val))
-# endif
-
-#elif defined(__DOXYGEN__)
-/**
+/*
  * Asserts that  your environment supports  more than one atomic  types.  These
  * days systems tend to have such property  (C11 was a standard of decades ago,
  * right?) but we still support older ones.
  */
+#if defined(__DOXYGEN__) || defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
 # define RUBY_ATOMIC_GENERIC_MACRO 1
+#endif
 
 /**
  * Type  that  is eligible  for  atomic  operations.   Depending on  your  host
  * platform you might have  more than one such type, but we  choose one of them
  * anyways.
  */
-using rb_atomic_t = std::atomic<std::uintptr_t>;
+#if defined(__DOXYGEN__)
+using rb_atomic_t = std::atomic<unsigned>;
+#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+typedef unsigned int rb_atomic_t;
+#elif defined(HAVE_GCC_SYNC_BUILTINS)
+typedef unsigned int rb_atomic_t;
+#elif defined(_WIN32)
+typedef LONG rb_atomic_t;
+#elif defined(__sun) && defined(HAVE_ATOMIC_H)
+typedef unsigned int rb_atomic_t;
+#else
+# error No atomic operation found
+#endif
 
 /**
  * Atomically replaces the  value pointed by `var` with the  result of addition
- * of `val` to  the old value of `var`.  In  case #RUBY_ATOMIC_GENERIC_MACRO is
- * set, this  operation could  be applied  to a  signed integer  type.  However
- * there is  no portabe way  to know what happens  on integer overflow  on such
- * situations.  You might better stick to unsigned types.
+ * of `val` to the old value of `var`.
  *
  * @param   var  A variable of ::rb_atomic_t.
  * @param   val  Value to add.
  * @return  What was stored in `var` before the addition.
  * @post    `var` holds `var + val`.
  */
-# define RUBY_ATOMIC_FETCH_ADD(var, val) std::atomic_fetch_add(&(var), val)
+#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val))
 
 /**
- * Atomically replaces the  value pointed by `var` with the  result of addition
- * of `val` to  the old value of `var`.  In  case #RUBY_ATOMIC_GENERIC_MACRO is
- * set, this  operation could  be applied  to a  signed integer  type.  However
- * there is  no portabe way  to know what happens  on integer overflow   (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]