mhd_locks.h (10856B)
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) 2016-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_locks.h 41 * @brief Header for platform-independent locks abstraction 42 * @author Karlson2k (Evgeny Grin) 43 * @author Christian Grothoff 44 * 45 * Provides basic abstraction for locks/mutex. 46 * Any functions can be implemented as macro on some platforms 47 * unless explicitly marked 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_LOCKS_H 56 #define MHD_LOCKS_H 1 57 58 #include "mhd_sys_options.h" 59 60 #ifdef MHD_SUPPORT_THREADS 61 62 # if defined(HAVE_PTHREAD_H) && defined(mhd_THREADS_KIND_POSIX) 63 /** 64 * The mutex is POSIX Threads' mutex 65 */ 66 # define mhd_MUTEX_KIND_PTHREAD 1 67 # define mhd_MUTEX_IMPLEMENTED 1 68 # include <pthread.h> 69 # include "sys_null_macro.h" 70 # endif 71 72 # if !defined(mhd_MUTEX_IMPLEMENTED) && defined(mhd_THREADS_KIND_W32) 73 # include "sys_w32_ver.h" 74 /* Define MHD_NO_W32_SRWLOCKS_MUTEX to force use critical section on W32 */ 75 # if _WIN32_WINNT >= 0x0600 /* Vista or later */ && \ 76 !defined(MHD_NO_W32_SRWLOCKS_MUTEX) 77 # include "mhd_locksrw.h" 78 # if defined(mhd_LOCKRW_KIND_W32_SRW) && !defined(mhd_LOCKRW_KIND_MUTEX) 79 /** 80 * The mutex is W32 SRW lock 81 */ 82 # define mhd_MUTEX_KIND_W32_SRW 1 83 # define mhd_MUTEX_KIND_LOCKRW 1 84 # define mhd_MUTEX_IMPLEMENTED 1 85 # endif 86 # endif 87 # ifndef mhd_MUTEX_IMPLEMENTED 88 /** 89 * The mutex is W32 Critical Section 90 */ 91 # define mhd_MUTEX_KIND_W32_CS 1 92 # define mhd_MUTEX_IMPLEMENTED 1 93 # if 0 /* _WIN32_WINNT >= 0x0602 */ /* Win8 or later */ 94 /* This include does not work as _ARM_ or _AMD64_ macros 95 are missing */ 96 # include <synchapi.h> 97 # else 98 # include <windows.h> 99 # endif 100 # endif 101 # endif 102 103 # ifndef mhd_MUTEX_IMPLEMENTED 104 # include "mhd_locksrw.h" 105 # if defined(mhd_LOCKRW_IMPLEMENTED) && !defined(mhd_LOCKRW_KIND_MUTEX) 106 /** 107 * The mutex is RW-lock 108 */ 109 # define mhd_MUTEX_KIND_LOCKRW 1 110 # define mhd_MUTEX_IMPLEMENTED 1 111 # endif 112 # endif 113 114 # ifndef mhd_MUTEX_IMPLEMENTED 115 # error No base mutex API is available. 116 # endif 117 118 /* Sanity check */ 119 # ifdef mhd_MUTEX_KIND_PTHREAD 120 # ifndef mhd_MUTEX_HAS_ONE_IMPLEMENTATION 121 # define mhd_MUTEX_HAS_ONE_IMPLEMENTATION 1 122 # else 123 # error Multiple mutex implementations are enabled simultaneously 124 # endif 125 # endif 126 # ifdef mhd_MUTEX_KIND_LOCKRW 127 # ifndef mhd_MUTEX_HAS_ONE_IMPLEMENTATION 128 # define mhd_MUTEX_HAS_ONE_IMPLEMENTATION 1 129 # else 130 # error Multiple mutex implementations are enabled simultaneously 131 # endif 132 # endif 133 # ifdef mhd_MUTEX_KIND_W32_CS 134 # ifndef mhd_MUTEX_HAS_ONE_IMPLEMENTATION 135 # define mhd_MUTEX_HAS_ONE_IMPLEMENTATION 1 136 # else 137 # error Multiple mutex implementations are enabled simultaneously 138 # endif 139 # endif 140 # ifndef mhd_MUTEX_HAS_ONE_IMPLEMENTATION 141 # error Not all mutex kinds were checked 142 # endif 143 # undef mhd_MUTEX_HAS_ONE_IMPLEMENTATION 144 145 # include "mhd_panic.h" 146 147 # if defined(mhd_MUTEX_KIND_PTHREAD) 148 typedef pthread_mutex_t mhd_mutex; 149 # elif defined(mhd_MUTEX_KIND_W32_CS) 150 typedef CRITICAL_SECTION mhd_mutex; 151 # elif defined(mhd_MUTEX_KIND_LOCKRW) 152 typedef mhd_lockrw mhd_mutex; 153 # endif 154 155 /** 156 * Initialise a new mutex. 157 * @param pmutex the pointer to the mutex 158 * @return nonzero on success, zero otherwise 159 */ 160 # if defined(mhd_MUTEX_KIND_PTHREAD) 161 # define mhd_mutex_init(pmutex) (0 == pthread_mutex_init((pmutex), NULL)) 162 # elif defined(mhd_MUTEX_KIND_W32_CS) 163 # if _WIN32_WINNT < 0x0600 164 /* Before Vista */ 165 # define mhd_mutex_init(pmutex) \ 166 (InitializeCriticalSectionAndSpinCount((pmutex), 0)) 167 # else 168 /* The function always succeed starting from Vista */ 169 # define mhd_mutex_init(pmutex) \ 170 (((void) InitializeCriticalSection(pmutex)), ! 0) 171 # endif 172 # elif defined(mhd_MUTEX_KIND_LOCKRW) 173 # define mhd_mutex_init(pmutex) mhd_lockrw_init((pmutex)) 174 # else 175 # error Mutex implementation is missing 176 # endif 177 178 /** 179 * Initialise a new mutex for short locks. 180 * 181 * Initialised mutex is optimised for locks held only for very short period of 182 * time. It should be used when only a single or just a few variables are 183 * modified under the lock. 184 * 185 * @param pmutex the pointer to the mutex 186 * @return nonzero on success, zero otherwise 187 */ 188 # ifdef mhd_MUTEX_KIND_W32_CS 189 # if _WIN32_WINNT < 0x0600 190 /* Before Vista */ 191 # define mhd_mutex_init_short(pmutex) \ 192 (InitializeCriticalSectionAndSpinCount((pmutex), 128)) 193 # else 194 /* The function always succeed starting from Vista */ 195 # define mhd_mutex_init_short(pmutex) \ 196 ((void) InitializeCriticalSectionAndSpinCount((pmutex), 128), ! 0) 197 # endif 198 # endif 199 200 # ifndef mhd_mutex_init_short 201 # define mhd_mutex_init_short(pmutex) mhd_mutex_init ((pmutex)) 202 # endif 203 204 /** 205 * The value to statically initialise mutex 206 */ 207 # if defined(mhd_MUTEX_KIND_PTHREAD) 208 # if !defined(NDEBUG) && defined(PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP) 209 # define mhd_MUTEX_INITIALISER_STAT \ 210 PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP 211 # elif defined(PTHREAD_MUTEX_INITIALIZER) 212 # define mhd_MUTEX_INITIALISER_STAT PTHREAD_MUTEX_INITIALIZER 213 # endif 214 # elif defined(mhd_MUTEX_KIND_LOCKRW) 215 # if defined(mhd_LOCKRW_INITIALISER_STAT) 216 # define mhd_MUTEX_INITIALISER_STAT mhd_LOCKRW_INITIALISER_STAT 217 # endif 218 # endif 219 220 # ifdef mhd_MUTEX_INITIALISER_STAT 221 /** 222 * Define static mutex and statically initialise it. 223 */ 224 # define mhd_MUTEX_STATIC_DEFN_INIT(m) \ 225 static mhd_mutex m = mhd_MUTEX_INITIALISER_STAT 226 # endif 227 228 /** 229 * Destroy previously initialised mutex. 230 * @param pmutex the pointer to the mutex 231 * @return nonzero on success, zero otherwise 232 */ 233 # if defined(mhd_MUTEX_KIND_PTHREAD) 234 # define mhd_mutex_destroy(pmutex) (0 == pthread_mutex_destroy((pmutex))) 235 # elif defined(mhd_MUTEX_KIND_W32_CS) 236 # define mhd_mutex_destroy(pmutex) (DeleteCriticalSection((pmutex)), ! 0) 237 # elif defined(mhd_MUTEX_KIND_LOCKRW) 238 # define mhd_mutex_destroy(pmutex) mhd_lockrw_destroy((pmutex)) 239 # else 240 # error Mutex implementation is missing 241 # endif 242 243 244 /** 245 * Acquire a lock on previously initialised mutex. 246 * If the mutex was already locked by other thread, function blocks until 247 * the mutex becomes available. 248 * @param pmutex the pointer to the mutex 249 * @return nonzero on success, zero otherwise 250 */ 251 # if defined(mhd_MUTEX_KIND_PTHREAD) 252 # define mhd_mutex_lock(pmutex) (0 == pthread_mutex_lock((pmutex))) 253 # elif defined(mhd_MUTEX_KIND_W32_CS) 254 # define mhd_mutex_lock(pmutex) (EnterCriticalSection((pmutex)), ! 0) 255 # elif defined(mhd_MUTEX_KIND_LOCKRW) 256 # define mhd_mutex_lock(pmutex) mhd_lockrw_w_lock((pmutex)) 257 # else 258 # error Mutex implementation is missing 259 # endif 260 261 /** 262 * Unlock previously locked mutex. 263 * @param pmutex the pointer to the mutex 264 * @return nonzero on success, zero otherwise 265 */ 266 # if defined(mhd_MUTEX_KIND_PTHREAD) 267 # define mhd_mutex_unlock(pmutex) (0 == pthread_mutex_unlock((pmutex))) 268 # elif defined(mhd_MUTEX_KIND_W32_CS) 269 # define mhd_mutex_unlock(pmutex) (LeaveCriticalSection((pmutex)), ! 0) 270 # elif defined(mhd_MUTEX_KIND_LOCKRW) 271 # define mhd_mutex_unlock(pmutex) mhd_lockrw_w_unlock((pmutex)) 272 # else 273 # error Mutex implementation is missing 274 # endif 275 276 /** 277 * Destroy previously initialised mutex and abort execution if error is 278 * detected. 279 * @param pmutex the pointer to the mutex 280 */ 281 # define mhd_mutex_destroy_chk(pmutex) do { \ 282 if (! mhd_mutex_destroy((pmutex))) \ 283 MHD_PANIC ("Failed to destroy mutex."); \ 284 } while (0) 285 286 /** 287 * Acquire a lock on previously initialised mutex. 288 * If the mutex was already locked by other thread, function blocks until 289 * the mutex becomes available. 290 * If error is detected, execution is aborted. 291 * @param pmutex the pointer to the mutex 292 */ 293 # define mhd_mutex_lock_chk(pmutex) do { \ 294 if (! mhd_mutex_lock((pmutex))) \ 295 MHD_PANIC ("Failed to lock mutex."); \ 296 } while (0) 297 298 /** 299 * Unlock previously locked mutex. 300 * If error is detected, execution is aborted. 301 * @param pmutex the pointer to the mutex 302 */ 303 # define mhd_mutex_unlock_chk(pmutex) do { \ 304 if (! mhd_mutex_unlock((pmutex))) \ 305 MHD_PANIC ("Failed to unlock mutex."); \ 306 } while (0) 307 308 #else /* ! MHD_SUPPORT_THREADS */ 309 310 # define mhd_mutex_init(ignored) (! 0) 311 # define mhd_mutex_init_short(ignored) (! 0) 312 # define mhd_MUTEX_INITIALISER_STAT /* empty */ 313 # define mhd_MUTEX_STATIC_DEFN_INIT(ignored) /* nothing */ 314 # define mhd_mutex_destroy(ignored) (! 0) 315 # define mhd_mutex_destroy_chk(ignored) ((void) 0) 316 # define mhd_mutex_lock(ignored) (! 0) 317 # define mhd_mutex_lock_chk(ignored) ((void) 0) 318 # define mhd_mutex_unlock(ignored) (! 0) 319 # define mhd_mutex_unlock_chk(ignored) ((void) 0) 320 321 #endif /* ! MHD_SUPPORT_THREADS */ 322 323 #endif /* ! MHD_LOCKS_H */