commit f1579ec8008ba0ecd23fb15b50a5bd7c31914e0f
parent 4fb283481e04e126d68ef82fcf89f39fd256a5e9
Author: Evgeny Grin (Karlson2k) <k2k@drgrin.dev>
Date: Thu, 5 Jun 2025 00:50:44 +0200
Implemented and used counters based on atomic variables
Diffstat:
3 files changed, 188 insertions(+), 3 deletions(-)
diff --git a/configure.ac b/configure.ac
@@ -1472,6 +1472,108 @@ AS_CASE([${mhd_cv_cc_kwd_fallthrough}],
CFLAGS_ac="${save_CFLAGS_ac}"
CFLAGS="${CFLAGS_ac} ${user_CFLAGS}"
+# Check for full support of atomic variables
+AC_CACHE_CHECK([whether $CC supports atomic variables],
+ [mhd_cv_c_atomic_variables],
+ [
+ AC_COMPILE_IFELSE(
+ [
+ AC_LANG_SOURCE(
+ [[
+#include <stdatomic.h>
+
+#ifdef __STDC_NO_ATOMICS__
+#error __STDC_NO_ATOMICS__ is declared
+choke me now
+#endif
+
+int main(void)
+{
+ volatile _Atomic int atmc_var;
+ int natmc_var;
+
+ atomic_init(&atmc_var, 0);
+
+ if (0 == atomic_exchange_explicit(&atmc_var, 16, memory_order_relaxed))
+ atomic_store_explicit(&atmc_var, 7, memory_order_release);
+
+ natmc_var = atomic_fetch_add_explicit(&atmc_var, 15, memory_order_acq_rel);
+
+ natmc_var = atomic_fetch_sub_explicit(&atmc_var, natmc_var, memory_order_relaxed);
+
+ natmc_var = atomic_fetch_or_explicit(&atmc_var, natmc_var, memory_order_seq_cst);
+
+ natmc_var = atomic_fetch_and_explicit(&atmc_var, natmc_var, memory_order_relaxed);
+
+ natmc_var = atomic_fetch_xor_explicit(&atmc_var, natmc_var, memory_order_release);
+
+ return natmc_var + 1 - atomic_load_explicit(&atmc_var, memory_order_acquire);
+}
+ ]]
+ )
+ ],
+ [mhd_cv_c_atomic_variables="yes"],[mhd_cv_c_atomic_variables="no"]
+ )
+ ]
+)
+AS_VAR_IF([mhd_cv_c_atomic_variables],["yes"],
+ [
+ AC_DEFINE([MHD_SUPPORT_ATOMIC_VARIABLES],[1],[Define to 1 i][f atomic variables are fully supported])
+ AC_DEFINE([MHD_SUPPORT_ATOMIC_COUNTERS],[1],[Define to 1 i][f counter subset of atomic operations is supported])
+ ],
+ [
+ # Check for minimal atomic variables support
+ AC_CACHE_CHECK([whether $CC supports atomic counters],
+ [mhd_cv_c_atomic_counters],
+ [
+ AC_COMPILE_IFELSE(
+ [
+ AC_LANG_SOURCE(
+ [[
+#if defined(HAVE_STDDEF_H)
+# include <stddef.h> /* size_t */
+#elif defined(HAVE_STDLIB_H)
+# include <stdlib.h> /* should provide size_t */
+#else
+# include <stdio.h> /* should provide size_t */
+#endif
+#ifdef HAVE_CRTDEFS_H
+# include <crtdefs.h> /* W32-specific header */
+#endif
+
+#include <stdatomic.h>
+
+#ifdef __STDC_NO_ATOMICS__
+#error __STDC_NO_ATOMICS__ is declared
+choke me now
+#endif
+
+int main(void)
+{
+ volatile _Atomic size_t cntr;
+
+ atomic_init(&cntr, 0);
+
+ atomic_fetch_add_explicit(&cntr, 1, memory_order_relaxed);
+ atomic_fetch_sub_explicit(&cntr, 1, memory_order_release);
+
+ return
+ (0u == atomic_load_explicit(&cntr, memory_order_relaxed)) ?
+ 0 : 2;
+}
+ ]]
+ )
+ ],
+ [mhd_cv_c_atomic_counters="yes"],[mhd_cv_c_atomic_counters="no"]
+ )
+ ]
+ )
+ AS_VAR_IF([mhd_cv_c_atomic_counters],["yes"],
+ [AC_DEFINE([MHD_SUPPORT_ATOMIC_COUNTERS],[1],[Define to 1 i][f counter subset of atomic operations is supported])]
+ )
+ ]
+)
+
AC_CHECK_HEADERS([stdalign.h], [], [], [AC_INCLUDES_DEFAULT])
AC_CACHE_CHECK([[for C11 'alignof()' support]], [[mhd_cv_c_alignof]],
[AC_COMPILE_IFELSE(
diff --git a/src/incl_priv/mhd_sys_options.h b/src/incl_priv/mhd_sys_options.h
@@ -554,6 +554,8 @@
# define MHD_NORETURN_ __attribute__((__noreturn__))
# undef mhd_FALLTHROUGH
# define mhd_FALLTHROUGH ((void) 0)
+# undef _Atomic
+# define _Atomic /* empty */
#endif
/* Avoid interference with third-party headers */
diff --git a/src/mhd2/mhd_atomic_counter.h b/src/mhd2/mhd_atomic_counter.h
@@ -48,10 +48,18 @@
#ifdef MHD_SUPPORT_THREADS
+# if defined(MHD_SUPPORT_ATOMIC_COUNTERS) && !defined(__STDC_NO_ATOMICS__)
+
+/**
+ * Atomic operations are based native compiler support for atomics
+ */
+# define mhd_ATOMIC_NATIVE 1
+# else
/**
* Atomic operations are based on locks
*/
-# define mhd_ATOMIC_BY_LOCKS 1
+# define mhd_ATOMIC_BY_LOCKS 1
+# endif
#else /* ! MHD_SUPPORT_THREADS */
@@ -61,8 +69,21 @@
# define mhd_ATOMIC_SINGLE_THREAD 1
#endif /* ! MHD_SUPPORT_THREADS */
+#if defined(mhd_ATOMIC_NATIVE)
+# include <stdatomic.h>
+
+/**
+ * The atomic counter
+ */
+struct mhd_AtomicCounter
+{
+ /**
+ * Counter value.
+ */
+ volatile _Atomic mhd_ATOMIC_COUNTER_TYPE count;
+};
-#if defined(mhd_ATOMIC_BY_LOCKS)
+#elif defined(mhd_ATOMIC_BY_LOCKS)
# include "mhd_locks.h"
# include "sys_bool_type.h"
@@ -98,7 +119,67 @@ struct mhd_AtomicCounter
#endif /* mhd_ATOMIC_SINGLE_THREAD */
-#if defined(mhd_ATOMIC_BY_LOCKS)
+#if defined(mhd_ATOMIC_NATIVE)
+
+/**
+ * Initialise the counter to specified value.
+ * @param pcnt the pointer to the counter to initialise
+ * @param initial_value the initial value for the counter
+ * @return 'true' if succeed, "false' if failed
+ * @warning Must not be called for the counters that has been initialised
+ * already.
+ */
+# define mhd_atomic_counter_init(pcnt,initial_value) \
+ (atomic_init (&((pcnt)->count), (initial_value)), (! 0))
+
+/**
+ * Deinitialise the counter.
+ * @param pcnt the pointer to the counter to deinitialise
+ * @warning Must be called only for the counters that has been initialised.
+ */
+# define mhd_atomic_counter_deinit(pcnt) ((void) 0)
+
+/**
+ * Atomically increment the value of the counter
+ * @param pcnt the pointer to the counter to increment
+ */
+# define mhd_atomic_counter_inc(pcnt) \
+ do { atomic_fetch_add_explicit(&((pcnt)->count), 1, \
+ memory_order_relaxed); } while (0)
+
+/**
+ * Atomically increment the value of the counter and return the result
+ * @param pcnt the pointer to the counter to increment
+ * @return the final/resulting counter value
+ */
+# define mhd_atomic_counter_inc_get(pcnt) \
+ (atomic_fetch_add_explicit(&((pcnt)->count), 1, memory_order_relaxed) + 1)
+
+/**
+ * Atomically decrement the value of the counter and return the result
+ * @param pcnt the pointer to the counter to decrement
+ * @return the final/resulting counter value
+ */
+# define mhd_atomic_counter_dec_get(pcnt) \
+ (atomic_fetch_sub_explicit(&((pcnt)->count), 1, memory_order_release) - 1)
+
+/**
+ * Atomically get the value of the counter
+ * @param pcnt the pointer to the counter to get
+ * @return the counter value
+ */
+# define mhd_atomic_counter_get(pcnt) \
+ (atomic_load_explicit(&((pcnt)->count), memory_order_relaxed))
+
+/**
+ * Atomically increment the value of the counter and return the result.
+ * The value is allowed to overflow and get back to zero.
+ * @param pcnt the pointer to the counter to increment
+ * @return the final/resulting counter value
+ */
+# define mhd_atomic_counter_inc_wrap_get(pcnt) \
+ mhd_atomic_counter_inc_get (pcnt)
+#elif defined(mhd_ATOMIC_BY_LOCKS)
/**
* Initialise the counter to specified value.