libmicrohttpd2

HTTP server C library (MHD 2.x, alpha)
Log | Files | Refs | README | LICENSE

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:
Mconfigure.ac | 102+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/incl_priv/mhd_sys_options.h | 2++
Msrc/mhd2/mhd_atomic_counter.h | 87++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
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.