1275970Scy/* 2275970Scy * Copyright (c) 2008-2012 Niels Provos, Nick Mathewson 3275970Scy * 4275970Scy * Redistribution and use in source and binary forms, with or without 5275970Scy * modification, are permitted provided that the following conditions 6275970Scy * are met: 7275970Scy * 1. Redistributions of source code must retain the above copyright 8275970Scy * notice, this list of conditions and the following disclaimer. 9275970Scy * 2. Redistributions in binary form must reproduce the above copyright 10275970Scy * notice, this list of conditions and the following disclaimer in the 11275970Scy * documentation and/or other materials provided with the distribution. 12275970Scy * 3. The name of the author may not be used to endorse or promote products 13275970Scy * derived from this software without specific prior written permission. 14275970Scy * 15275970Scy * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16275970Scy * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17275970Scy * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18275970Scy * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19275970Scy * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20275970Scy * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21275970Scy * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22275970Scy * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23275970Scy * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24275970Scy * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25275970Scy */ 26275970Scy 27275970Scy#include "event2/event-config.h" 28275970Scy#include "evconfig-private.h" 29275970Scy 30275970Scy#ifndef EVENT__DISABLE_THREAD_SUPPORT 31275970Scy 32275970Scy#include "event2/thread.h" 33275970Scy 34275970Scy#include <stdlib.h> 35275970Scy#include <string.h> 36275970Scy 37275970Scy#include "log-internal.h" 38275970Scy#include "mm-internal.h" 39275970Scy#include "util-internal.h" 40275970Scy#include "evthread-internal.h" 41275970Scy 42275970Scy#ifdef EVTHREAD_EXPOSE_STRUCTS 43275970Scy#define GLOBAL 44275970Scy#else 45275970Scy#define GLOBAL static 46275970Scy#endif 47275970Scy 48275970Scy/* globals */ 49275970ScyGLOBAL int evthread_lock_debugging_enabled_ = 0; 50275970ScyGLOBAL struct evthread_lock_callbacks evthread_lock_fns_ = { 51275970Scy 0, 0, NULL, NULL, NULL, NULL 52275970Scy}; 53275970ScyGLOBAL unsigned long (*evthread_id_fn_)(void) = NULL; 54275970ScyGLOBAL struct evthread_condition_callbacks evthread_cond_fns_ = { 55275970Scy 0, NULL, NULL, NULL, NULL 56275970Scy}; 57275970Scy 58275970Scy/* Used for debugging */ 59275970Scystatic struct evthread_lock_callbacks original_lock_fns_ = { 60275970Scy 0, 0, NULL, NULL, NULL, NULL 61275970Scy}; 62275970Scystatic struct evthread_condition_callbacks original_cond_fns_ = { 63275970Scy 0, NULL, NULL, NULL, NULL 64275970Scy}; 65275970Scy 66275970Scyvoid 67275970Scyevthread_set_id_callback(unsigned long (*id_fn)(void)) 68275970Scy{ 69275970Scy evthread_id_fn_ = id_fn; 70275970Scy} 71275970Scy 72282408Scystruct evthread_lock_callbacks *evthread_get_lock_callbacks() 73282408Scy{ 74282408Scy return evthread_lock_debugging_enabled_ 75282408Scy ? &original_lock_fns_ : &evthread_lock_fns_; 76282408Scy} 77282408Scystruct evthread_condition_callbacks *evthread_get_condition_callbacks() 78282408Scy{ 79282408Scy return evthread_lock_debugging_enabled_ 80282408Scy ? &original_cond_fns_ : &evthread_cond_fns_; 81282408Scy} 82282408Scyvoid evthreadimpl_disable_lock_debugging_(void) 83282408Scy{ 84282408Scy evthread_lock_debugging_enabled_ = 0; 85282408Scy} 86282408Scy 87275970Scyint 88275970Scyevthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs) 89275970Scy{ 90282408Scy struct evthread_lock_callbacks *target = evthread_get_lock_callbacks(); 91275970Scy 92275970Scy if (!cbs) { 93275970Scy if (target->alloc) 94275970Scy event_warnx("Trying to disable lock functions after " 95275970Scy "they have been set up will probaby not work."); 96275970Scy memset(target, 0, sizeof(evthread_lock_fns_)); 97275970Scy return 0; 98275970Scy } 99275970Scy if (target->alloc) { 100275970Scy /* Uh oh; we already had locking callbacks set up.*/ 101275970Scy if (target->lock_api_version == cbs->lock_api_version && 102275970Scy target->supported_locktypes == cbs->supported_locktypes && 103275970Scy target->alloc == cbs->alloc && 104275970Scy target->free == cbs->free && 105275970Scy target->lock == cbs->lock && 106275970Scy target->unlock == cbs->unlock) { 107275970Scy /* no change -- allow this. */ 108275970Scy return 0; 109275970Scy } 110275970Scy event_warnx("Can't change lock callbacks once they have been " 111275970Scy "initialized."); 112275970Scy return -1; 113275970Scy } 114275970Scy if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) { 115275970Scy memcpy(target, cbs, sizeof(evthread_lock_fns_)); 116275970Scy return event_global_setup_locks_(1); 117275970Scy } else { 118275970Scy return -1; 119275970Scy } 120275970Scy} 121275970Scy 122275970Scyint 123275970Scyevthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs) 124275970Scy{ 125282408Scy struct evthread_condition_callbacks *target = evthread_get_condition_callbacks(); 126275970Scy 127275970Scy if (!cbs) { 128275970Scy if (target->alloc_condition) 129275970Scy event_warnx("Trying to disable condition functions " 130275970Scy "after they have been set up will probaby not " 131275970Scy "work."); 132275970Scy memset(target, 0, sizeof(evthread_cond_fns_)); 133275970Scy return 0; 134275970Scy } 135275970Scy if (target->alloc_condition) { 136275970Scy /* Uh oh; we already had condition callbacks set up.*/ 137275970Scy if (target->condition_api_version == cbs->condition_api_version && 138275970Scy target->alloc_condition == cbs->alloc_condition && 139275970Scy target->free_condition == cbs->free_condition && 140275970Scy target->signal_condition == cbs->signal_condition && 141275970Scy target->wait_condition == cbs->wait_condition) { 142275970Scy /* no change -- allow this. */ 143275970Scy return 0; 144275970Scy } 145275970Scy event_warnx("Can't change condition callbacks once they " 146275970Scy "have been initialized."); 147275970Scy return -1; 148275970Scy } 149275970Scy if (cbs->alloc_condition && cbs->free_condition && 150275970Scy cbs->signal_condition && cbs->wait_condition) { 151275970Scy memcpy(target, cbs, sizeof(evthread_cond_fns_)); 152275970Scy } 153275970Scy if (evthread_lock_debugging_enabled_) { 154275970Scy evthread_cond_fns_.alloc_condition = cbs->alloc_condition; 155275970Scy evthread_cond_fns_.free_condition = cbs->free_condition; 156275970Scy evthread_cond_fns_.signal_condition = cbs->signal_condition; 157275970Scy } 158275970Scy return 0; 159275970Scy} 160275970Scy 161275970Scy#define DEBUG_LOCK_SIG 0xdeb0b10c 162275970Scy 163275970Scystruct debug_lock { 164275970Scy unsigned signature; 165275970Scy unsigned locktype; 166275970Scy unsigned long held_by; 167275970Scy /* XXXX if we ever use read-write locks, we will need a separate 168275970Scy * lock to protect count. */ 169275970Scy int count; 170275970Scy void *lock; 171275970Scy}; 172275970Scy 173275970Scystatic void * 174275970Scydebug_lock_alloc(unsigned locktype) 175275970Scy{ 176275970Scy struct debug_lock *result = mm_malloc(sizeof(struct debug_lock)); 177275970Scy if (!result) 178275970Scy return NULL; 179275970Scy if (original_lock_fns_.alloc) { 180275970Scy if (!(result->lock = original_lock_fns_.alloc( 181275970Scy locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) { 182275970Scy mm_free(result); 183275970Scy return NULL; 184275970Scy } 185275970Scy } else { 186275970Scy result->lock = NULL; 187275970Scy } 188275970Scy result->signature = DEBUG_LOCK_SIG; 189275970Scy result->locktype = locktype; 190275970Scy result->count = 0; 191275970Scy result->held_by = 0; 192275970Scy return result; 193275970Scy} 194275970Scy 195275970Scystatic void 196275970Scydebug_lock_free(void *lock_, unsigned locktype) 197275970Scy{ 198275970Scy struct debug_lock *lock = lock_; 199275970Scy EVUTIL_ASSERT(lock->count == 0); 200275970Scy EVUTIL_ASSERT(locktype == lock->locktype); 201275970Scy EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 202275970Scy if (original_lock_fns_.free) { 203275970Scy original_lock_fns_.free(lock->lock, 204275970Scy lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE); 205275970Scy } 206275970Scy lock->lock = NULL; 207275970Scy lock->count = -100; 208275970Scy lock->signature = 0x12300fda; 209275970Scy mm_free(lock); 210275970Scy} 211275970Scy 212275970Scystatic void 213275970Scyevthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock) 214275970Scy{ 215275970Scy EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 216275970Scy ++lock->count; 217275970Scy if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) 218275970Scy EVUTIL_ASSERT(lock->count == 1); 219275970Scy if (evthread_id_fn_) { 220275970Scy unsigned long me; 221275970Scy me = evthread_id_fn_(); 222275970Scy if (lock->count > 1) 223275970Scy EVUTIL_ASSERT(lock->held_by == me); 224275970Scy lock->held_by = me; 225275970Scy } 226275970Scy} 227275970Scy 228275970Scystatic int 229275970Scydebug_lock_lock(unsigned mode, void *lock_) 230275970Scy{ 231275970Scy struct debug_lock *lock = lock_; 232275970Scy int res = 0; 233275970Scy if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) 234275970Scy EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); 235275970Scy else 236275970Scy EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); 237275970Scy if (original_lock_fns_.lock) 238275970Scy res = original_lock_fns_.lock(mode, lock->lock); 239275970Scy if (!res) { 240275970Scy evthread_debug_lock_mark_locked(mode, lock); 241275970Scy } 242275970Scy return res; 243275970Scy} 244275970Scy 245275970Scystatic void 246275970Scyevthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock) 247275970Scy{ 248275970Scy EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 249275970Scy if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) 250275970Scy EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); 251275970Scy else 252275970Scy EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); 253275970Scy if (evthread_id_fn_) { 254275970Scy unsigned long me; 255275970Scy me = evthread_id_fn_(); 256275970Scy EVUTIL_ASSERT(lock->held_by == me); 257275970Scy if (lock->count == 1) 258275970Scy lock->held_by = 0; 259275970Scy } 260275970Scy --lock->count; 261275970Scy EVUTIL_ASSERT(lock->count >= 0); 262275970Scy} 263275970Scy 264275970Scystatic int 265275970Scydebug_lock_unlock(unsigned mode, void *lock_) 266275970Scy{ 267275970Scy struct debug_lock *lock = lock_; 268275970Scy int res = 0; 269275970Scy evthread_debug_lock_mark_unlocked(mode, lock); 270275970Scy if (original_lock_fns_.unlock) 271275970Scy res = original_lock_fns_.unlock(mode, lock->lock); 272275970Scy return res; 273275970Scy} 274275970Scy 275275970Scystatic int 276275970Scydebug_cond_wait(void *cond_, void *lock_, const struct timeval *tv) 277275970Scy{ 278275970Scy int r; 279275970Scy struct debug_lock *lock = lock_; 280275970Scy EVUTIL_ASSERT(lock); 281275970Scy EVUTIL_ASSERT(DEBUG_LOCK_SIG == lock->signature); 282275970Scy EVLOCK_ASSERT_LOCKED(lock_); 283275970Scy evthread_debug_lock_mark_unlocked(0, lock); 284275970Scy r = original_cond_fns_.wait_condition(cond_, lock->lock, tv); 285275970Scy evthread_debug_lock_mark_locked(0, lock); 286275970Scy return r; 287275970Scy} 288275970Scy 289275970Scy/* misspelled version for backward compatibility */ 290275970Scyvoid 291275970Scyevthread_enable_lock_debuging(void) 292275970Scy{ 293275970Scy evthread_enable_lock_debugging(); 294275970Scy} 295275970Scy 296275970Scyvoid 297275970Scyevthread_enable_lock_debugging(void) 298275970Scy{ 299275970Scy struct evthread_lock_callbacks cbs = { 300275970Scy EVTHREAD_LOCK_API_VERSION, 301275970Scy EVTHREAD_LOCKTYPE_RECURSIVE, 302275970Scy debug_lock_alloc, 303275970Scy debug_lock_free, 304275970Scy debug_lock_lock, 305275970Scy debug_lock_unlock 306275970Scy }; 307275970Scy if (evthread_lock_debugging_enabled_) 308275970Scy return; 309275970Scy memcpy(&original_lock_fns_, &evthread_lock_fns_, 310275970Scy sizeof(struct evthread_lock_callbacks)); 311275970Scy memcpy(&evthread_lock_fns_, &cbs, 312275970Scy sizeof(struct evthread_lock_callbacks)); 313275970Scy 314275970Scy memcpy(&original_cond_fns_, &evthread_cond_fns_, 315275970Scy sizeof(struct evthread_condition_callbacks)); 316275970Scy evthread_cond_fns_.wait_condition = debug_cond_wait; 317275970Scy evthread_lock_debugging_enabled_ = 1; 318275970Scy 319275970Scy /* XXX return value should get checked. */ 320275970Scy event_global_setup_locks_(0); 321275970Scy} 322275970Scy 323275970Scyint 324275970Scyevthread_is_debug_lock_held_(void *lock_) 325275970Scy{ 326275970Scy struct debug_lock *lock = lock_; 327275970Scy if (! lock->count) 328275970Scy return 0; 329275970Scy if (evthread_id_fn_) { 330275970Scy unsigned long me = evthread_id_fn_(); 331275970Scy if (lock->held_by != me) 332275970Scy return 0; 333275970Scy } 334275970Scy return 1; 335275970Scy} 336275970Scy 337275970Scyvoid * 338275970Scyevthread_debug_get_real_lock_(void *lock_) 339275970Scy{ 340275970Scy struct debug_lock *lock = lock_; 341275970Scy return lock->lock; 342275970Scy} 343275970Scy 344275970Scyvoid * 345275970Scyevthread_setup_global_lock_(void *lock_, unsigned locktype, int enable_locks) 346275970Scy{ 347275970Scy /* there are four cases here: 348275970Scy 1) we're turning on debugging; locking is not on. 349275970Scy 2) we're turning on debugging; locking is on. 350275970Scy 3) we're turning on locking; debugging is not on. 351275970Scy 4) we're turning on locking; debugging is on. */ 352275970Scy 353275970Scy if (!enable_locks && original_lock_fns_.alloc == NULL) { 354275970Scy /* Case 1: allocate a debug lock. */ 355275970Scy EVUTIL_ASSERT(lock_ == NULL); 356275970Scy return debug_lock_alloc(locktype); 357275970Scy } else if (!enable_locks && original_lock_fns_.alloc != NULL) { 358275970Scy /* Case 2: wrap the lock in a debug lock. */ 359275970Scy struct debug_lock *lock; 360275970Scy EVUTIL_ASSERT(lock_ != NULL); 361275970Scy 362275970Scy if (!(locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) { 363275970Scy /* We can't wrap it: We need a recursive lock */ 364275970Scy original_lock_fns_.free(lock_, locktype); 365275970Scy return debug_lock_alloc(locktype); 366275970Scy } 367275970Scy lock = mm_malloc(sizeof(struct debug_lock)); 368275970Scy if (!lock) { 369275970Scy original_lock_fns_.free(lock_, locktype); 370275970Scy return NULL; 371275970Scy } 372275970Scy lock->lock = lock_; 373275970Scy lock->locktype = locktype; 374275970Scy lock->count = 0; 375275970Scy lock->held_by = 0; 376275970Scy return lock; 377275970Scy } else if (enable_locks && ! evthread_lock_debugging_enabled_) { 378275970Scy /* Case 3: allocate a regular lock */ 379275970Scy EVUTIL_ASSERT(lock_ == NULL); 380275970Scy return evthread_lock_fns_.alloc(locktype); 381275970Scy } else { 382275970Scy /* Case 4: Fill in a debug lock with a real lock */ 383275970Scy struct debug_lock *lock = lock_; 384275970Scy EVUTIL_ASSERT(enable_locks && 385275970Scy evthread_lock_debugging_enabled_); 386275970Scy EVUTIL_ASSERT(lock->locktype == locktype); 387275970Scy EVUTIL_ASSERT(lock->lock == NULL); 388275970Scy lock->lock = original_lock_fns_.alloc( 389275970Scy locktype|EVTHREAD_LOCKTYPE_RECURSIVE); 390275970Scy if (!lock->lock) { 391275970Scy lock->count = -200; 392275970Scy mm_free(lock); 393275970Scy return NULL; 394275970Scy } 395275970Scy return lock; 396275970Scy } 397275970Scy} 398275970Scy 399275970Scy 400275970Scy#ifndef EVTHREAD_EXPOSE_STRUCTS 401275970Scyunsigned long 402275970Scyevthreadimpl_get_id_() 403275970Scy{ 404275970Scy return evthread_id_fn_ ? evthread_id_fn_() : 1; 405275970Scy} 406275970Scyvoid * 407275970Scyevthreadimpl_lock_alloc_(unsigned locktype) 408275970Scy{ 409275970Scy return evthread_lock_fns_.alloc ? 410275970Scy evthread_lock_fns_.alloc(locktype) : NULL; 411275970Scy} 412275970Scyvoid 413275970Scyevthreadimpl_lock_free_(void *lock, unsigned locktype) 414275970Scy{ 415275970Scy if (evthread_lock_fns_.free) 416275970Scy evthread_lock_fns_.free(lock, locktype); 417275970Scy} 418275970Scyint 419275970Scyevthreadimpl_lock_lock_(unsigned mode, void *lock) 420275970Scy{ 421275970Scy if (evthread_lock_fns_.lock) 422275970Scy return evthread_lock_fns_.lock(mode, lock); 423275970Scy else 424275970Scy return 0; 425275970Scy} 426275970Scyint 427275970Scyevthreadimpl_lock_unlock_(unsigned mode, void *lock) 428275970Scy{ 429275970Scy if (evthread_lock_fns_.unlock) 430275970Scy return evthread_lock_fns_.unlock(mode, lock); 431275970Scy else 432275970Scy return 0; 433275970Scy} 434275970Scyvoid * 435275970Scyevthreadimpl_cond_alloc_(unsigned condtype) 436275970Scy{ 437275970Scy return evthread_cond_fns_.alloc_condition ? 438275970Scy evthread_cond_fns_.alloc_condition(condtype) : NULL; 439275970Scy} 440275970Scyvoid 441275970Scyevthreadimpl_cond_free_(void *cond) 442275970Scy{ 443275970Scy if (evthread_cond_fns_.free_condition) 444275970Scy evthread_cond_fns_.free_condition(cond); 445275970Scy} 446275970Scyint 447275970Scyevthreadimpl_cond_signal_(void *cond, int broadcast) 448275970Scy{ 449275970Scy if (evthread_cond_fns_.signal_condition) 450275970Scy return evthread_cond_fns_.signal_condition(cond, broadcast); 451275970Scy else 452275970Scy return 0; 453275970Scy} 454275970Scyint 455275970Scyevthreadimpl_cond_wait_(void *cond, void *lock, const struct timeval *tv) 456275970Scy{ 457275970Scy if (evthread_cond_fns_.wait_condition) 458275970Scy return evthread_cond_fns_.wait_condition(cond, lock, tv); 459275970Scy else 460275970Scy return 0; 461275970Scy} 462275970Scyint 463275970Scyevthreadimpl_is_lock_debugging_enabled_(void) 464275970Scy{ 465275970Scy return evthread_lock_debugging_enabled_; 466275970Scy} 467275970Scy 468275970Scyint 469275970Scyevthreadimpl_locking_enabled_(void) 470275970Scy{ 471275970Scy return evthread_lock_fns_.lock != NULL; 472275970Scy} 473275970Scy#endif 474275970Scy 475275970Scy#endif 476