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 */