libmicrohttpd2

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

mhd_locksrw.h (12838B)


      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) 2026 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_locksrw.h
     41  * @brief  Header for platform-independent RW-locks abstraction
     42  * @author Karlson2k (Evgeny Grin)
     43  *
     44  * Provides basic abstraction for read-write locks.
     45  * On some platforms read-only lock can be implemented as full lock.
     46  * Any functions can be implemented as macro unless explicitly marked
     47  * otherwise.
     48  * Any function argument can be skipped in macro, so avoid
     49  * variable modification in function parameters.
     50  *
     51  * @warning Unlike pthread functions, most of functions return
     52  *          nonzero on success.
     53  */
     54 
     55 #ifndef MHD_LOCKSRW_H
     56 #define MHD_LOCKSRW_H 1
     57 
     58 #include "mhd_sys_options.h"
     59 
     60 #ifdef MHD_SUPPORT_THREADS
     61 
     62 #  if defined(mhd_THREADS_KIND_POSIX) && defined(HAVE_PTHREAD_RWLOCKS)
     63 /**
     64  * The RW-lock is pthreads RW-lock
     65  */
     66 #    define mhd_LOCKRW_KIND_PTHREAD     1
     67 #    define mhd_LOCKRW_NATIVE           1
     68 #    define mhd_LOCKRW_IMPLEMENTED      1
     69 #    include <pthread.h>
     70 #    include "sys_null_macro.h"
     71 #  endif
     72 
     73 #  if !defined(mhd_LOCKRW_IMPLEMENTED) && defined(mhd_THREADS_KIND_W32)
     74 #    include "sys_w32_ver.h"
     75 #    if _WIN32_WINNT >= 0x0600 /* Vista or later */
     76 /**
     77  * The RW-lock is W32 SRW lock
     78  */
     79 #      define mhd_LOCKRW_KIND_W32_SRW   1
     80 #      define mhd_LOCKRW_NATIVE         1
     81 #      define mhd_LOCKRW_IMPLEMENTED    1
     82 #      if 0 /* _WIN32_WINNT >= 0x0602 */ /* Win8 or later */
     83             /* This include does not work as _ARM_ or _AMD64_ macros
     84                are missing */
     85 #        include <synchapi.h>
     86 #      else
     87 #        include <windows.h>
     88 #      endif
     89 #    endif
     90 #  endif
     91 
     92 #  if !defined(mhd_LOCKRW_IMPLEMENTED)
     93 #    include "mhd_locks.h"
     94 #    if defined(mhd_MUTEX_IMPLEMENTED) && !defined(mhd_MUTEX_KIND_LOCKRW)
     95 /**
     96  * The RW-lock is dumb mutex without shared read-lock support
     97  */
     98 #      define mhd_LOCKRW_KIND_MUTEX     1
     99 #      define mhd_LOCKRW_DUMB           1
    100 #      define mhd_LOCKRW_IMPLEMENTED    1
    101 #    endif
    102 #  endif
    103 
    104 #  if !defined(mhd_LOCKRW_IMPLEMENTED)
    105 #    error No base RW-locks API is available.
    106 #  endif
    107 
    108 /* Sanity check */
    109 #  ifdef mhd_LOCKRW_KIND_PTHREAD
    110 #    ifndef mhd_LOCKRW_HAS_ONE_IMPLEMENTATION
    111 #      define mhd_LOCKRW_HAS_ONE_IMPLEMENTATION 1
    112 #    else
    113 #      error Multiple RW-locks implementations are enabled simultaneously
    114 #    endif
    115 #  endif
    116 #  ifdef mhd_LOCKRW_KIND_W32_SRW
    117 #    ifndef mhd_LOCKRW_HAS_ONE_IMPLEMENTATION
    118 #      define mhd_LOCKRW_HAS_ONE_IMPLEMENTATION 1
    119 #    else
    120 #      error Multiple RW-locks implementations are enabled simultaneously
    121 #    endif
    122 #  endif
    123 #  ifdef mhd_LOCKRW_KIND_MUTEX
    124 #    ifndef mhd_LOCKRW_HAS_ONE_IMPLEMENTATION
    125 #      define mhd_LOCKRW_HAS_ONE_IMPLEMENTATION 1
    126 #    else
    127 #      error Multiple RW-locks implementations are enabled simultaneously
    128 #    endif
    129 #  endif
    130 #  ifndef mhd_LOCKRW_HAS_ONE_IMPLEMENTATION
    131 #    error Not all RW-locks kinds were checked
    132 #  endif
    133 #  undef mhd_LOCKRW_HAS_ONE_IMPLEMENTATION
    134 
    135 #  include "mhd_panic.h"
    136 
    137 #  if defined(mhd_LOCKRW_KIND_PTHREAD)
    138 typedef pthread_rwlock_t mhd_lockrw;
    139 #  elif defined(mhd_LOCKRW_KIND_W32_SRW)
    140 typedef SRWLOCK mhd_lockrw;
    141 #  elif defined(mhd_LOCKRW_KIND_MUTEX)
    142 typedef mhd_mutex mhd_lockrw;
    143 #  else
    144 #    error RW-locks implementation is missing
    145 #  endif
    146 
    147 /**
    148  * Initialise a new rw-lock.
    149  * @param plock the pointer to the rw-lock
    150  * @return nonzero on success, zero otherwise
    151  */
    152 #  if defined(mhd_LOCKRW_KIND_PTHREAD)
    153 #    define mhd_lockrw_init(plock) (0 == pthread_rwlock_init ((plock), NULL))
    154 #  elif defined(mhd_LOCKRW_KIND_W32_SRW)
    155 #    define mhd_lockrw_init(plock) (InitializeSRWLock ((plock)), ! 0)
    156 #  elif defined(mhd_LOCKRW_KIND_MUTEX)
    157 #    define mhd_lockrw_init(plock) mhd_mutex_init((plock))
    158 #  else
    159 #    error RW-locks implementation is missing
    160 #  endif
    161 
    162 /**
    163  * The value to statically initialise rw-lock
    164  */
    165 #  if defined(mhd_LOCKRW_KIND_PTHREAD)
    166 #    if defined(PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP)
    167 #      define mhd_LOCKRW_INITIALISER_STAT        \
    168               PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
    169 #    elif defined(PTHREAD_RWLOCK_INITIALIZER)
    170 #      define mhd_LOCKRW_INITIALISER_STAT       PTHREAD_RWLOCK_INITIALIZER
    171 #    elif defined(PTHREAD_RWLOCK_INITIALIZER_NP)
    172 #      define mhd_LOCKRW_INITIALISER_STAT       PTHREAD_RWLOCK_INITIALIZER_NP
    173 #    endif
    174 #  elif defined(mhd_LOCKRW_KIND_W32_SRW)
    175 #    if defined(SRWLOCK_INIT)
    176 #      define mhd_LOCKRW_INITIALISER_STAT       SRWLOCK_INIT
    177 #    endif
    178 #  elif defined(mhd_LOCKRW_KIND_MUTEX)
    179 #    if defined(mhd_MUTEX_INITIALISER_STAT)
    180 #      define mhd_LOCKRW_INITIALISER_STAT       mhd_MUTEX_INITIALISER_STAT
    181 #    endif
    182 #  endif
    183 
    184 #  ifdef mhd_LOCKRW_INITIALISER_STAT
    185 /**
    186  *  Define static rw-lock and statically initialise it.
    187  */
    188 #    define mhd_LOCKRW_STATIC_DEFN_INIT(l) \
    189             static mhd_lockrw l = mhd_LOCKRW_INITIALISER_STAT
    190 #  endif
    191 
    192 /**
    193  * Destroy previously initialised rw-lock.
    194  * @param plock the pointer to the rw-lock
    195  * @return nonzero on success, zero otherwise
    196  */
    197 #  if defined(mhd_LOCKRW_KIND_PTHREAD)
    198 #    define mhd_lockrw_destroy(plock) (0 == pthread_rwlock_destroy((plock)))
    199 #  elif defined(mhd_LOCKRW_KIND_W32_SRW)
    200 #    define mhd_lockrw_destroy(plock) ((void) (plock), ! 0)
    201 #  elif defined(mhd_LOCKRW_KIND_MUTEX)
    202 #    define mhd_lockrw_destroy(plock) mhd_mutex_destroy((plock))
    203 #  else
    204 #    error RW-locks implementation is missing
    205 #  endif
    206 
    207 
    208 /**
    209  * Acquire a read lock on previously initialised rw-lock.
    210  * If the write-lock was already locked by other thread, function blocks until
    211  * the rw-lock becomes available.
    212  * Behaviour is undefined if write or read lock has been already locked by
    213  * the same thread.
    214  * @param plock the pointer to the rw-lock
    215  * @return nonzero on success, zero otherwise
    216  */
    217 #  if defined(mhd_LOCKRW_KIND_PTHREAD)
    218 #    define mhd_lockrw_r_lock(plock) (0 == pthread_rwlock_rdlock((plock)))
    219 #  elif defined(mhd_LOCKRW_KIND_W32_SRW)
    220 #    define mhd_lockrw_r_lock(plock) (AcquireSRWLockShared((plock)), ! 0)
    221 #  elif defined(mhd_LOCKRW_KIND_MUTEX)
    222 #    define mhd_lockrw_r_lock(plock) mhd_mutex_lock((plock))
    223 #  else
    224 #    error RW-locks implementation is missing
    225 #  endif
    226 
    227 
    228 /**
    229  * Unlock previously read-locked rw-lock.
    230  * Behaviour is undefined if rw-lock has not been read-locked.
    231  * @param plock the pointer to the rw-lock
    232  * @return nonzero on success, zero otherwise
    233  */
    234 #  if defined(mhd_LOCKRW_KIND_PTHREAD)
    235 #    define mhd_lockrw_r_unlock(plock) (0 == pthread_rwlock_unlock((plock)))
    236 #  elif defined(mhd_LOCKRW_KIND_W32_SRW)
    237 #    define mhd_lockrw_r_unlock(plock) (ReleaseSRWLockShared((plock)), ! 0)
    238 #  elif defined(mhd_LOCKRW_KIND_MUTEX)
    239 #    define mhd_lockrw_r_unlock(plock) mhd_mutex_unlock((plock))
    240 #  else
    241 #    error RW-locks implementation is missing
    242 #  endif
    243 
    244 
    245 /**
    246  * Acquire a write lock on previously initialised rw-lock.
    247  * If the rw-lock was already locked by other thread, function blocks until
    248  * the rw-lock becomes available.
    249  * Behaviour is undefined if write or read lock has been already locked by
    250  * the same thread.
    251  * @param plock the pointer to the rw-lock
    252  * @return nonzero on success, zero otherwise
    253  */
    254 #  if defined(mhd_LOCKRW_KIND_PTHREAD)
    255 #    define mhd_lockrw_w_lock(plock) (0 == pthread_rwlock_wrlock((plock)))
    256 #  elif defined(mhd_LOCKRW_KIND_W32_SRW)
    257 #    define mhd_lockrw_w_lock(plock) (AcquireSRWLockExclusive((plock)), ! 0)
    258 #  elif defined(mhd_LOCKRW_KIND_MUTEX)
    259 #    define mhd_lockrw_w_lock(plock) mhd_mutex_lock((plock))
    260 #  else
    261 #    error RW-locks implementation is missing
    262 #  endif
    263 
    264 
    265 /**
    266  * Unlock previously write-locked rw-lock.
    267  * Behaviour is undefined if rw-lock has not been write-locked.
    268  * @param plock the pointer to the rw-lock
    269  * @return nonzero on success, zero otherwise
    270  */
    271 #  if defined(mhd_LOCKRW_KIND_PTHREAD)
    272 #    define mhd_lockrw_w_unlock(plock) (0 == pthread_rwlock_unlock((plock)))
    273 #  elif defined(mhd_LOCKRW_KIND_W32_SRW)
    274 #    define mhd_lockrw_w_unlock(plock) (ReleaseSRWLockExclusive((plock)), ! 0)
    275 #  elif defined(mhd_LOCKRW_KIND_MUTEX)
    276 #    define mhd_lockrw_w_unlock(plock) mhd_mutex_unlock((plock))
    277 #  else
    278 #    error RW-locks implementation is missing
    279 #  endif
    280 
    281 /**
    282  * Destroy previously initialised rw-lock and abort execution if error is
    283  * detected.
    284  * @param plock the pointer to the rw-lock
    285  */
    286 #  define mhd_lockrw_destroy_chk(plock) do {          \
    287             if (! mhd_lockrw_destroy((plock)))         \
    288               MHD_PANIC ("Failed to destroy rw-lock."); \
    289           } while (0)
    290 
    291 /**
    292  * Acquire a read lock on previously initialised rw-lock.
    293  * If the write-lock was already locked by other thread, function blocks until
    294  * the rw-lock becomes available.
    295  * If error is detected, execution is aborted.
    296  * Behaviour is undefined if write or read lock has been already locked by
    297  * the same thread.
    298  * @param plock the pointer to the rw-lock
    299  */
    300 #  define mhd_lockrw_r_lock_chk(plock) do {             \
    301             if (! mhd_lockrw_r_lock((plock)))            \
    302               MHD_PANIC ("Failed to read-lock rw-lock."); \
    303           } while (0)
    304 
    305 /**
    306  * Unlock previously read-locked rw-lock.
    307  * If error is detected, execution is aborted.
    308  * Behaviour is undefined if rw-lock has not been read-locked.
    309  * @param plock the pointer to the rw-lock
    310  */
    311 #  define mhd_lockrw_r_unlock_chk(plock) do {             \
    312             if (! mhd_lockrw_r_unlock((plock)))            \
    313               MHD_PANIC ("Failed to read-unlock rw-lock."); \
    314           } while (0)
    315 
    316 /**
    317  * Acquire a write lock on previously initialised rw-lock.
    318  * If the rw-lock was already locked by other thread, function blocks until
    319  * the rw-lock becomes available.
    320  * If error is detected, execution is aborted.
    321  * Behaviour is undefined if write or read lock has been already locked by
    322  * the same thread.
    323  * @param plock the pointer to the rw-lock
    324  */
    325 #  define mhd_lockrw_w_lock_chk(plock) do {              \
    326             if (! mhd_lockrw_w_lock((plock)))             \
    327               MHD_PANIC ("Failed to write-lock rw-lock."); \
    328           } while (0)
    329 
    330 /**
    331  * Unlock previously write-locked rw-lock.
    332  * If error is detected, execution is aborted.
    333  * Behaviour is undefined if rw-lock has not been write-locked.
    334  * @param plock the pointer to the rw-lock
    335  */
    336 #  define mhd_lockrw_w_unlock_chk(plock) do {              \
    337             if (! mhd_lockrw_w_unlock((plock)))             \
    338               MHD_PANIC ("Failed to write-unlock rw-lock."); \
    339           } while (0)
    340 
    341 #else  /* ! MHD_SUPPORT_THREADS */
    342 
    343 #  define mhd_lockrw_init(ignored) (! 0)
    344 #  define mhd_LOCKRW_INITIALISER_STAT /* empty */
    345 #  define mhd_LOCKRW_STATIC_DEFN_INIT(ignored) /* nothing */
    346 #  define mhd_lockrw_destroy(ignored) (! 0)
    347 #  define mhd_lockrw_destroy_chk(ignored) ((void) 0)
    348 #  define mhd_lockrw_r_lock(ignored) (! 0)
    349 #  define mhd_lockrw_r_lock_chk(ignored) ((void) 0)
    350 #  define mhd_lockrw_r_unlock(ignored) (! 0)
    351 #  define mhd_lockrw_r_unlock_chk(ignored) ((void) 0)
    352 #  define mhd_lockrw_w_lock(ignored) (! 0)
    353 #  define mhd_lockrw_w_lock_chk(ignored) ((void) 0)
    354 #  define mhd_lockrw_w_unlock(ignored) (! 0)
    355 #  define mhd_lockrw_w_unlock_chk(ignored) ((void) 0)
    356 
    357 #endif /* ! MHD_SUPPORT_THREADS */
    358 
    359 #endif /* ! MHD_LOCKSRW_H */