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 27#include "event2/event-config.h" 28#include "evconfig-private.h" 29 30#ifndef EVENT__DISABLE_THREAD_SUPPORT 31 32#include "event2/thread.h" 33 34#include <stdlib.h> 35#include <string.h> 36 37#include "log-internal.h" 38#include "mm-internal.h" 39#include "util-internal.h" 40#include "evthread-internal.h" 41 42#ifdef EVTHREAD_EXPOSE_STRUCTS 43#define GLOBAL 44#else 45#define GLOBAL static 46#endif 47 48#ifndef EVENT__DISABLE_DEBUG_MODE 49extern int event_debug_created_threadable_ctx_; 50extern int event_debug_mode_on_; 51#endif 52 53/* globals */ 54GLOBAL int evthread_lock_debugging_enabled_ = 0; 55GLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = { 56 0, 0, NULL, NULL, NULL, NULL 57}; 58GLOBAL unsigned long (*evthread_id_fn_)(void) = NULL; 59GLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = { 60 0, NULL, NULL, NULL, NULL 61}; 62 63/* Used for debugging */ 64static struct evthread_lock_callbacks original_lock_fns_ = { 65 0, 0, NULL, NULL, NULL, NULL 66}; 67static struct evthread_condition_callbacks original_cond_fns_ = { 68 0, NULL, NULL, NULL, NULL 69}; 70 71void 72evthread_set_id_callback(unsigned long (*id_fn)(void)) 73{ 74 evthread_id_fn_ = id_fn; 75} 76 77struct evthread_lock_callbacks *evthread_get_lock_callbacks() 78{ 79 return evthread_lock_debugging_enabled_ 80 ? &original_lock_fns_ : &evthread_lock_fns_; 81} 82struct evthread_condition_callbacks *evthread_get_condition_callbacks() 83{ 84 return evthread_lock_debugging_enabled_ 85 ? &original_cond_fns_ : &evthread_cond_fns_; 86} 87void evthreadimpl_disable_lock_debugging_(void) 88{ 89 evthread_lock_debugging_enabled_ = 0; 90} 91 92int 93evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs) 94{ 95 struct evthread_lock_callbacks *target = evthread_get_lock_callbacks(); 96 97#ifndef EVENT__DISABLE_DEBUG_MODE 98 if (event_debug_mode_on_) { 99 if (event_debug_created_threadable_ctx_) { 100 event_errx(1, "evthread initialization must be called BEFORE anything else!"); 101 } 102 } 103#endif 104 105 if (!cbs) { 106 if (target->alloc) 107 event_warnx("Trying to disable lock functions after " 108 "they have been set up will probaby not work."); 109 memset(target, 0, sizeof(evthread_lock_fns_)); 110 return 0; 111 } 112 if (target->alloc) { 113 /* Uh oh; we already had locking callbacks set up.*/ 114 if (target->lock_api_version == cbs->lock_api_version && 115 target->supported_locktypes == cbs->supported_locktypes && 116 target->alloc == cbs->alloc && 117 target->free == cbs->free && 118 target->lock == cbs->lock && 119 target->unlock == cbs->unlock) { 120 /* no change -- allow this. */ 121 return 0; 122 } 123 event_warnx("Can't change lock callbacks once they have been " 124 "initialized."); 125 return -1; 126 } 127 if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) { 128 memcpy(target, cbs, sizeof(evthread_lock_fns_)); 129 return event_global_setup_locks_(1); 130 } else { 131 return -1; 132 } 133} 134 135int 136evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs) 137{ 138 struct evthread_condition_callbacks *target = evthread_get_condition_callbacks(); 139 140#ifndef EVENT__DISABLE_DEBUG_MODE 141 if (event_debug_mode_on_) { 142 if (event_debug_created_threadable_ctx_) { 143 event_errx(1, "evthread initialization must be called BEFORE anything else!"); 144 } 145 } 146#endif 147 148 if (!cbs) { 149 if (target->alloc_condition) 150 event_warnx("Trying to disable condition functions " 151 "after they have been set up will probaby not " 152 "work."); 153 memset(target, 0, sizeof(evthread_cond_fns_)); 154 return 0; 155 } 156 if (target->alloc_condition) { 157 /* Uh oh; we already had condition callbacks set up.*/ 158 if (target->condition_api_version == cbs->condition_api_version && 159 target->alloc_condition == cbs->alloc_condition && 160 target->free_condition == cbs->free_condition && 161 target->signal_condition == cbs->signal_condition && 162 target->wait_condition == cbs->wait_condition) { 163 /* no change -- allow this. */ 164 return 0; 165 } 166 event_warnx("Can't change condition callbacks once they " 167 "have been initialized."); 168 return -1; 169 } 170 if (cbs->alloc_condition && cbs->free_condition && 171 cbs->signal_condition && cbs->wait_condition) { 172 memcpy(target, cbs, sizeof(evthread_cond_fns_)); 173 } 174 if (evthread_lock_debugging_enabled_) { 175 evthread_cond_fns_.alloc_condition = cbs->alloc_condition; 176 evthread_cond_fns_.free_condition = cbs->free_condition; 177 evthread_cond_fns_.signal_condition = cbs->signal_condition; 178 } 179 return 0; 180} 181 182#define DEBUG_LOCK_SIG 0xdeb0b10c 183 184struct debug_lock { 185 unsigned signature; 186 unsigned locktype; 187 unsigned long held_by; 188 /* XXXX if we ever use read-write locks, we will need a separate 189 * lock to protect count. */ 190 int count; 191 void *lock; 192}; 193 194static void * 195debug_lock_alloc(unsigned locktype) 196{ 197 struct debug_lock *result = mm_malloc(sizeof(struct debug_lock)); 198 if (!result) 199 return NULL; 200 if (original_lock_fns_.alloc) { 201 if (!(result->lock = original_lock_fns_.alloc( 202 locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) { 203 mm_free(result); 204 return NULL; 205 } 206 } else { 207 result->lock = NULL; 208 } 209 result->signature = DEBUG_LOCK_SIG; 210 result->locktype = locktype; 211 result->count = 0; 212 result->held_by = 0; 213 return result; 214} 215 216static void 217debug_lock_free(void *lock_, unsigned locktype) 218{ 219 struct debug_lock *lock = lock_; 220 EVUTIL_ASSERT(lock->count == 0); 221 EVUTIL_ASSERT(locktype == lock->locktype); 222 EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 223 if (original_lock_fns_.free) { 224 original_lock_fns_.free(lock->lock, 225 lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE); 226 } 227 lock->lock = NULL; 228 lock->count = -100; 229 lock->signature = 0x12300fda; 230 mm_free(lock); 231} 232 233static void 234evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock) 235{ 236 EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 237 ++lock->count; 238 if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) 239 EVUTIL_ASSERT(lock->count == 1); 240 if (evthread_id_fn_) { 241 unsigned long me; 242 me = evthread_id_fn_(); 243 if (lock->count > 1) 244 EVUTIL_ASSERT(lock->held_by == me); 245 lock->held_by = me; 246 } 247} 248 249static int 250debug_lock_lock(unsigned mode, void *lock_) 251{ 252 struct debug_lock *lock = lock_; 253 int res = 0; 254 if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) 255 EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); 256 else 257 EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); 258 if (original_lock_fns_.lock) 259 res = original_lock_fns_.lock(mode, lock->lock); 260 if (!res) { 261 evthread_debug_lock_mark_locked(mode, lock); 262 } 263 return res; 264} 265 266static void 267evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock) 268{ 269 EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 270 if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) 271 EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); 272 else 273 EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); 274 if (evthread_id_fn_) { 275 unsigned long me; 276 me = evthread_id_fn_(); 277 EVUTIL_ASSERT(lock->held_by == me); 278 if (lock->count == 1) 279 lock->held_by = 0; 280 } 281 --lock->count; 282 EVUTIL_ASSERT(lock->count >= 0); 283} 284 285static int 286debug_lock_unlock(unsigned mode, void *lock_) 287{ 288 struct debug_lock *lock = lock_; 289 int res = 0; 290 evthread_debug_lock_mark_unlocked(mode, lock); 291 if (original_lock_fns_.unlock) 292 res = original_lock_fns_.unlock(mode, lock->lock); 293 return res; 294} 295 296static int 297debug_cond_wait(void *cond_, void *lock_, const struct timeval *tv) 298{ 299 int r; 300 struct debug_lock *lock = lock_; 301 EVUTIL_ASSERT(lock); 302 EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 303 EVLOCK_ASSERT_LOCKED(lock_); 304 evthread_debug_lock_mark_unlocked(0, lock); 305 r = original_cond_fns_.wait_condition(cond_, lock->lock, tv); 306 evthread_debug_lock_mark_locked(0, lock); 307 return r; 308} 309 310/* misspelled version for backward compatibility */ 311void 312evthread_enable_lock_debuging(void) 313{ 314 evthread_enable_lock_debugging(); 315} 316 317void 318evthread_enable_lock_debugging(void) 319{ 320 struct evthread_lock_callbacks cbs = { 321 EVTHREAD_LOCK_API_VERSION, 322 EVTHREAD_LOCKTYPE_RECURSIVE, 323 debug_lock_alloc, 324 debug_lock_free, 325 debug_lock_lock, 326 debug_lock_unlock 327 }; 328 if (evthread_lock_debugging_enabled_) 329 return; 330 memcpy(&original_lock_fns_, &evthread_lock_fns_, 331 sizeof(struct evthread_lock_callbacks)); 332 memcpy(&evthread_lock_fns_, &cbs, 333 sizeof(struct evthread_lock_callbacks)); 334 335 memcpy(&original_cond_fns_, &evthread_cond_fns_, 336 sizeof(struct evthread_condition_callbacks)); 337 evthread_cond_fns_.wait_condition = debug_cond_wait; 338 evthread_lock_debugging_enabled_ = 1; 339 340 /* XXX return value should get checked. */ 341 event_global_setup_locks_(0); 342} 343 344int 345evthread_is_debug_lock_held_(void *lock_) 346{ 347 struct debug_lock *lock = lock_; 348 if (! lock->count) 349 return 0; 350 if (evthread_id_fn_) { 351 unsigned long me = evthread_id_fn_(); 352 if (lock->held_by != me) 353 return 0; 354 } 355 return 1; 356} 357 358void * 359evthread_debug_get_real_lock_(void *lock_) 360{ 361 struct debug_lock *lock = lock_; 362 return lock->lock; 363} 364 365void * 366evthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks) 367{ 368 /* there are four cases here: 369 1) we're turning on debugging; locking is not on. 370 2) we're turning on debugging; locking is on. 371 3) we're turning on locking; debugging is not on. 372 4) we're turning on locking; debugging is on. */ 373 374 if (!enable_locks && original_lock_fns_.alloc == NULL) { 375 /* Case 1: allocate a debug lock. */ 376 EVUTIL_ASSERT(lock_ == NULL); 377 return debug_lock_alloc(locktype); 378 } else if (!enable_locks && original_lock_fns_.alloc != NULL) { 379 /* Case 2: wrap the lock in a debug lock. */ 380 struct debug_lock *lock; 381 EVUTIL_ASSERT(lock_ != NULL); 382 383 if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) { 384 /* We can't wrap it: We need a recursive lock */ 385 original_lock_fns_.free(lock_, locktype); 386 return debug_lock_alloc(locktype); 387 } 388 lock = mm_malloc(sizeof(struct debug_lock)); 389 if (!lock) { 390 original_lock_fns_.free(lock_, locktype); 391 return NULL; 392 } 393 lock->lock = lock_; 394 lock->locktype = locktype; 395 lock->count = 0; 396 lock->held_by = 0; 397 return lock; 398 } else if (enable_locks && ! evthread_lock_debugging_enabled_) { 399 /* Case 3: allocate a regular lock */ 400 EVUTIL_ASSERT(lock_ == NULL); 401 return evthread_lock_fns_.alloc(locktype); 402 } else { 403 /* Case 4: Fill in a debug lock with a real lock */ 404 struct debug_lock *lock = lock_ ? lock_ : debug_lock_alloc(locktype); 405 EVUTIL_ASSERT(enable_locks && 406 evthread_lock_debugging_enabled_); 407 EVUTIL_ASSERT(lock->locktype == locktype); 408 if (!lock->lock) { 409 lock->lock = original_lock_fns_.alloc( 410 locktype|EVTHREAD_LOCKTYPE_RECURSIVE); 411 if (!lock->lock) { 412 lock->count = -200; 413 mm_free(lock); 414 return NULL; 415 } 416 } 417 return lock; 418 } 419} 420 421 422#ifndef EVTHREAD_EXPOSE_STRUCTS 423unsigned long 424evthreadimpl_get_id_() 425{ 426 return evthread_id_fn_ ? evthread_id_fn_() : 1; 427} 428void * 429evthreadimpl_lock_alloc_(unsigned locktype) 430{ 431#ifndef EVENT__DISABLE_DEBUG_MODE 432 if (event_debug_mode_on_) { 433 event_debug_created_threadable_ctx_ = 1; 434 } 435#endif 436 437 return evthread_lock_fns_.alloc ? 438 evthread_lock_fns_.alloc(locktype) : NULL; 439} 440void 441evthreadimpl_lock_free_(void *lock, unsigned locktype) 442{ 443 if (evthread_lock_fns_.free) 444 evthread_lock_fns_.free(lock, locktype); 445} 446int 447evthreadimpl_lock_lock_(unsigned mode, void *lock) 448{ 449 if (evthread_lock_fns_.lock) 450 return evthread_lock_fns_.lock(mode, lock); 451 else 452 return 0; 453} 454int 455evthreadimpl_lock_unlock_(unsigned mode, void *lock) 456{ 457 if (evthread_lock_fns_.unlock) 458 return evthread_lock_fns_.unlock(mode, lock); 459 else 460 return 0; 461} 462void * 463evthreadimpl_cond_alloc_(unsigned condtype) 464{ 465#ifndef EVENT__DISABLE_DEBUG_MODE 466 if (event_debug_mode_on_) { 467 event_debug_created_threadable_ctx_ = 1; 468 } 469#endif 470 471 return evthread_cond_fns_.alloc_condition ? 472 evthread_cond_fns_.alloc_condition(condtype) : NULL; 473} 474void 475evthreadimpl_cond_free_(void *cond) 476{ 477 if (evthread_cond_fns_.free_condition) 478 evthread_cond_fns_.free_condition(cond); 479} 480int 481evthreadimpl_cond_signal_(void *cond, int broadcast) 482{ 483 if (evthread_cond_fns_.signal_condition) 484 return evthread_cond_fns_.signal_condition(cond, broadcast); 485 else 486 return 0; 487} 488int 489evthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv) 490{ 491 if (evthread_cond_fns_.wait_condition) 492 return evthread_cond_fns_.wait_condition(cond, lock, tv); 493 else 494 return 0; 495} 496int 497evthreadimpl_is_lock_debugging_enabled_(void) 498{ 499 return evthread_lock_debugging_enabled_; 500} 501 502int 503evthreadimpl_locking_enabled_(void) 504{ 505 return evthread_lock_fns_.lock != NULL; 506} 507#endif 508 509#endif 510