1 /* 2 * Copyright (c) 2008-2010 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 29 #ifndef _EVENT_DISABLE_THREAD_SUPPORT 30 31 #include <event2/thread.h> 32 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include "log-internal.h" 37 #include "mm-internal.h" 38 #include "util-internal.h" 39 #include "evthread-internal.h" 40 41 #ifdef EVTHREAD_EXPOSE_STRUCTS 42 #define GLOBAL 43 #else 44 #define GLOBAL static 45 #endif 46 47 /* globals */ 48 GLOBAL int _evthread_lock_debugging_enabled = 0; 49 GLOBAL struct evthread_lock_callbacks _evthread_lock_fns = { 50 0, 0, NULL, NULL, NULL, NULL 51 }; 52 GLOBAL unsigned long (*_evthread_id_fn)(void) = NULL; 53 GLOBAL struct evthread_condition_callbacks _evthread_cond_fns = { 54 0, NULL, NULL, NULL, NULL 55 }; 56 57 /* Used for debugging */ 58 static struct evthread_lock_callbacks _original_lock_fns = { 59 0, 0, NULL, NULL, NULL, NULL 60 }; 61 static struct evthread_condition_callbacks _original_cond_fns = { 62 0, NULL, NULL, NULL, NULL 63 }; 64 65 void 66 evthread_set_id_callback(unsigned long (*id_fn)(void)) 67 { 68 _evthread_id_fn = id_fn; 69 } 70 71 int 72 evthread_set_lock_callbacks(const struct evthread_lock_callbacks *cbs) 73 { 74 struct evthread_lock_callbacks *target = 75 _evthread_lock_debugging_enabled 76 ? &_original_lock_fns : &_evthread_lock_fns; 77 78 if (!cbs) { 79 memset(target, 0, sizeof(_evthread_lock_fns)); 80 return 0; 81 } 82 if (cbs->alloc && cbs->free && cbs->lock && cbs->unlock) { 83 memcpy(target, cbs, sizeof(_evthread_lock_fns)); 84 return 0; 85 } else { 86 return -1; 87 } 88 } 89 90 int 91 evthread_set_condition_callbacks(const struct evthread_condition_callbacks *cbs) 92 { 93 struct evthread_condition_callbacks *target = 94 _evthread_lock_debugging_enabled 95 ? &_original_cond_fns : &_evthread_cond_fns; 96 97 if (!cbs) { 98 memset(target, 0, sizeof(_evthread_cond_fns)); 99 } else if (cbs->alloc_condition && cbs->free_condition && 100 cbs->signal_condition && cbs->wait_condition) { 101 memcpy(target, cbs, sizeof(_evthread_cond_fns)); 102 } 103 if (_evthread_lock_debugging_enabled) { 104 _evthread_cond_fns.alloc_condition = cbs->alloc_condition; 105 _evthread_cond_fns.free_condition = cbs->free_condition; 106 _evthread_cond_fns.signal_condition = cbs->signal_condition; 107 } 108 return 0; 109 } 110 111 struct debug_lock { 112 unsigned locktype; 113 unsigned long held_by; 114 /* XXXX if we ever use read-write locks, we will need a separate 115 * lock to protect count. */ 116 int count; 117 void *lock; 118 }; 119 120 static void * 121 debug_lock_alloc(unsigned locktype) 122 { 123 struct debug_lock *result = mm_malloc(sizeof(struct debug_lock)); 124 if (!result) 125 return NULL; 126 if (_original_lock_fns.alloc) { 127 if (!(result->lock = _original_lock_fns.alloc( 128 locktype|EVTHREAD_LOCKTYPE_RECURSIVE))) { 129 mm_free(result); 130 return NULL; 131 } 132 } else { 133 result->lock = NULL; 134 } 135 result->locktype = locktype; 136 result->count = 0; 137 result->held_by = 0; 138 return result; 139 } 140 141 static void 142 debug_lock_free(void *lock_, unsigned locktype) 143 { 144 struct debug_lock *lock = lock_; 145 EVUTIL_ASSERT(lock->count == 0); 146 EVUTIL_ASSERT(locktype == lock->locktype); 147 if (_original_lock_fns.free) { 148 _original_lock_fns.free(lock->lock, 149 lock->locktype|EVTHREAD_LOCKTYPE_RECURSIVE); 150 } 151 lock->lock = NULL; 152 lock->count = -100; 153 mm_free(lock); 154 } 155 156 static void 157 evthread_debug_lock_mark_locked(unsigned mode, struct debug_lock *lock) 158 { 159 ++lock->count; 160 if (!(lock->locktype & EVTHREAD_LOCKTYPE_RECURSIVE)) 161 EVUTIL_ASSERT(lock->count == 1); 162 if (_evthread_id_fn) { 163 unsigned long me; 164 me = _evthread_id_fn(); 165 if (lock->count > 1) 166 EVUTIL_ASSERT(lock->held_by == me); 167 lock->held_by = me; 168 } 169 } 170 171 static int 172 debug_lock_lock(unsigned mode, void *lock_) 173 { 174 struct debug_lock *lock = lock_; 175 int res = 0; 176 if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) 177 EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); 178 else 179 EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); 180 if (_original_lock_fns.lock) 181 res = _original_lock_fns.lock(mode, lock->lock); 182 if (!res) { 183 evthread_debug_lock_mark_locked(mode, lock); 184 } 185 return res; 186 } 187 188 static void 189 evthread_debug_lock_mark_unlocked(unsigned mode, struct debug_lock *lock) 190 { 191 if (lock->locktype & EVTHREAD_LOCKTYPE_READWRITE) 192 EVUTIL_ASSERT(mode & (EVTHREAD_READ|EVTHREAD_WRITE)); 193 else 194 EVUTIL_ASSERT((mode & (EVTHREAD_READ|EVTHREAD_WRITE)) == 0); 195 if (_evthread_id_fn) { 196 EVUTIL_ASSERT(lock->held_by == _evthread_id_fn()); 197 if (lock->count == 1) 198 lock->held_by = 0; 199 } 200 --lock->count; 201 EVUTIL_ASSERT(lock->count >= 0); 202 } 203 204 static int 205 debug_lock_unlock(unsigned mode, void *lock_) 206 { 207 struct debug_lock *lock = lock_; 208 int res = 0; 209 evthread_debug_lock_mark_unlocked(mode, lock); 210 if (_original_lock_fns.unlock) 211 res = _original_lock_fns.unlock(mode, lock->lock); 212 return res; 213 } 214 215 static int 216 debug_cond_wait(void *_cond, void *_lock, const struct timeval *tv) 217 { 218 int r; 219 struct debug_lock *lock = _lock; 220 EVLOCK_ASSERT_LOCKED(_lock); 221 evthread_debug_lock_mark_unlocked(0, lock); 222 r = _original_cond_fns.wait_condition(_cond, lock->lock, tv); 223 evthread_debug_lock_mark_locked(0, lock); 224 return r; 225 } 226 227 void 228 evthread_enable_lock_debuging(void) 229 { 230 struct evthread_lock_callbacks cbs = { 231 EVTHREAD_LOCK_API_VERSION, 232 EVTHREAD_LOCKTYPE_RECURSIVE, 233 debug_lock_alloc, 234 debug_lock_free, 235 debug_lock_lock, 236 debug_lock_unlock 237 }; 238 if (_evthread_lock_debugging_enabled) 239 return; 240 memcpy(&_original_lock_fns, &_evthread_lock_fns, 241 sizeof(struct evthread_lock_callbacks)); 242 memcpy(&_evthread_lock_fns, &cbs, 243 sizeof(struct evthread_lock_callbacks)); 244 245 memcpy(&_original_cond_fns, &_evthread_cond_fns, 246 sizeof(struct evthread_condition_callbacks)); 247 _evthread_cond_fns.wait_condition = debug_cond_wait; 248 _evthread_lock_debugging_enabled = 1; 249 } 250 251 int 252 _evthread_is_debug_lock_held(void *lock_) 253 { 254 struct debug_lock *lock = lock_; 255 if (! lock->count) 256 return 0; 257 if (_evthread_id_fn) { 258 unsigned long me = _evthread_id_fn(); 259 if (lock->held_by != me) 260 return 0; 261 } 262 return 1; 263 } 264 265 void * 266 _evthread_debug_get_real_lock(void *lock_) 267 { 268 struct debug_lock *lock = lock_; 269 return lock->lock; 270 } 271 272 #ifndef EVTHREAD_EXPOSE_STRUCTS 273 unsigned long 274 _evthreadimpl_get_id() 275 { 276 return _evthread_id_fn ? _evthread_id_fn() : 1; 277 } 278 void * 279 _evthreadimpl_lock_alloc(unsigned locktype) 280 { 281 return _evthread_lock_fns.alloc ? 282 _evthread_lock_fns.alloc(locktype) : NULL; 283 } 284 void 285 _evthreadimpl_lock_free(void *lock, unsigned locktype) 286 { 287 if (_evthread_lock_fns.free) 288 _evthread_lock_fns.free(lock, locktype); 289 } 290 int 291 _evthreadimpl_lock_lock(unsigned mode, void *lock) 292 { 293 if (_evthread_lock_fns.lock) 294 return _evthread_lock_fns.lock(mode, lock); 295 else 296 return 0; 297 } 298 int 299 _evthreadimpl_lock_unlock(unsigned mode, void *lock) 300 { 301 if (_evthread_lock_fns.unlock) 302 return _evthread_lock_fns.unlock(mode, lock); 303 else 304 return 0; 305 } 306 void * 307 _evthreadimpl_cond_alloc(unsigned condtype) 308 { 309 return _evthread_cond_fns.alloc_condition ? 310 _evthread_cond_fns.alloc_condition(condtype) : NULL; 311 } 312 void 313 _evthreadimpl_cond_free(void *cond) 314 { 315 if (_evthread_cond_fns.free_condition) 316 _evthread_cond_fns.free_condition(cond); 317 } 318 int 319 _evthreadimpl_cond_signal(void *cond, int broadcast) 320 { 321 if (_evthread_cond_fns.signal_condition) 322 return _evthread_cond_fns.signal_condition(cond, broadcast); 323 else 324 return 0; 325 } 326 int 327 _evthreadimpl_cond_wait(void *cond, void *lock, const struct timeval *tv) 328 { 329 if (_evthread_cond_fns.wait_condition) 330 return _evthread_cond_fns.wait_condition(cond, lock, tv); 331 else 332 return 0; 333 } 334 int 335 _evthreadimpl_is_lock_debugging_enabled(void) 336 { 337 return _evthread_lock_debugging_enabled; 338 } 339 #endif 340 341 #endif 342