libmicrohttpd2

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

mhd_atomic_counter.h (14129B)


      1 /* SPDX-License-Identifier: LGPL-2.1-or-later OR (GPL-2.0-or-later WITH eCos-exception-2.0) */
      2 /*
      3   This file is part of GNU libmicrohttpd.
      4   Copyright (C) 2024-2025 Evgeny Grin (Karlson2k)
      5 
      6   GNU libmicrohttpd is free software; you can redistribute it and/or
      7   modify it under the terms of the GNU Lesser General Public
      8   License as published by the Free Software Foundation; either
      9   version 2.1 of the License, or (at your option) any later version.
     10 
     11   GNU libmicrohttpd is distributed in the hope that it will be useful,
     12   but WITHOUT ANY WARRANTY; without even the implied warranty of
     13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     14   Lesser General Public License for more details.
     15 
     16   Alternatively, you can redistribute GNU libmicrohttpd and/or
     17   modify it under the terms of the GNU General Public License as
     18   published by the Free Software Foundation; either version 2 of
     19   the License, or (at your option) any later version, together
     20   with the eCos exception, as follows:
     21 
     22     As a special exception, if other files instantiate templates or
     23     use macros or inline functions from this file, or you compile this
     24     file and link it with other works to produce a work based on this
     25     file, this file does not by itself cause the resulting work to be
     26     covered by the GNU General Public License. However the source code
     27     for this file must still be made available in accordance with
     28     section (3) of the GNU General Public License v2.
     29 
     30     This exception does not invalidate any other reasons why a work
     31     based on this file might be covered by the GNU General Public
     32     License.
     33 
     34   You should have received copies of the GNU Lesser General Public
     35   License and the GNU General Public License along with this library;
     36   if not, see <https://www.gnu.org/licenses/>.
     37 */
     38 
     39 /**
     40  * @file src/mhd2/mhd_atomic_counter.h
     41  * @brief  The definition of the atomic counter type and related functions
     42  *         declarations
     43  * @author Karlson2k (Evgeny Grin)
     44  */
     45 
     46 #ifndef MHD_ATOMIC_COUNTER_H
     47 #define MHD_ATOMIC_COUNTER_H 1
     48 
     49 #include "mhd_sys_options.h"
     50 
     51 #include "mhd_assert.h"
     52 
     53 #include "sys_sizet_type.h"
     54 
     55 /* Use 'size_t' to make sure it would never overflow when used for
     56  * MHD needs. */
     57 
     58 /**
     59  * The type used to contain the counter value.
     60  * Always unsigned.
     61  */
     62 #define mhd_ATOMIC_COUNTER_TYPE size_t
     63 /**
     64  * The maximum counter value
     65  */
     66 #define mhd_ATOMIC_COUNTER_MAX \
     67         ((mhd_ATOMIC_COUNTER_TYPE) (~((mhd_ATOMIC_COUNTER_TYPE) 0)))
     68 
     69 #ifdef MHD_SUPPORT_THREADS
     70 
     71 #  if defined(MHD_SUPPORT_ATOMIC_COUNTERS) && !defined(__STDC_NO_ATOMICS__)
     72 
     73 /**
     74  * Atomic operations are based native compiler support for atomics
     75  */
     76 #    define mhd_ATOMIC_NATIVE 1
     77 #  else
     78 /**
     79  * Atomic operations are based on locks
     80  */
     81 #    define mhd_ATOMIC_BY_LOCKS 1
     82 #  endif
     83 
     84 #else  /* ! MHD_SUPPORT_THREADS */
     85 
     86 /**
     87  * Atomic because single thread environment is used
     88  */
     89 #  define mhd_ATOMIC_SINGLE_THREAD 1
     90 #endif /* ! MHD_SUPPORT_THREADS */
     91 
     92 #if defined(mhd_ATOMIC_NATIVE)
     93 #  include <stdatomic.h>
     94 
     95 /**
     96  * The atomic counter
     97  */
     98 struct mhd_AtomicCounter
     99 {
    100   /**
    101    * Counter value.
    102    */
    103   volatile _Atomic mhd_ATOMIC_COUNTER_TYPE count;
    104 };
    105 
    106 #elif defined(mhd_ATOMIC_BY_LOCKS)
    107 #  include "mhd_locks.h"
    108 #  include "sys_bool_type.h"
    109 
    110 /**
    111  * The atomic counter
    112  */
    113 struct mhd_AtomicCounter
    114 {
    115   /**
    116    * Counter value.
    117    * Must be read or written only with @a lock held.
    118    */
    119   volatile mhd_ATOMIC_COUNTER_TYPE count;
    120   /**
    121    * The mutex.
    122    */
    123   mhd_mutex lock;
    124 };
    125 
    126 #elif defined(mhd_ATOMIC_SINGLE_THREAD)
    127 
    128 /**
    129  * The atomic counter
    130  */
    131 struct mhd_AtomicCounter
    132 {
    133   /**
    134    * Counter value.
    135    */
    136   volatile mhd_ATOMIC_COUNTER_TYPE count;
    137 };
    138 
    139 #endif /* mhd_ATOMIC_SINGLE_THREAD */
    140 
    141 
    142 #if defined(mhd_ATOMIC_NATIVE)
    143 
    144 /**
    145  * Initialise the counter to specified value.
    146  * @param pcnt the pointer to the counter to initialise
    147  * @param initial_value the initial value for the counter
    148  * @return 'true' if succeed, "false' if failed
    149  * @warning Must not be called for the counters that has been initialised
    150  *          already.
    151  */
    152 #  define mhd_atomic_counter_init(pcnt, initial_value) \
    153           (atomic_init (&((pcnt)->count), (initial_value)), (! 0))
    154 
    155 /**
    156  * Deinitialise the counter.
    157  * @param pcnt the pointer to the counter to deinitialise
    158  * @warning Must be called only for the counters that has been initialised.
    159  */
    160 #  define mhd_atomic_counter_deinit(pcnt) ((void) 0)
    161 
    162 /**
    163  * Get the value of the counter and atomically increment the counter.
    164  * The value may overflow and wrap back to zero.
    165  * @param pcnt the pointer to the counter to increment
    166  * @return the counter value before the increment
    167  */
    168 #  define mhd_atomic_counter_get_inc_wrap(pcnt)   \
    169           atomic_fetch_add_explicit (&((pcnt)->count), \
    170                                      1, memory_order_relaxed)
    171 
    172 #  ifdef NDEBUG
    173 /**
    174  * Atomically increment the value of the counter.
    175  * Counter overflow is detected in debug builds.
    176  * @param pcnt the pointer to the counter to increment
    177  */
    178 #    define mhd_atomic_counter_inc(pcnt)                   \
    179             do { (void)                                         \
    180                  atomic_fetch_add_explicit (&((pcnt)->count), 1, \
    181                                             memory_order_relaxed); } while (0)
    182 
    183 /**
    184  * Get the value of the counter and atomically increment the counter.
    185  * Counter overflow is detected in debug builds.
    186  * @param pcnt the pointer to the counter to increment
    187  * @return the counter value before the increment
    188  */
    189 #    define mhd_atomic_counter_get_inc(pcnt) \
    190             mhd_atomic_counter_get_inc_wrap ((pcnt))
    191 
    192 /**
    193  * Get the value of the counter and atomically decrement the counter.
    194  * Counter underflow is detected in debug builds.
    195  * @param pcnt the pointer to the counter to decrement
    196  * @return the counter value before the decrement
    197  */
    198 #    define mhd_atomic_counter_get_dec(pcnt)        \
    199             atomic_fetch_sub_explicit (&((pcnt)->count), \
    200                                        1, memory_order_release)
    201 #  else  /* _DEBUG */
    202 /**
    203  * Atomically increment the value of the counter.
    204  * Counter overflow is detected in debug builds.
    205  * @param pcnt the pointer to the counter to increment
    206  */
    207 #    define mhd_atomic_counter_inc(pcnt)                      \
    208             do { mhd_ATOMIC_COUNTER_TYPE old_val =                 \
    209                    atomic_fetch_add_explicit (&((pcnt)->count), 1,  \
    210                                               memory_order_relaxed); \
    211                  mhd_assert (mhd_ATOMIC_COUNTER_MAX != old_val); } while (0)
    212 
    213 /**
    214  * Get the value of the counter and atomically increment the counter.
    215  * Counter overflow is detected in debug builds.
    216  * @param pcnt the pointer to the counter to increment
    217  * @return the counter value before the increment
    218  */
    219 mhd_static_inline mhd_ATOMIC_COUNTER_TYPE
    220 mhd_atomic_counter_get_inc (struct mhd_AtomicCounter *pcnt)
    221 {
    222   mhd_ATOMIC_COUNTER_TYPE ret;
    223 
    224   ret = mhd_atomic_counter_get_inc_wrap (pcnt);
    225 
    226   mhd_assert (mhd_ATOMIC_COUNTER_MAX != ret);
    227 
    228   return ret;
    229 }
    230 
    231 
    232 /**
    233  * Get the value of the counter and atomically decrement the counter.
    234  * Counter underflow is detected in debug builds.
    235  * @param pcnt the pointer to the counter to decrement
    236  * @return the counter value before the decrement
    237  */
    238 mhd_static_inline mhd_ATOMIC_COUNTER_TYPE
    239 mhd_atomic_counter_get_dec (struct mhd_AtomicCounter *pcnt)
    240 {
    241   mhd_ATOMIC_COUNTER_TYPE ret;
    242 
    243   ret = atomic_fetch_sub_explicit (&((pcnt)->count), 1, memory_order_relaxed);
    244 
    245   mhd_assert (0 != ret);
    246 
    247   return ret;
    248 }
    249 
    250 
    251 #  endif /* _DEBUG */
    252 
    253 /**
    254  * Atomically get the value of the counter.
    255  * @param pcnt the pointer to the counter to get
    256  * @return the counter value
    257  */
    258 #  define mhd_atomic_counter_get(pcnt) \
    259           (atomic_load_explicit (&((pcnt)->count), memory_order_relaxed))
    260 
    261 #elif defined(mhd_ATOMIC_BY_LOCKS)
    262 
    263 /**
    264  * Initialise the counter to specified value.
    265  * @param pcnt the pointer to the counter to initialise
    266  * @param initial_value the initial value for the counter
    267  * @return 'true' if succeed, "false' if failed
    268  * @warning Must not be called for the counters that has been initialised
    269  *          already.
    270  */
    271 #  define mhd_atomic_counter_init(pcnt, initial_value) \
    272           ((pcnt)->count = (initial_value),             \
    273            mhd_mutex_init_short (&((pcnt)->lock)))
    274 
    275 /**
    276  * Deinitialise the counter.
    277  * @param pcnt the pointer to the counter to deinitialise
    278  * @warning Must be called only for the counters that has been initialised.
    279  */
    280 #  define mhd_atomic_counter_deinit(pcnt) \
    281           mhd_mutex_destroy_chk (&((pcnt)->lock))
    282 /**
    283  * Get the value of the counter and atomically increment the counter.
    284  * The value may overflow and wrap back to zero.
    285  * @param pcnt the pointer to the counter to increment
    286  * @return the counter value before the increment
    287  */
    288 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
    289 mhd_atomic_counter_get_inc_wrap (struct mhd_AtomicCounter *pcnt);
    290 
    291 #  ifdef NDEBUG
    292 
    293 /**
    294  * Atomically increment the value of the counter.
    295  * Counter overflow is detected in debug builds.
    296  * @param pcnt the pointer to the counter to increment
    297  */
    298 #    define mhd_atomic_counter_inc(pcnt)  do { \
    299             mhd_mutex_lock_chk (&((pcnt)->lock)); \
    300             ++((pcnt)->count);                     \
    301             mhd_mutex_unlock_chk (&((pcnt)->lock)); } while (0)
    302 
    303 /**
    304  * Get the value of the counter and atomically increment the counter.
    305  * Counter overflow is detected in debug builds.
    306  * @param pcnt the pointer to the counter to increment
    307  * @return the counter value before the increment
    308  */
    309 #    define mhd_atomic_counter_get_inc(pcnt) \
    310             mhd_atomic_counter_get_inc_wrap (pcnt)
    311 
    312 #  else
    313 
    314 /**
    315  * Atomically increment the value of the counter.
    316  * Counter overflow is detected in debug builds.
    317  * @param pcnt the pointer to the counter to increment
    318  */
    319 #    define mhd_atomic_counter_inc(pcnt)  do {\
    320             mhd_ATOMIC_COUNTER_TYPE old_val;     \
    321             mhd_mutex_lock_chk (&((pcnt)->lock)); \
    322             old_val = (pcnt)->count++;             \
    323             mhd_mutex_unlock_chk (&((pcnt)->lock)); \
    324             mhd_assert (mhd_ATOMIC_COUNTER_MAX != old_val); } while (0)
    325 
    326 /**
    327  * Get the value of the counter and atomically increment the counter.
    328  * Counter overflow is detected in debug builds.
    329  * @param pcnt the pointer to the counter to increment
    330  * @return the counter value before the increment
    331  */
    332 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
    333 mhd_atomic_counter_get_inc (struct mhd_AtomicCounter *pcnt);
    334 
    335 #  endif
    336 
    337 /**
    338  * Get the value of the counter and atomically decrement the counter.
    339  * Counter underflow is detected in debug builds.
    340  * @param pcnt the pointer to the counter to decrement
    341  * @return the counter value before the decrement
    342  */
    343 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
    344 mhd_atomic_counter_get_dec (struct mhd_AtomicCounter *pcnt);
    345 
    346 /**
    347  * Atomically get the value of the counter.
    348  * @param pcnt the pointer to the counter to get
    349  * @return the counter value
    350  */
    351 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
    352 mhd_atomic_counter_get (struct mhd_AtomicCounter *pcnt);
    353 
    354 #elif defined(mhd_ATOMIC_SINGLE_THREAD)
    355 
    356 /**
    357  * Initialise the counter to specified value.
    358  * @param pcnt the pointer to the counter to initialise
    359  * @param initial_value the initial value for the counter
    360  * @return 'true' if succeed, "false' if failed
    361  * @warning Must not be called for the counters that has been initialised
    362  *          already.
    363  */
    364 #  define mhd_atomic_counter_init(pcnt, initial_value) \
    365           ((pcnt)->count = (initial_value), (! 0))
    366 
    367 /**
    368  * Deinitialise the counter.
    369  * @param pcnt the pointer to the counter to deinitialise
    370  * @warning Must be called only for the counters that has been initialised.
    371  */
    372 #  define mhd_atomic_counter_deinit(pcnt) ((void) 0)
    373 
    374 /**
    375  * Get the value of the counter and atomically increment the counter.
    376  * The value may overflow and wrap back to zero.
    377  * @param pcnt the pointer to the counter to increment
    378  * @return the counter value before the increment
    379  */
    380 #  define mhd_atomic_counter_get_inc_wrap(pcnt) ((pcnt)->count++)
    381 
    382 /**
    383  * Atomically increment the value of the counter.
    384  * Counter overflow is detected in debug builds.
    385  * @param pcnt the pointer to the counter to increment
    386  */
    387 #  define mhd_atomic_counter_inc(pcnt)  \
    388           do { mhd_assert (mhd_ATOMIC_COUNTER_MAX != ((pcnt)->count)); \
    389                ++((pcnt)->count); } while (0)
    390 
    391 #  ifdef NDEBUG
    392 /**
    393  * Get the value of the counter and atomically increment the counter.
    394  * Counter overflow is detected in debug builds.
    395  * @param pcnt the pointer to the counter to increment
    396  * @return the counter value before the increment
    397  */
    398 #    define mhd_atomic_counter_get_inc(pcnt) \
    399             mhd_atomic_counter_get_inc_wrap ((pcnt))
    400 
    401 /**
    402  * Get the value of the counter and atomically decrement the counter.
    403  * Counter underflow is detected in debug builds.
    404  * @param pcnt the pointer to the counter to decrement
    405  * @return the counter value before the decrement
    406  */
    407 #    define mhd_atomic_counter_get_dec(pcnt) ((pcnt)->count--)
    408 
    409 #  else  /* _DEBUG */
    410 /**
    411  * Get the value of the counter and atomically increment the counter.
    412  * Counter overflow is detected in debug builds.
    413  * @param pcnt the pointer to the counter to increment
    414  * @return the counter value before the increment
    415  */
    416 mhd_static_inline mhd_ATOMIC_COUNTER_TYPE
    417 mhd_atomic_counter_get_inc (struct mhd_AtomicCounter *pcnt)
    418 {
    419   mhd_assert (mhd_ATOMIC_COUNTER_MAX != (pcnt->count));
    420 
    421   return mhd_atomic_counter_get_inc_wrap (pcnt);
    422 }
    423 
    424 
    425 /**
    426  * Get the value of the counter and atomically decrement the counter.
    427  * Counter underflow is detected in debug builds.
    428  * @param pcnt the pointer to the counter to decrement
    429  * @return the counter value before the decrement
    430  */
    431 mhd_static_inline mhd_ATOMIC_COUNTER_TYPE
    432 mhd_atomic_counter_get_dec (struct mhd_AtomicCounter *pcnt)
    433 {
    434   mhd_assert (0 != ((pcnt)->count));
    435 
    436   return ((pcnt)->count--);
    437 }
    438 
    439 
    440 #  endif /* _DEBUG */
    441 
    442 /**
    443  * Atomically get the value of the counter.
    444  * @param pcnt the pointer to the counter to get
    445  * @return the counter value
    446  */
    447 #  define mhd_atomic_counter_get(pcnt) ((pcnt)->count)
    448 
    449 #endif /* mhd_ATOMIC_SINGLE_THREAD */
    450 
    451 #endif /* ! MHD_ATOMIC_COUNTER_H */