1eaad808eSchristos /** 2eaad808eSchristos * testcode/checklocks.h - wrapper on locks that checks access. 3eaad808eSchristos * 4eaad808eSchristos * Copyright (c) 2007, NLnet Labs. All rights reserved. 5eaad808eSchristos * 6eaad808eSchristos * This software is open source. 7eaad808eSchristos * 8eaad808eSchristos * Redistribution and use in source and binary forms, with or without 9eaad808eSchristos * modification, are permitted provided that the following conditions 10eaad808eSchristos * are met: 11eaad808eSchristos * 12eaad808eSchristos * Redistributions of source code must retain the above copyright notice, 13eaad808eSchristos * this list of conditions and the following disclaimer. 14eaad808eSchristos * 15eaad808eSchristos * Redistributions in binary form must reproduce the above copyright notice, 16eaad808eSchristos * this list of conditions and the following disclaimer in the documentation 17eaad808eSchristos * and/or other materials provided with the distribution. 18eaad808eSchristos * 19eaad808eSchristos * Neither the name of the NLNET LABS nor the names of its contributors may 20eaad808eSchristos * be used to endorse or promote products derived from this software without 21eaad808eSchristos * specific prior written permission. 22eaad808eSchristos * 23eaad808eSchristos * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24eaad808eSchristos * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25eaad808eSchristos * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26eaad808eSchristos * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27eaad808eSchristos * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28eaad808eSchristos * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29eaad808eSchristos * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30eaad808eSchristos * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31eaad808eSchristos * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32eaad808eSchristos * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33eaad808eSchristos * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34eaad808eSchristos */ 35eaad808eSchristos 36eaad808eSchristos #ifndef TESTCODE_CHECK_LOCKS_H 37eaad808eSchristos #define TESTCODE_CHECK_LOCKS_H 38eaad808eSchristos 39eaad808eSchristos /** 40eaad808eSchristos * \file 41eaad808eSchristos * Locks that are checked. 42eaad808eSchristos * 43eaad808eSchristos * Holds information per lock and per thread. 44eaad808eSchristos * That information is protected by a mutex (unchecked). 45eaad808eSchristos * 46eaad808eSchristos * Checks: 47eaad808eSchristos * o which func, file, line created the lock. 48eaad808eSchristos * o contention count, measures amount of contention on the lock. 49eaad808eSchristos * o the memory region(s) that the lock protects are 50eaad808eSchristos * memcmp'ed to ascertain no race conditions. 51eaad808eSchristos * o checks that locks are unlocked properly (before deletion). 52eaad808eSchristos * keeps which func, file, line that locked it. 53eaad808eSchristos * o checks deadlocks with timeout so it can print errors for them. 54eaad808eSchristos * 55eaad808eSchristos * Limitations: 56eaad808eSchristos * o Detects unprotected memory access when the lock is locked or freed, 57eaad808eSchristos * which detects races only if they happen, and only if in protected 58eaad808eSchristos * memory areas. 59eaad808eSchristos * o Detects deadlocks by timeout, so approximately, as they happen. 60eaad808eSchristos * o Does not check order of locking. 61eaad808eSchristos * o Uses a lot of memory. 62eaad808eSchristos * o The checks use locks themselves, changing scheduling, 63eaad808eSchristos * thus changing what races you see. 64eaad808eSchristos */ 65eaad808eSchristos 66eaad808eSchristos #ifdef USE_THREAD_DEBUG 67eaad808eSchristos #ifndef HAVE_PTHREAD 68eaad808eSchristos /* we need the *timed*lock() routines to use for deadlock detection. */ 69eaad808eSchristos #error "Need pthreads for checked locks" 70eaad808eSchristos #endif 71eaad808eSchristos /******************* THREAD DEBUG ************************/ 72eaad808eSchristos #include <pthread.h> 73eaad808eSchristos 74eaad808eSchristos /** How many threads to allocate for */ 75eaad808eSchristos #define THRDEBUG_MAX_THREADS 32 /* threads */ 76eaad808eSchristos /** do we check locking order */ 77eaad808eSchristos extern int check_locking_order; 78eaad808eSchristos 79eaad808eSchristos /** 80eaad808eSchristos * Protection memory area. 81eaad808eSchristos * It is copied to a holding buffer to compare against later. 82eaad808eSchristos * Note that it may encompass the lock structure. 83eaad808eSchristos */ 84eaad808eSchristos struct protected_area { 85eaad808eSchristos /** where the memory region starts */ 86eaad808eSchristos void* region; 87eaad808eSchristos /** size of the region */ 88eaad808eSchristos size_t size; 89eaad808eSchristos /** backbuffer that holds a copy, of same size. */ 90eaad808eSchristos void* hold; 91eaad808eSchristos /** next protected area in list */ 92eaad808eSchristos struct protected_area* next; 93eaad808eSchristos }; 94eaad808eSchristos 95eaad808eSchristos /** 96eaad808eSchristos * Per thread information for locking debug wrappers. 97eaad808eSchristos */ 98eaad808eSchristos struct thr_check { 99eaad808eSchristos /** thread id */ 100eaad808eSchristos pthread_t id; 101eaad808eSchristos /** real thread func */ 102eaad808eSchristos void* (*func)(void*); 103eaad808eSchristos /** func user arg */ 104eaad808eSchristos void* arg; 105eaad808eSchristos /** number of thread in list structure */ 106eaad808eSchristos int num; 107eaad808eSchristos /** instance number - how many locks have been created by thread */ 108eaad808eSchristos int locks_created; 109eaad808eSchristos /** file to write locking order information to */ 110eaad808eSchristos FILE* order_info; 111eaad808eSchristos /** 112eaad808eSchristos * List of locks that this thread is holding, double 113eaad808eSchristos * linked list. The first element is the most recent lock acquired. 114eaad808eSchristos * So it represents the stack of locks acquired. (of all types). 115eaad808eSchristos */ 116eaad808eSchristos struct checked_lock *holding_first, *holding_last; 117eaad808eSchristos /** if the thread is currently waiting for a lock, which one */ 118eaad808eSchristos struct checked_lock* waiting; 119eaad808eSchristos }; 120eaad808eSchristos 121eaad808eSchristos /** 122eaad808eSchristos * One structure for all types of locks. 123eaad808eSchristos */ 124eaad808eSchristos struct checked_lock { 125eaad808eSchristos /** mutex for exclusive access to this structure */ 126eaad808eSchristos pthread_mutex_t lock; 127eaad808eSchristos /** list of memory regions protected by this checked lock */ 128eaad808eSchristos struct protected_area* prot; 129eaad808eSchristos /** where was this lock created */ 130eaad808eSchristos const char* create_func, *create_file; 131eaad808eSchristos /** where was this lock created */ 132eaad808eSchristos int create_line; 133eaad808eSchristos /** unique instance identifier */ 134eaad808eSchristos int create_thread, create_instance; 135eaad808eSchristos /** contention count */ 136eaad808eSchristos size_t contention_count; 137eaad808eSchristos /** number of times locked, ever */ 138eaad808eSchristos size_t history_count; 139eaad808eSchristos /** hold count (how many threads are holding this lock) */ 140eaad808eSchristos int hold_count; 141eaad808eSchristos /** how many threads are waiting for this lock */ 142eaad808eSchristos int wait_count; 143eaad808eSchristos /** who touched it last */ 144eaad808eSchristos const char* holder_func, *holder_file; 145eaad808eSchristos /** who touched it last */ 146eaad808eSchristos int holder_line; 147eaad808eSchristos /** who owns the lock now */ 148eaad808eSchristos struct thr_check* holder; 149eaad808eSchristos /** for rwlocks, the writelock holder */ 150eaad808eSchristos struct thr_check* writeholder; 151eaad808eSchristos 152eaad808eSchristos /** next lock a thread is holding (less recent) */ 153eaad808eSchristos struct checked_lock* next_held_lock[THRDEBUG_MAX_THREADS]; 154eaad808eSchristos /** prev lock a thread is holding (more recent) */ 155eaad808eSchristos struct checked_lock* prev_held_lock[THRDEBUG_MAX_THREADS]; 156eaad808eSchristos 157eaad808eSchristos /** type of lock */ 158eaad808eSchristos enum check_lock_type { 159eaad808eSchristos /** basic mutex */ 160eaad808eSchristos check_lock_mutex, 161eaad808eSchristos /** fast spinlock */ 162eaad808eSchristos check_lock_spinlock, 163eaad808eSchristos /** rwlock */ 164eaad808eSchristos check_lock_rwlock 165eaad808eSchristos } type; 166eaad808eSchristos /** the lock itself, see type to disambiguate the union */ 167eaad808eSchristos union { 168eaad808eSchristos /** mutex */ 169eaad808eSchristos pthread_mutex_t mutex; 170eaad808eSchristos /** spinlock */ 171eaad808eSchristos pthread_spinlock_t spinlock; 172eaad808eSchristos /** rwlock */ 173eaad808eSchristos pthread_rwlock_t rwlock; 174eaad808eSchristos } u; 175eaad808eSchristos }; 176eaad808eSchristos 177eaad808eSchristos /** 178eaad808eSchristos * Additional call for the user to specify what areas are protected 179eaad808eSchristos * @param lock: the lock that protects the area. It can be inside the area. 180eaad808eSchristos * The lock must be inited. Call with user lock. (any type). 181eaad808eSchristos * It demangles the lock itself (struct checked_lock**). 182eaad808eSchristos * @param area: ptr to mem. 183eaad808eSchristos * @param size: length of area. 184eaad808eSchristos * You can call it multiple times with the same lock to give several areas. 185*762909a6Schristos * Call it when you are done initializing the area, since it will be copied 186eaad808eSchristos * at this time and protected right away against unauthorised changes until 187eaad808eSchristos * the next lock() call is done. 188eaad808eSchristos */ 189eaad808eSchristos void lock_protect(void* lock, void* area, size_t size); 190eaad808eSchristos 191eaad808eSchristos /** 192eaad808eSchristos * Remove protected area from lock. 193eaad808eSchristos * No need to call this when deleting the lock. 194eaad808eSchristos * @param lock: the lock, any type, (struct checked_lock**). 195eaad808eSchristos * @param area: pointer to memory. 196eaad808eSchristos */ 197eaad808eSchristos void lock_unprotect(void* lock, void* area); 198eaad808eSchristos 199eaad808eSchristos /** 200eaad808eSchristos * Get memory associated with a checked lock 201eaad808eSchristos * @param lock: the checked lock, any type. (struct checked_lock**). 202eaad808eSchristos * @return: in bytes, including protected areas. 203eaad808eSchristos */ 204eaad808eSchristos size_t lock_get_mem(void* lock); 205eaad808eSchristos 206eaad808eSchristos /** 207eaad808eSchristos * Initialise checklock. Sets up internal debug structures. 208eaad808eSchristos */ 209eaad808eSchristos void checklock_start(void); 210eaad808eSchristos 211eaad808eSchristos /** 212eaad808eSchristos * Cleanup internal debug state. 213eaad808eSchristos */ 214eaad808eSchristos void checklock_stop(void); 215eaad808eSchristos 216eaad808eSchristos /** 217eaad808eSchristos * Init locks. 218eaad808eSchristos * @param type: what type of lock this is. 219eaad808eSchristos * @param lock: ptr to user alloced ptr structure. This is inited. 220eaad808eSchristos * So an alloc is done and the ptr is stored as result. 221eaad808eSchristos * @param func: caller function name. 222eaad808eSchristos * @param file: caller file name. 223eaad808eSchristos * @param line: caller line number. 224eaad808eSchristos */ 225eaad808eSchristos void checklock_init(enum check_lock_type type, struct checked_lock** lock, 226eaad808eSchristos const char* func, const char* file, int line); 227eaad808eSchristos 228eaad808eSchristos /** 229eaad808eSchristos * Destroy locks. Free the structure. 230eaad808eSchristos * @param type: what type of lock this is. 231eaad808eSchristos * @param lock: ptr to user alloced structure. This is destroyed. 232eaad808eSchristos * @param func: caller function name. 233eaad808eSchristos * @param file: caller file name. 234eaad808eSchristos * @param line: caller line number. 235eaad808eSchristos */ 236eaad808eSchristos void checklock_destroy(enum check_lock_type type, struct checked_lock** lock, 237eaad808eSchristos const char* func, const char* file, int line); 238eaad808eSchristos 239eaad808eSchristos /** 240eaad808eSchristos * Acquire readlock. 241eaad808eSchristos * @param type: what type of lock this is. Had better be a rwlock. 242eaad808eSchristos * @param lock: ptr to lock. 243eaad808eSchristos * @param func: caller function name. 244eaad808eSchristos * @param file: caller file name. 245eaad808eSchristos * @param line: caller line number. 246eaad808eSchristos */ 247eaad808eSchristos void checklock_rdlock(enum check_lock_type type, struct checked_lock* lock, 248eaad808eSchristos const char* func, const char* file, int line); 249eaad808eSchristos 250eaad808eSchristos /** 251eaad808eSchristos * Acquire writelock. 252eaad808eSchristos * @param type: what type of lock this is. Had better be a rwlock. 253eaad808eSchristos * @param lock: ptr to lock. 254eaad808eSchristos * @param func: caller function name. 255eaad808eSchristos * @param file: caller file name. 256eaad808eSchristos * @param line: caller line number. 257eaad808eSchristos */ 258eaad808eSchristos void checklock_wrlock(enum check_lock_type type, struct checked_lock* lock, 259eaad808eSchristos const char* func, const char* file, int line); 260eaad808eSchristos 261eaad808eSchristos /** 262eaad808eSchristos * Locks. 263eaad808eSchristos * @param type: what type of lock this is. Had better be mutex or spinlock. 264eaad808eSchristos * @param lock: the lock. 265eaad808eSchristos * @param func: caller function name. 266eaad808eSchristos * @param file: caller file name. 267eaad808eSchristos * @param line: caller line number. 268eaad808eSchristos */ 269eaad808eSchristos void checklock_lock(enum check_lock_type type, struct checked_lock* lock, 270eaad808eSchristos const char* func, const char* file, int line); 271eaad808eSchristos 272eaad808eSchristos /** 273eaad808eSchristos * Unlocks. 274eaad808eSchristos * @param type: what type of lock this is. 275eaad808eSchristos * @param lock: the lock. 276eaad808eSchristos * @param func: caller function name. 277eaad808eSchristos * @param file: caller file name. 278eaad808eSchristos * @param line: caller line number. 279eaad808eSchristos */ 280eaad808eSchristos void checklock_unlock(enum check_lock_type type, struct checked_lock* lock, 281eaad808eSchristos const char* func, const char* file, int line); 282eaad808eSchristos 283eaad808eSchristos /** 284eaad808eSchristos * Create thread. 285eaad808eSchristos * @param thr: Thread id, where to store result. 286eaad808eSchristos * @param func: thread start function. 287eaad808eSchristos * @param arg: user argument. 288eaad808eSchristos */ 289eaad808eSchristos void checklock_thrcreate(pthread_t* thr, void* (*func)(void*), void* arg); 290eaad808eSchristos 291eaad808eSchristos /** 292eaad808eSchristos * Wait for thread to exit. Returns thread return value. 293eaad808eSchristos * @param thread: thread to wait for. 294eaad808eSchristos */ 295eaad808eSchristos void checklock_thrjoin(pthread_t thread); 296eaad808eSchristos 297eaad808eSchristos /** structures to enable compiler type checking on the locks. 298eaad808eSchristos * Also the pointer makes it so that the lock can be part of the protected 299eaad808eSchristos * region without any possible problem (since the ptr will stay the same.) 300eaad808eSchristos * i.e. there can be contention and readlocks stored in checked_lock, while 301eaad808eSchristos * the protected area stays the same, even though it contains (ptr to) lock. 302eaad808eSchristos */ 303eaad808eSchristos struct checked_lock_rw { struct checked_lock* c_rw; }; 304eaad808eSchristos /** structures to enable compiler type checking on the locks. */ 305eaad808eSchristos struct checked_lock_mutex { struct checked_lock* c_m; }; 306eaad808eSchristos /** structures to enable compiler type checking on the locks. */ 307eaad808eSchristos struct checked_lock_spl { struct checked_lock* c_spl; }; 308eaad808eSchristos 309eaad808eSchristos /** debugging rwlock */ 310*762909a6Schristos typedef struct checked_lock_rw lock_rw_type; 311eaad808eSchristos #define lock_rw_init(lock) checklock_init(check_lock_rwlock, &((lock)->c_rw), __func__, __FILE__, __LINE__) 312eaad808eSchristos #define lock_rw_destroy(lock) checklock_destroy(check_lock_rwlock, &((lock)->c_rw), __func__, __FILE__, __LINE__) 313eaad808eSchristos #define lock_rw_rdlock(lock) checklock_rdlock(check_lock_rwlock, (lock)->c_rw, __func__, __FILE__, __LINE__) 314eaad808eSchristos #define lock_rw_wrlock(lock) checklock_wrlock(check_lock_rwlock, (lock)->c_rw, __func__, __FILE__, __LINE__) 315eaad808eSchristos #define lock_rw_unlock(lock) checklock_unlock(check_lock_rwlock, (lock)->c_rw, __func__, __FILE__, __LINE__) 316eaad808eSchristos 317eaad808eSchristos /** debugging mutex */ 318*762909a6Schristos typedef struct checked_lock_mutex lock_basic_type; 319eaad808eSchristos #define lock_basic_init(lock) checklock_init(check_lock_mutex, &((lock)->c_m), __func__, __FILE__, __LINE__) 320eaad808eSchristos #define lock_basic_destroy(lock) checklock_destroy(check_lock_mutex, &((lock)->c_m), __func__, __FILE__, __LINE__) 321eaad808eSchristos #define lock_basic_lock(lock) checklock_lock(check_lock_mutex, (lock)->c_m, __func__, __FILE__, __LINE__) 322eaad808eSchristos #define lock_basic_unlock(lock) checklock_unlock(check_lock_mutex, (lock)->c_m, __func__, __FILE__, __LINE__) 323eaad808eSchristos 324eaad808eSchristos /** debugging spinlock */ 325*762909a6Schristos typedef struct checked_lock_spl lock_quick_type; 326eaad808eSchristos #define lock_quick_init(lock) checklock_init(check_lock_spinlock, &((lock)->c_spl), __func__, __FILE__, __LINE__) 327eaad808eSchristos #define lock_quick_destroy(lock) checklock_destroy(check_lock_spinlock, &((lock)->c_spl), __func__, __FILE__, __LINE__) 328eaad808eSchristos #define lock_quick_lock(lock) checklock_lock(check_lock_spinlock, (lock)->c_spl, __func__, __FILE__, __LINE__) 329eaad808eSchristos #define lock_quick_unlock(lock) checklock_unlock(check_lock_spinlock, (lock)->c_spl, __func__, __FILE__, __LINE__) 330eaad808eSchristos 331eaad808eSchristos /** we use the pthread id, our thr_check structure is kept behind the scenes */ 332*762909a6Schristos typedef pthread_t ub_thread_type; 333eaad808eSchristos #define ub_thread_create(thr, func, arg) checklock_thrcreate(thr, func, arg) 334eaad808eSchristos #define ub_thread_self() pthread_self() 335eaad808eSchristos #define ub_thread_join(thread) checklock_thrjoin(thread) 336eaad808eSchristos 337*762909a6Schristos typedef pthread_key_t ub_thread_key_type; 338eaad808eSchristos #define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f)) 339eaad808eSchristos #define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v)) 340eaad808eSchristos #define ub_thread_key_get(key) pthread_getspecific(key) 341eaad808eSchristos 342eaad808eSchristos #endif /* USE_THREAD_DEBUG */ 343eaad808eSchristos #endif /* TESTCODE_CHECK_LOCKS_H */ 344