1 /* 2 * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 3. The name of the author may not be used to endorse or promote products 13 * derived from this software without specific prior written permission. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 #ifndef EVTHREAD_INTERNAL_H_INCLUDED_ 27 #define EVTHREAD_INTERNAL_H_INCLUDED_ 28 29 #ifdef __cplusplus 30 extern "C" { 31 #endif 32 33 #include "event2/event-config.h" 34 #include "evconfig-private.h" 35 36 #include "event2/thread.h" 37 #include "util-internal.h" 38 39 struct event_base; 40 41 #ifndef _WIN32 42 /* On Windows, the way we currently make DLLs, it's not allowed for us to 43 * have shared global structures. Thus, we only do the direct-call-to-function 44 * code path if we know that the local shared library system supports it. 45 */ 46 #define EVTHREAD_EXPOSE_STRUCTS 47 #endif 48 49 #if ! defined(EVENT__DISABLE_THREAD_SUPPORT) && defined(EVTHREAD_EXPOSE_STRUCTS) 50 /* Global function pointers to lock-related functions. NULL if locking isn't 51 enabled. */ 52 extern struct evthread_lock_callbacks evthread_lock_fns_; 53 extern struct evthread_condition_callbacks evthread_cond_fns_; 54 extern unsigned long (*evthread_id_fn_)(void); 55 extern int evthread_lock_debugging_enabled_; 56 57 /** Return the ID of the current thread, or 1 if threading isn't enabled. */ 58 #define EVTHREAD_GET_ID() \ 59 (evthread_id_fn_ ? evthread_id_fn_() : 1) 60 61 /** Return true iff we're in the thread that is currently (or most recently) 62 * running a given event_base's loop. Requires lock. */ 63 #define EVBASE_IN_THREAD(base) \ 64 (evthread_id_fn_ == NULL || \ 65 (base)->th_owner_id == evthread_id_fn_()) 66 67 /** Return true iff we need to notify the base's main thread about changes to 68 * its state, because it's currently running the main loop in another 69 * thread. Requires lock. */ 70 #define EVBASE_NEED_NOTIFY(base) \ 71 (evthread_id_fn_ != NULL && \ 72 (base)->running_loop && \ 73 (base)->th_owner_id != evthread_id_fn_()) 74 75 /** Allocate a new lock, and store it in lockvar, a void*. Sets lockvar to 76 NULL if locking is not enabled. */ 77 #define EVTHREAD_ALLOC_LOCK(lockvar, locktype) \ 78 ((lockvar) = evthread_lock_fns_.alloc ? \ 79 evthread_lock_fns_.alloc(locktype) : NULL) 80 81 /** Free a given lock, if it is present and locking is enabled. */ 82 #define EVTHREAD_FREE_LOCK(lockvar, locktype) \ 83 do { \ 84 void *lock_tmp_ = (lockvar); \ 85 if (lock_tmp_ && evthread_lock_fns_.free) \ 86 evthread_lock_fns_.free(lock_tmp_, (locktype)); \ 87 } while (0) 88 89 /** Acquire a lock. */ 90 #define EVLOCK_LOCK(lockvar,mode) \ 91 do { \ 92 if (lockvar) \ 93 evthread_lock_fns_.lock(mode, lockvar); \ 94 } while (0) 95 96 /** Release a lock */ 97 #define EVLOCK_UNLOCK(lockvar,mode) \ 98 do { \ 99 if (lockvar) \ 100 evthread_lock_fns_.unlock(mode, lockvar); \ 101 } while (0) 102 103 /** Helper: put lockvar1 and lockvar2 into pointerwise ascending order. */ 104 #define EVLOCK_SORTLOCKS_(lockvar1, lockvar2) \ 105 do { \ 106 if (lockvar1 && lockvar2 && lockvar1 > lockvar2) { \ 107 void *tmp = lockvar1; \ 108 lockvar1 = lockvar2; \ 109 lockvar2 = tmp; \ 110 } \ 111 } while (0) 112 113 /** Lock an event_base, if it is set up for locking. Acquires the lock 114 in the base structure whose field is named 'lockvar'. */ 115 #define EVBASE_ACQUIRE_LOCK(base, lockvar) do { \ 116 EVLOCK_LOCK((base)->lockvar, 0); \ 117 } while (0) 118 119 /** Unlock an event_base, if it is set up for locking. */ 120 #define EVBASE_RELEASE_LOCK(base, lockvar) do { \ 121 EVLOCK_UNLOCK((base)->lockvar, 0); \ 122 } while (0) 123 124 /** If lock debugging is enabled, and lock is non-null, assert that 'lock' is 125 * locked and held by us. */ 126 #define EVLOCK_ASSERT_LOCKED(lock) \ 127 do { \ 128 if ((lock) && evthread_lock_debugging_enabled_) { \ 129 EVUTIL_ASSERT(evthread_is_debug_lock_held_(lock)); \ 130 } \ 131 } while (0) 132 133 /** Try to grab the lock for 'lockvar' without blocking, and return 1 if we 134 * manage to get it. */ 135 static inline int EVLOCK_TRY_LOCK_(void *lock); 136 static inline int 137 EVLOCK_TRY_LOCK_(void *lock) 138 { 139 if (lock && evthread_lock_fns_.lock) { 140 int r = evthread_lock_fns_.lock(EVTHREAD_TRY, lock); 141 return !r; 142 } else { 143 /* Locking is disabled either globally or for this thing; 144 * of course we count as having the lock. */ 145 return 1; 146 } 147 } 148 149 /** Allocate a new condition variable and store it in the void *, condvar */ 150 #define EVTHREAD_ALLOC_COND(condvar) \ 151 do { \ 152 (condvar) = evthread_cond_fns_.alloc_condition ? \ 153 evthread_cond_fns_.alloc_condition(0) : NULL; \ 154 } while (0) 155 /** Deallocate and free a condition variable in condvar */ 156 #define EVTHREAD_FREE_COND(cond) \ 157 do { \ 158 if (cond) \ 159 evthread_cond_fns_.free_condition((cond)); \ 160 } while (0) 161 /** Signal one thread waiting on cond */ 162 #define EVTHREAD_COND_SIGNAL(cond) \ 163 ( (cond) ? evthread_cond_fns_.signal_condition((cond), 0) : 0 ) 164 /** Signal all threads waiting on cond */ 165 #define EVTHREAD_COND_BROADCAST(cond) \ 166 ( (cond) ? evthread_cond_fns_.signal_condition((cond), 1) : 0 ) 167 /** Wait until the condition 'cond' is signalled. Must be called while 168 * holding 'lock'. The lock will be released until the condition is 169 * signalled, at which point it will be acquired again. Returns 0 for 170 * success, -1 for failure. */ 171 #define EVTHREAD_COND_WAIT(cond, lock) \ 172 ( (cond) ? evthread_cond_fns_.wait_condition((cond), (lock), NULL) : 0 ) 173 /** As EVTHREAD_COND_WAIT, but gives up after 'tv' has elapsed. Returns 1 174 * on timeout. */ 175 #define EVTHREAD_COND_WAIT_TIMED(cond, lock, tv) \ 176 ( (cond) ? evthread_cond_fns_.wait_condition((cond), (lock), (tv)) : 0 ) 177 178 /** True iff locking functions have been configured. */ 179 #define EVTHREAD_LOCKING_ENABLED() \ 180 (evthread_lock_fns_.lock != NULL) 181 182 #elif ! defined(EVENT__DISABLE_THREAD_SUPPORT) 183 184 unsigned long evthreadimpl_get_id_(void); 185 int evthreadimpl_is_lock_debugging_enabled_(void); 186 void *evthreadimpl_lock_alloc_(unsigned locktype); 187 void evthreadimpl_lock_free_(void *lock, unsigned locktype); 188 int evthreadimpl_lock_lock_(unsigned mode, void *lock); 189 int evthreadimpl_lock_unlock_(unsigned mode, void *lock); 190 void *evthreadimpl_cond_alloc_(unsigned condtype); 191 void evthreadimpl_cond_free_(void *cond); 192 int evthreadimpl_cond_signal_(void *cond, int broadcast); 193 int evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv); 194 int evthreadimpl_locking_enabled_(void); 195 196 #define EVTHREAD_GET_ID() evthreadimpl_get_id_() 197 #define EVBASE_IN_THREAD(base) \ 198 ((base)->th_owner_id == evthreadimpl_get_id_()) 199 #define EVBASE_NEED_NOTIFY(base) \ 200 ((base)->running_loop && \ 201 ((base)->th_owner_id != evthreadimpl_get_id_())) 202 203 #define EVTHREAD_ALLOC_LOCK(lockvar, locktype) \ 204 ((lockvar) = evthreadimpl_lock_alloc_(locktype)) 205 206 #define EVTHREAD_FREE_LOCK(lockvar, locktype) \ 207 do { \ 208 void *lock_tmp_ = (lockvar); \ 209 if (lock_tmp_) \ 210 evthreadimpl_lock_free_(lock_tmp_, (locktype)); \ 211 } while (0) 212 213 /** Acquire a lock. */ 214 #define EVLOCK_LOCK(lockvar,mode) \ 215 do { \ 216 if (lockvar) \ 217 evthreadimpl_lock_lock_(mode, lockvar); \ 218 } while (0) 219 220 /** Release a lock */ 221 #define EVLOCK_UNLOCK(lockvar,mode) \ 222 do { \ 223 if (lockvar) \ 224 evthreadimpl_lock_unlock_(mode, lockvar); \ 225 } while (0) 226 227 /** Lock an event_base, if it is set up for locking. Acquires the lock 228 in the base structure whose field is named 'lockvar'. */ 229 #define EVBASE_ACQUIRE_LOCK(base, lockvar) do { \ 230 EVLOCK_LOCK((base)->lockvar, 0); \ 231 } while (0) 232 233 /** Unlock an event_base, if it is set up for locking. */ 234 #define EVBASE_RELEASE_LOCK(base, lockvar) do { \ 235 EVLOCK_UNLOCK((base)->lockvar, 0); \ 236 } while (0) 237 238 /** If lock debugging is enabled, and lock is non-null, assert that 'lock' is 239 * locked and held by us. */ 240 #define EVLOCK_ASSERT_LOCKED(lock) \ 241 do { \ 242 if ((lock) && evthreadimpl_is_lock_debugging_enabled_()) { \ 243 EVUTIL_ASSERT(evthread_is_debug_lock_held_(lock)); \ 244 } \ 245 } while (0) 246 247 /** Try to grab the lock for 'lockvar' without blocking, and return 1 if we 248 * manage to get it. */ 249 static inline int EVLOCK_TRY_LOCK_(void *lock); 250 static inline int 251 EVLOCK_TRY_LOCK_(void *lock) 252 { 253 if (lock) { 254 int r = evthreadimpl_lock_lock_(EVTHREAD_TRY, lock); 255 return !r; 256 } else { 257 /* Locking is disabled either globally or for this thing; 258 * of course we count as having the lock. */ 259 return 1; 260 } 261 } 262 263 /** Allocate a new condition variable and store it in the void *, condvar */ 264 #define EVTHREAD_ALLOC_COND(condvar) \ 265 do { \ 266 (condvar) = evthreadimpl_cond_alloc_(0); \ 267 } while (0) 268 /** Deallocate and free a condition variable in condvar */ 269 #define EVTHREAD_FREE_COND(cond) \ 270 do { \ 271 if (cond) \ 272 evthreadimpl_cond_free_((cond)); \ 273 } while (0) 274 /** Signal one thread waiting on cond */ 275 #define EVTHREAD_COND_SIGNAL(cond) \ 276 ( (cond) ? evthreadimpl_cond_signal_((cond), 0) : 0 ) 277 /** Signal all threads waiting on cond */ 278 #define EVTHREAD_COND_BROADCAST(cond) \ 279 ( (cond) ? evthreadimpl_cond_signal_((cond), 1) : 0 ) 280 /** Wait until the condition 'cond' is signalled. Must be called while 281 * holding 'lock'. The lock will be released until the condition is 282 * signalled, at which point it will be acquired again. Returns 0 for 283 * success, -1 for failure. */ 284 #define EVTHREAD_COND_WAIT(cond, lock) \ 285 ( (cond) ? evthreadimpl_cond_wait_((cond), (lock), NULL) : 0 ) 286 /** As EVTHREAD_COND_WAIT, but gives up after 'tv' has elapsed. Returns 1 287 * on timeout. */ 288 #define EVTHREAD_COND_WAIT_TIMED(cond, lock, tv) \ 289 ( (cond) ? evthreadimpl_cond_wait_((cond), (lock), (tv)) : 0 ) 290 291 #define EVTHREAD_LOCKING_ENABLED() \ 292 (evthreadimpl_locking_enabled_()) 293 294 #else /* EVENT__DISABLE_THREAD_SUPPORT */ 295 296 #define EVTHREAD_GET_ID() 1 297 #define EVTHREAD_ALLOC_LOCK(lockvar, locktype) EVUTIL_NIL_STMT_ 298 #define EVTHREAD_FREE_LOCK(lockvar, locktype) EVUTIL_NIL_STMT_ 299 300 #define EVLOCK_LOCK(lockvar, mode) EVUTIL_NIL_STMT_ 301 #define EVLOCK_UNLOCK(lockvar, mode) EVUTIL_NIL_STMT_ 302 #define EVLOCK_LOCK2(lock1,lock2,mode1,mode2) EVUTIL_NIL_STMT_ 303 #define EVLOCK_UNLOCK2(lock1,lock2,mode1,mode2) EVUTIL_NIL_STMT_ 304 305 #define EVBASE_IN_THREAD(base) 1 306 #define EVBASE_NEED_NOTIFY(base) 0 307 #define EVBASE_ACQUIRE_LOCK(base, lock) EVUTIL_NIL_STMT_ 308 #define EVBASE_RELEASE_LOCK(base, lock) EVUTIL_NIL_STMT_ 309 #define EVLOCK_ASSERT_LOCKED(lock) EVUTIL_NIL_STMT_ 310 311 #define EVLOCK_TRY_LOCK_(lock) 1 312 313 #define EVTHREAD_ALLOC_COND(condvar) EVUTIL_NIL_STMT_ 314 #define EVTHREAD_FREE_COND(cond) EVUTIL_NIL_STMT_ 315 #define EVTHREAD_COND_SIGNAL(cond) EVUTIL_NIL_STMT_ 316 #define EVTHREAD_COND_BROADCAST(cond) EVUTIL_NIL_STMT_ 317 #define EVTHREAD_COND_WAIT(cond, lock) EVUTIL_NIL_STMT_ 318 #define EVTHREAD_COND_WAIT_TIMED(cond, lock, howlong) EVUTIL_NIL_STMT_ 319 320 #define EVTHREAD_LOCKING_ENABLED() 0 321 322 #endif 323 324 /* This code is shared between both lock impls */ 325 #if ! defined(EVENT__DISABLE_THREAD_SUPPORT) 326 /** Helper: put lockvar1 and lockvar2 into pointerwise ascending order. */ 327 #define EVLOCK_SORTLOCKS_(lockvar1, lockvar2) \ 328 do { \ 329 if (lockvar1 && lockvar2 && lockvar1 > lockvar2) { \ 330 void *tmp = lockvar1; \ 331 lockvar1 = lockvar2; \ 332 lockvar2 = tmp; \ 333 } \ 334 } while (0) 335 336 /** Acquire both lock1 and lock2. Always allocates locks in the same order, 337 * so that two threads locking two locks with LOCK2 will not deadlock. */ 338 #define EVLOCK_LOCK2(lock1,lock2,mode1,mode2) \ 339 do { \ 340 void *lock1_tmplock_ = (lock1); \ 341 void *lock2_tmplock_ = (lock2); \ 342 EVLOCK_SORTLOCKS_(lock1_tmplock_,lock2_tmplock_); \ 343 EVLOCK_LOCK(lock1_tmplock_,mode1); \ 344 if (lock2_tmplock_ != lock1_tmplock_) \ 345 EVLOCK_LOCK(lock2_tmplock_,mode2); \ 346 } while (0) 347 /** Release both lock1 and lock2. */ 348 #define EVLOCK_UNLOCK2(lock1,lock2,mode1,mode2) \ 349 do { \ 350 void *lock1_tmplock_ = (lock1); \ 351 void *lock2_tmplock_ = (lock2); \ 352 EVLOCK_SORTLOCKS_(lock1_tmplock_,lock2_tmplock_); \ 353 if (lock2_tmplock_ != lock1_tmplock_) \ 354 EVLOCK_UNLOCK(lock2_tmplock_,mode2); \ 355 EVLOCK_UNLOCK(lock1_tmplock_,mode1); \ 356 } while (0) 357 358 int evthread_is_debug_lock_held_(void *lock); 359 void *evthread_debug_get_real_lock_(void *lock); 360 361 void *evthread_setup_global_lock_(void *lock_, unsigned locktype, 362 int enable_locks); 363 364 #define EVTHREAD_SETUP_GLOBAL_LOCK(lockvar, locktype) \ 365 do { \ 366 lockvar = evthread_setup_global_lock_(lockvar, \ 367 (locktype), enable_locks); \ 368 if (!lockvar) { \ 369 event_warn("Couldn't allocate %s", #lockvar); \ 370 return -1; \ 371 } \ 372 } while (0); 373 374 int event_global_setup_locks_(const int enable_locks); 375 int evsig_global_setup_locks_(const int enable_locks); 376 int evutil_global_setup_locks_(const int enable_locks); 377 int evutil_secure_rng_global_setup_locks_(const int enable_locks); 378 379 /** Return current evthread_lock_callbacks */ 380 struct evthread_lock_callbacks *evthread_get_lock_callbacks(void); 381 /** Return current evthread_condition_callbacks */ 382 struct evthread_condition_callbacks *evthread_get_condition_callbacks(void); 383 /** Disable locking for internal usage (like global shutdown) */ 384 void evthreadimpl_disable_lock_debugging_(void); 385 386 #endif 387 388 #ifdef __cplusplus 389 } 390 #endif 391 392 #endif /* EVTHREAD_INTERNAL_H_INCLUDED_ */ 393