libmicrohttpd2

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

mhd_atomic_counter.h (14022B)


      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) mhd_atomic_counter_get_inc_wrap (pcnt)
    310 
    311 #else
    312 
    313 /**
    314  * Atomically increment the value of the counter.
    315  * Counter overflow is detected in debug builds.
    316  * @param pcnt the pointer to the counter to increment
    317  */
    318 #  define mhd_atomic_counter_inc(pcnt)  do {  \
    319           mhd_ATOMIC_COUNTER_TYPE old_val;     \
    320           mhd_mutex_lock_chk (&((pcnt)->lock)); \
    321           old_val = (pcnt)->count++;             \
    322           mhd_mutex_unlock_chk (&((pcnt)->lock)); \
    323           mhd_assert (mhd_ATOMIC_COUNTER_MAX != old_val); } while (0)
    324 
    325 /**
    326  * Get the value of the counter and atomically increment the counter.
    327  * Counter overflow is detected in debug builds.
    328  * @param pcnt the pointer to the counter to increment
    329  * @return the counter value before the increment
    330  */
    331 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
    332 mhd_atomic_counter_get_inc (struct mhd_AtomicCounter *pcnt);
    333 
    334 #endif
    335 
    336 /**
    337  * Get the value of the counter and atomically decrement the counter.
    338  * Counter underflow is detected in debug builds.
    339  * @param pcnt the pointer to the counter to decrement
    340  * @return the counter value before the decrement
    341  */
    342 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
    343 mhd_atomic_counter_get_dec (struct mhd_AtomicCounter *pcnt);
    344 
    345 /**
    346  * Atomically get the value of the counter.
    347  * @param pcnt the pointer to the counter to get
    348  * @return the counter value
    349  */
    350 MHD_INTERNAL mhd_ATOMIC_COUNTER_TYPE
    351 mhd_atomic_counter_get (struct mhd_AtomicCounter *pcnt);
    352 
    353 #elif defined(mhd_ATOMIC_SINGLE_THREAD)
    354 
    355 /**
    356  * Initialise the counter to specified value.
    357  * @param pcnt the pointer to the counter to initialise
    358  * @param initial_value the initial value for the counter
    359  * @return 'true' if succeed, "false' if failed
    360  * @warning Must not be called for the counters that has been initialised
    361  *          already.
    362  */
    363 #  define mhd_atomic_counter_init(pcnt,initial_value) \
    364         ((pcnt)->count = (initial_value), (! 0))
    365 
    366 /**
    367  * Deinitialise the counter.
    368  * @param pcnt the pointer to the counter to deinitialise
    369  * @warning Must be called only for the counters that has been initialised.
    370  */
    371 #  define mhd_atomic_counter_deinit(pcnt) ((void) 0)
    372 
    373 /**
    374  * Get the value of the counter and atomically increment the counter.
    375  * The value may overflow and wrap back to zero.
    376  * @param pcnt the pointer to the counter to increment
    377  * @return the counter value before the increment
    378  */
    379 #  define mhd_atomic_counter_get_inc_wrap(pcnt) ((pcnt)->count++)
    380 
    381 /**
    382  * Atomically increment the value of the counter.
    383  * Counter overflow is detected in debug builds.
    384  * @param pcnt the pointer to the counter to increment
    385  */
    386 #  define mhd_atomic_counter_inc(pcnt)  \
    387         do { mhd_assert (mhd_ATOMIC_COUNTER_MAX != ((pcnt)->count)); \
    388              ++((pcnt)->count); } while (0)
    389 
    390 #  ifdef NDEBUG
    391 /**
    392  * Get the value of the counter and atomically increment the counter.
    393  * Counter overflow is detected in debug builds.
    394  * @param pcnt the pointer to the counter to increment
    395  * @return the counter value before the increment
    396  */
    397 #    define mhd_atomic_counter_get_inc(pcnt) \
    398         mhd_atomic_counter_get_inc_wrap ((pcnt))
    399 
    400 /**
    401  * Get the value of the counter and atomically decrement the counter.
    402  * Counter underflow is detected in debug builds.
    403  * @param pcnt the pointer to the counter to decrement
    404  * @return the counter value before the decrement
    405  */
    406 #  define mhd_atomic_counter_get_dec(pcnt) ((pcnt)->count--)
    407 
    408 #  else  /* _DEBUG */
    409 /**
    410  * Get the value of the counter and atomically increment the counter.
    411  * Counter overflow is detected in debug builds.
    412  * @param pcnt the pointer to the counter to increment
    413  * @return the counter value before the increment
    414  */
    415 mhd_static_inline mhd_ATOMIC_COUNTER_TYPE
    416 mhd_atomic_counter_get_inc (struct mhd_AtomicCounter *pcnt)
    417 {
    418   mhd_assert (mhd_ATOMIC_COUNTER_MAX != (pcnt->count));
    419 
    420   return mhd_atomic_counter_get_inc_wrap (pcnt);
    421 }
    422 
    423 
    424 /**
    425  * Get the value of the counter and atomically decrement the counter.
    426  * Counter underflow is detected in debug builds.
    427  * @param pcnt the pointer to the counter to decrement
    428  * @return the counter value before the decrement
    429  */
    430 mhd_static_inline mhd_ATOMIC_COUNTER_TYPE
    431 mhd_atomic_counter_get_dec (struct mhd_AtomicCounter *pcnt)
    432 {
    433   mhd_assert (0 != ((pcnt)->count));
    434 
    435   return ((pcnt)->count--);
    436 }
    437 
    438 
    439 #  endif /* _DEBUG */
    440 
    441 /**
    442  * Atomically get the value of the counter.
    443  * @param pcnt the pointer to the counter to get
    444  * @return the counter value
    445  */
    446 #  define mhd_atomic_counter_get(pcnt) ((pcnt)->count)
    447 
    448 #endif /* mhd_ATOMIC_SINGLE_THREAD */
    449 
    450 #endif /* ! MHD_ATOMIC_COUNTER_H */