1*be771a7bSCy Schubert /** 2*be771a7bSCy Schubert * testcode/checklocks.c - wrapper on locks that checks access. 3*be771a7bSCy Schubert * 4*be771a7bSCy Schubert * Copyright (c) 2007, NLnet Labs. All rights reserved. 5*be771a7bSCy Schubert * 6*be771a7bSCy Schubert * This software is open source. 7*be771a7bSCy Schubert * 8*be771a7bSCy Schubert * Redistribution and use in source and binary forms, with or without 9*be771a7bSCy Schubert * modification, are permitted provided that the following conditions 10*be771a7bSCy Schubert * are met: 11*be771a7bSCy Schubert * 12*be771a7bSCy Schubert * Redistributions of source code must retain the above copyright notice, 13*be771a7bSCy Schubert * this list of conditions and the following disclaimer. 14*be771a7bSCy Schubert * 15*be771a7bSCy Schubert * Redistributions in binary form must reproduce the above copyright notice, 16*be771a7bSCy Schubert * this list of conditions and the following disclaimer in the documentation 17*be771a7bSCy Schubert * and/or other materials provided with the distribution. 18*be771a7bSCy Schubert * 19*be771a7bSCy Schubert * Neither the name of the NLNET LABS nor the names of its contributors may 20*be771a7bSCy Schubert * be used to endorse or promote products derived from this software without 21*be771a7bSCy Schubert * specific prior written permission. 22*be771a7bSCy Schubert * 23*be771a7bSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 24*be771a7bSCy Schubert * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 25*be771a7bSCy Schubert * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 26*be771a7bSCy Schubert * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 27*be771a7bSCy Schubert * HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 28*be771a7bSCy Schubert * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 29*be771a7bSCy Schubert * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 30*be771a7bSCy Schubert * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 31*be771a7bSCy Schubert * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 32*be771a7bSCy Schubert * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 33*be771a7bSCy Schubert * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 34*be771a7bSCy Schubert */ 35*be771a7bSCy Schubert 36*be771a7bSCy Schubert #include "config.h" 37*be771a7bSCy Schubert #include <signal.h> 38*be771a7bSCy Schubert #include "util/locks.h" /* include before checklocks.h */ 39*be771a7bSCy Schubert #include "testcode/checklocks.h" 40*be771a7bSCy Schubert 41*be771a7bSCy Schubert /** 42*be771a7bSCy Schubert * \file 43*be771a7bSCy Schubert * Locks that are checked. 44*be771a7bSCy Schubert * 45*be771a7bSCy Schubert * Ugly hack: uses the fact that workers start with an int thread_num, and 46*be771a7bSCy Schubert * are passed to thread_create to make the thread numbers here the same as 47*be771a7bSCy Schubert * those used for logging which is nice. 48*be771a7bSCy Schubert * 49*be771a7bSCy Schubert * Todo: 50*be771a7bSCy Schubert * - debug status print, of thread lock stacks, and current waiting. 51*be771a7bSCy Schubert */ 52*be771a7bSCy Schubert #ifdef USE_THREAD_DEBUG 53*be771a7bSCy Schubert 54*be771a7bSCy Schubert /** How long to wait before lock attempt is a failure. */ 55*be771a7bSCy Schubert #define CHECK_LOCK_TIMEOUT 120 /* seconds */ 56*be771a7bSCy Schubert /** How long to wait before join attempt is a failure. */ 57*be771a7bSCy Schubert #define CHECK_JOIN_TIMEOUT 120 /* seconds */ 58*be771a7bSCy Schubert 59*be771a7bSCy Schubert /** if key has been created */ 60*be771a7bSCy Schubert static int key_created = 0; 61*be771a7bSCy Schubert /** if the key was deleted, i.e. we have quit */ 62*be771a7bSCy Schubert static int key_deleted = 0; 63*be771a7bSCy Schubert /** we hide the thread debug info with this key. */ 64*be771a7bSCy Schubert static ub_thread_key_type thr_debug_key; 65*be771a7bSCy Schubert /** the list of threads, so all threads can be examined. NULL if unused. */ 66*be771a7bSCy Schubert static struct thr_check* thread_infos[THRDEBUG_MAX_THREADS]; 67*be771a7bSCy Schubert /** stored maximum lock number for threads, when a thread is restarted the 68*be771a7bSCy Schubert * number is kept track of, because the new locks get new id numbers. */ 69*be771a7bSCy Schubert static int thread_lockcount[THRDEBUG_MAX_THREADS]; 70*be771a7bSCy Schubert /** do we check locking order */ 71*be771a7bSCy Schubert int check_locking_order = 1; 72*be771a7bSCy Schubert /** the pid of this runset, reasonably unique. */ 73*be771a7bSCy Schubert static pid_t check_lock_pid; 74*be771a7bSCy Schubert /** the name of the output file */ 75*be771a7bSCy Schubert static const char* output_name = "ublocktrace"; 76*be771a7bSCy Schubert /** 77*be771a7bSCy Schubert * Should checklocks print a trace of the lock and unlock calls. 78*be771a7bSCy Schubert * It uses fprintf for that because the log function uses a lock and that 79*be771a7bSCy Schubert * would loop otherwise. 80*be771a7bSCy Schubert */ 81*be771a7bSCy Schubert static int verbose_locking = 0; 82*be771a7bSCy Schubert /** 83*be771a7bSCy Schubert * Assume lock 0 0 (create_thread, create_instance), is the log lock and 84*be771a7bSCy Schubert * do not print for that. Otherwise the output is full of log lock accesses. 85*be771a7bSCy Schubert */ 86*be771a7bSCy Schubert static int verbose_locking_not_loglock = 1; 87*be771a7bSCy Schubert 88*be771a7bSCy Schubert /** print all possible debug info on the state of the system */ 89*be771a7bSCy Schubert static void total_debug_info(void); 90*be771a7bSCy Schubert /** print pretty lock error and exit (decl for NORETURN attribute) */ 91*be771a7bSCy Schubert static void lock_error(struct checked_lock* lock, const char* func, 92*be771a7bSCy Schubert const char* file, int line, const char* err) ATTR_NORETURN; 93*be771a7bSCy Schubert 94*be771a7bSCy Schubert /** print pretty lock error and exit */ 95*be771a7bSCy Schubert static void lock_error(struct checked_lock* lock, 96*be771a7bSCy Schubert const char* func, const char* file, int line, const char* err) 97*be771a7bSCy Schubert { 98*be771a7bSCy Schubert log_err("lock error (description follows)"); 99*be771a7bSCy Schubert log_err("Created at %s %s:%d", lock->create_func, 100*be771a7bSCy Schubert lock->create_file, lock->create_line); 101*be771a7bSCy Schubert if(lock->holder_func && lock->holder_file) 102*be771a7bSCy Schubert log_err("Previously %s %s:%d", lock->holder_func, 103*be771a7bSCy Schubert lock->holder_file, lock->holder_line); 104*be771a7bSCy Schubert log_err("At %s %s:%d", func, file, line); 105*be771a7bSCy Schubert log_err("Error for %s lock: %s", 106*be771a7bSCy Schubert (lock->type==check_lock_mutex)?"mutex": ( 107*be771a7bSCy Schubert (lock->type==check_lock_spinlock)?"spinlock": ( 108*be771a7bSCy Schubert (lock->type==check_lock_rwlock)?"rwlock": "badtype")), err); 109*be771a7bSCy Schubert log_err("complete status display:"); 110*be771a7bSCy Schubert total_debug_info(); 111*be771a7bSCy Schubert fatal_exit("bailing out"); 112*be771a7bSCy Schubert } 113*be771a7bSCy Schubert 114*be771a7bSCy Schubert /** 115*be771a7bSCy Schubert * Obtain lock on debug lock structure. This could be a deadlock by the caller. 116*be771a7bSCy Schubert * The debug code itself does not deadlock. Anyway, check with timeouts. 117*be771a7bSCy Schubert * @param lock: on what to acquire lock. 118*be771a7bSCy Schubert * @param func: user level caller identification. 119*be771a7bSCy Schubert * @param file: user level caller identification. 120*be771a7bSCy Schubert * @param line: user level caller identification. 121*be771a7bSCy Schubert */ 122*be771a7bSCy Schubert static void 123*be771a7bSCy Schubert acquire_locklock(struct checked_lock* lock, 124*be771a7bSCy Schubert const char* func, const char* file, int line) 125*be771a7bSCy Schubert { 126*be771a7bSCy Schubert struct timespec to; 127*be771a7bSCy Schubert int err; 128*be771a7bSCy Schubert int contend = 0; 129*be771a7bSCy Schubert /* first try; inc contention counter if not immediately */ 130*be771a7bSCy Schubert if((err = pthread_mutex_trylock(&lock->lock))) { 131*be771a7bSCy Schubert if(err==EBUSY) 132*be771a7bSCy Schubert contend++; 133*be771a7bSCy Schubert else fatal_exit("error in mutex_trylock: %s", strerror(err)); 134*be771a7bSCy Schubert } 135*be771a7bSCy Schubert if(!err) 136*be771a7bSCy Schubert return; /* immediate success */ 137*be771a7bSCy Schubert to.tv_sec = time(NULL) + CHECK_LOCK_TIMEOUT; 138*be771a7bSCy Schubert to.tv_nsec = 0; 139*be771a7bSCy Schubert err = pthread_mutex_timedlock(&lock->lock, &to); 140*be771a7bSCy Schubert if(err) { 141*be771a7bSCy Schubert log_err("in acquiring locklock: %s", strerror(err)); 142*be771a7bSCy Schubert lock_error(lock, func, file, line, "acquire locklock"); 143*be771a7bSCy Schubert } 144*be771a7bSCy Schubert /* since we hold the lock, we can edit the contention_count */ 145*be771a7bSCy Schubert lock->contention_count += contend; 146*be771a7bSCy Schubert } 147*be771a7bSCy Schubert 148*be771a7bSCy Schubert /** add protected region */ 149*be771a7bSCy Schubert void 150*be771a7bSCy Schubert lock_protect_place(void* p, void* area, size_t size, const char* def_func, 151*be771a7bSCy Schubert const char* def_file, int def_line, const char* def_area) 152*be771a7bSCy Schubert { 153*be771a7bSCy Schubert struct checked_lock* lock = *(struct checked_lock**)p; 154*be771a7bSCy Schubert struct protected_area* e = (struct protected_area*)malloc( 155*be771a7bSCy Schubert sizeof(struct protected_area)); 156*be771a7bSCy Schubert if(!e) 157*be771a7bSCy Schubert fatal_exit("lock_protect: out of memory"); 158*be771a7bSCy Schubert e->region = area; 159*be771a7bSCy Schubert e->size = size; 160*be771a7bSCy Schubert e->def_func = def_func; 161*be771a7bSCy Schubert e->def_file = def_file; 162*be771a7bSCy Schubert e->def_line = def_line; 163*be771a7bSCy Schubert e->def_area = def_area; 164*be771a7bSCy Schubert e->hold = malloc(size); 165*be771a7bSCy Schubert if(!e->hold) 166*be771a7bSCy Schubert fatal_exit("lock_protect: out of memory"); 167*be771a7bSCy Schubert memcpy(e->hold, e->region, e->size); 168*be771a7bSCy Schubert 169*be771a7bSCy Schubert acquire_locklock(lock, __func__, __FILE__, __LINE__); 170*be771a7bSCy Schubert e->next = lock->prot; 171*be771a7bSCy Schubert lock->prot = e; 172*be771a7bSCy Schubert LOCKRET(pthread_mutex_unlock(&lock->lock)); 173*be771a7bSCy Schubert } 174*be771a7bSCy Schubert 175*be771a7bSCy Schubert /** remove protected region */ 176*be771a7bSCy Schubert void 177*be771a7bSCy Schubert lock_unprotect(void* mangled, void* area) 178*be771a7bSCy Schubert { 179*be771a7bSCy Schubert struct checked_lock* lock = *(struct checked_lock**)mangled; 180*be771a7bSCy Schubert struct protected_area* p, **prevp; 181*be771a7bSCy Schubert if(!lock) 182*be771a7bSCy Schubert return; 183*be771a7bSCy Schubert acquire_locklock(lock, __func__, __FILE__, __LINE__); 184*be771a7bSCy Schubert p = lock->prot; 185*be771a7bSCy Schubert prevp = &lock->prot; 186*be771a7bSCy Schubert while(p) { 187*be771a7bSCy Schubert if(p->region == area) { 188*be771a7bSCy Schubert *prevp = p->next; 189*be771a7bSCy Schubert free(p->hold); 190*be771a7bSCy Schubert free(p); 191*be771a7bSCy Schubert LOCKRET(pthread_mutex_unlock(&lock->lock)); 192*be771a7bSCy Schubert return; 193*be771a7bSCy Schubert } 194*be771a7bSCy Schubert prevp = &p->next; 195*be771a7bSCy Schubert p = p->next; 196*be771a7bSCy Schubert } 197*be771a7bSCy Schubert LOCKRET(pthread_mutex_unlock(&lock->lock)); 198*be771a7bSCy Schubert } 199*be771a7bSCy Schubert 200*be771a7bSCy Schubert /** 201*be771a7bSCy Schubert * Check protected memory region. Memory compare. Exit on error. 202*be771a7bSCy Schubert * @param lock: which lock to check. 203*be771a7bSCy Schubert * @param func: location we are now (when failure is detected). 204*be771a7bSCy Schubert * @param file: location we are now (when failure is detected). 205*be771a7bSCy Schubert * @param line: location we are now (when failure is detected). 206*be771a7bSCy Schubert */ 207*be771a7bSCy Schubert static void 208*be771a7bSCy Schubert prot_check(struct checked_lock* lock, 209*be771a7bSCy Schubert const char* func, const char* file, int line) 210*be771a7bSCy Schubert { 211*be771a7bSCy Schubert struct protected_area* p = lock->prot; 212*be771a7bSCy Schubert while(p) { 213*be771a7bSCy Schubert if(memcmp(p->hold, p->region, p->size) != 0) { 214*be771a7bSCy Schubert log_hex("memory prev", p->hold, p->size); 215*be771a7bSCy Schubert log_hex("memory here", p->region, p->size); 216*be771a7bSCy Schubert log_err("lock_protect on %s %s:%d %s failed", 217*be771a7bSCy Schubert p->def_func, p->def_file, p->def_line, 218*be771a7bSCy Schubert p->def_area); 219*be771a7bSCy Schubert lock_error(lock, func, file, line, 220*be771a7bSCy Schubert "protected area modified"); 221*be771a7bSCy Schubert } 222*be771a7bSCy Schubert p = p->next; 223*be771a7bSCy Schubert } 224*be771a7bSCy Schubert } 225*be771a7bSCy Schubert 226*be771a7bSCy Schubert /** Copy protected memory region */ 227*be771a7bSCy Schubert static void 228*be771a7bSCy Schubert prot_store(struct checked_lock* lock) 229*be771a7bSCy Schubert { 230*be771a7bSCy Schubert struct protected_area* p = lock->prot; 231*be771a7bSCy Schubert while(p) { 232*be771a7bSCy Schubert memcpy(p->hold, p->region, p->size); 233*be771a7bSCy Schubert p = p->next; 234*be771a7bSCy Schubert } 235*be771a7bSCy Schubert } 236*be771a7bSCy Schubert 237*be771a7bSCy Schubert /** get memory held by lock */ 238*be771a7bSCy Schubert size_t 239*be771a7bSCy Schubert lock_get_mem(void* pp) 240*be771a7bSCy Schubert { 241*be771a7bSCy Schubert size_t s; 242*be771a7bSCy Schubert struct checked_lock* lock = *(struct checked_lock**)pp; 243*be771a7bSCy Schubert struct protected_area* p; 244*be771a7bSCy Schubert s = sizeof(struct checked_lock); 245*be771a7bSCy Schubert acquire_locklock(lock, __func__, __FILE__, __LINE__); 246*be771a7bSCy Schubert for(p = lock->prot; p; p = p->next) { 247*be771a7bSCy Schubert s += sizeof(struct protected_area); 248*be771a7bSCy Schubert s += p->size; 249*be771a7bSCy Schubert } 250*be771a7bSCy Schubert LOCKRET(pthread_mutex_unlock(&lock->lock)); 251*be771a7bSCy Schubert return s; 252*be771a7bSCy Schubert } 253*be771a7bSCy Schubert 254*be771a7bSCy Schubert /** write lock trace info to file, while you hold those locks */ 255*be771a7bSCy Schubert static void 256*be771a7bSCy Schubert ordercheck_locklock(struct thr_check* thr, struct checked_lock* lock) 257*be771a7bSCy Schubert { 258*be771a7bSCy Schubert int info[4]; 259*be771a7bSCy Schubert if(!check_locking_order) return; 260*be771a7bSCy Schubert if(!thr->holding_first) return; /* no older lock, no info */ 261*be771a7bSCy Schubert /* write: <lock id held> <lock id new> <file> <line> */ 262*be771a7bSCy Schubert info[0] = thr->holding_first->create_thread; 263*be771a7bSCy Schubert info[1] = thr->holding_first->create_instance; 264*be771a7bSCy Schubert info[2] = lock->create_thread; 265*be771a7bSCy Schubert info[3] = lock->create_instance; 266*be771a7bSCy Schubert if(fwrite(info, 4*sizeof(int), 1, thr->order_info) != 1 || 267*be771a7bSCy Schubert fwrite(lock->holder_file, strlen(lock->holder_file)+1, 1, 268*be771a7bSCy Schubert thr->order_info) != 1 || 269*be771a7bSCy Schubert fwrite(&lock->holder_line, sizeof(int), 1, 270*be771a7bSCy Schubert thr->order_info) != 1) 271*be771a7bSCy Schubert log_err("fwrite: %s", strerror(errno)); 272*be771a7bSCy Schubert } 273*be771a7bSCy Schubert 274*be771a7bSCy Schubert /** write ordercheck lock creation details to file */ 275*be771a7bSCy Schubert static void 276*be771a7bSCy Schubert ordercheck_lockcreate(struct thr_check* thr, struct checked_lock* lock) 277*be771a7bSCy Schubert { 278*be771a7bSCy Schubert /* write: <ffff = create> <lock id> <file> <line> */ 279*be771a7bSCy Schubert int cmd = -1; 280*be771a7bSCy Schubert if(!check_locking_order) return; 281*be771a7bSCy Schubert 282*be771a7bSCy Schubert if( fwrite(&cmd, sizeof(int), 1, thr->order_info) != 1 || 283*be771a7bSCy Schubert fwrite(&lock->create_thread, sizeof(int), 1, 284*be771a7bSCy Schubert thr->order_info) != 1 || 285*be771a7bSCy Schubert fwrite(&lock->create_instance, sizeof(int), 1, 286*be771a7bSCy Schubert thr->order_info) != 1 || 287*be771a7bSCy Schubert fwrite(lock->create_file, strlen(lock->create_file)+1, 1, 288*be771a7bSCy Schubert thr->order_info) != 1 || 289*be771a7bSCy Schubert fwrite(&lock->create_line, sizeof(int), 1, 290*be771a7bSCy Schubert thr->order_info) != 1) 291*be771a7bSCy Schubert log_err("fwrite: %s", strerror(errno)); 292*be771a7bSCy Schubert } 293*be771a7bSCy Schubert 294*be771a7bSCy Schubert /** alloc struct, init lock empty */ 295*be771a7bSCy Schubert void 296*be771a7bSCy Schubert checklock_init(enum check_lock_type type, struct checked_lock** lock, 297*be771a7bSCy Schubert const char* func, const char* file, int line) 298*be771a7bSCy Schubert { 299*be771a7bSCy Schubert struct checked_lock* e = (struct checked_lock*)calloc(1, 300*be771a7bSCy Schubert sizeof(struct checked_lock)); 301*be771a7bSCy Schubert struct thr_check *thr = (struct thr_check*)pthread_getspecific( 302*be771a7bSCy Schubert thr_debug_key); 303*be771a7bSCy Schubert if(!e) 304*be771a7bSCy Schubert fatal_exit("%s %s %d: out of memory", func, file, line); 305*be771a7bSCy Schubert if(!thr) { 306*be771a7bSCy Schubert /* this is called when log_init() calls lock_init() 307*be771a7bSCy Schubert * functions, and the test check code has not yet 308*be771a7bSCy Schubert * been initialised. But luckily, the checklock_start() 309*be771a7bSCy Schubert * routine can be called multiple times without ill effect. 310*be771a7bSCy Schubert */ 311*be771a7bSCy Schubert checklock_start(); 312*be771a7bSCy Schubert thr = (struct thr_check*)pthread_getspecific(thr_debug_key); 313*be771a7bSCy Schubert } 314*be771a7bSCy Schubert if(!thr) 315*be771a7bSCy Schubert fatal_exit("%s %s %d: lock_init no thread info", func, file, 316*be771a7bSCy Schubert line); 317*be771a7bSCy Schubert *lock = e; 318*be771a7bSCy Schubert e->type = type; 319*be771a7bSCy Schubert e->create_func = func; 320*be771a7bSCy Schubert e->create_file = file; 321*be771a7bSCy Schubert e->create_line = line; 322*be771a7bSCy Schubert e->create_thread = thr->num; 323*be771a7bSCy Schubert e->create_instance = thr->locks_created++; 324*be771a7bSCy Schubert ordercheck_lockcreate(thr, e); 325*be771a7bSCy Schubert LOCKRET(pthread_mutex_init(&e->lock, NULL)); 326*be771a7bSCy Schubert switch(e->type) { 327*be771a7bSCy Schubert case check_lock_mutex: 328*be771a7bSCy Schubert LOCKRET(pthread_mutex_init(&e->u.mutex, NULL)); 329*be771a7bSCy Schubert break; 330*be771a7bSCy Schubert case check_lock_spinlock: 331*be771a7bSCy Schubert LOCKRET(pthread_spin_init(&e->u.spinlock, PTHREAD_PROCESS_PRIVATE)); 332*be771a7bSCy Schubert break; 333*be771a7bSCy Schubert case check_lock_rwlock: 334*be771a7bSCy Schubert LOCKRET(pthread_rwlock_init(&e->u.rwlock, NULL)); 335*be771a7bSCy Schubert break; 336*be771a7bSCy Schubert default: 337*be771a7bSCy Schubert log_assert(0); 338*be771a7bSCy Schubert } 339*be771a7bSCy Schubert } 340*be771a7bSCy Schubert 341*be771a7bSCy Schubert /** delete prot items */ 342*be771a7bSCy Schubert static void 343*be771a7bSCy Schubert prot_clear(struct checked_lock* lock) 344*be771a7bSCy Schubert { 345*be771a7bSCy Schubert struct protected_area* p=lock->prot, *np; 346*be771a7bSCy Schubert while(p) { 347*be771a7bSCy Schubert np = p->next; 348*be771a7bSCy Schubert free(p->hold); 349*be771a7bSCy Schubert free(p); 350*be771a7bSCy Schubert p = np; 351*be771a7bSCy Schubert } 352*be771a7bSCy Schubert } 353*be771a7bSCy Schubert 354*be771a7bSCy Schubert /** check if type is OK for the lock given */ 355*be771a7bSCy Schubert static void 356*be771a7bSCy Schubert checktype(enum check_lock_type type, struct checked_lock* lock, 357*be771a7bSCy Schubert const char* func, const char* file, int line) 358*be771a7bSCy Schubert { 359*be771a7bSCy Schubert if(!lock) 360*be771a7bSCy Schubert fatal_exit("use of null/deleted lock at %s %s:%d", 361*be771a7bSCy Schubert func, file, line); 362*be771a7bSCy Schubert if(type != lock->type) { 363*be771a7bSCy Schubert lock_error(lock, func, file, line, "wrong lock type"); 364*be771a7bSCy Schubert } 365*be771a7bSCy Schubert } 366*be771a7bSCy Schubert 367*be771a7bSCy Schubert /** check if OK, free struct */ 368*be771a7bSCy Schubert void 369*be771a7bSCy Schubert checklock_destroy(enum check_lock_type type, struct checked_lock** lock, 370*be771a7bSCy Schubert const char* func, const char* file, int line) 371*be771a7bSCy Schubert { 372*be771a7bSCy Schubert const size_t contention_interest = 1; /* promille contented locks */ 373*be771a7bSCy Schubert struct checked_lock* e; 374*be771a7bSCy Schubert if(!lock) 375*be771a7bSCy Schubert return; 376*be771a7bSCy Schubert e = *lock; 377*be771a7bSCy Schubert if(!e) 378*be771a7bSCy Schubert return; 379*be771a7bSCy Schubert checktype(type, e, func, file, line); 380*be771a7bSCy Schubert 381*be771a7bSCy Schubert /* check if delete is OK */ 382*be771a7bSCy Schubert acquire_locklock(e, func, file, line); 383*be771a7bSCy Schubert if(e->hold_count != 0) 384*be771a7bSCy Schubert lock_error(e, func, file, line, "delete while locked."); 385*be771a7bSCy Schubert if(e->wait_count != 0) 386*be771a7bSCy Schubert lock_error(e, func, file, line, "delete while waited on."); 387*be771a7bSCy Schubert prot_check(e, func, file, line); 388*be771a7bSCy Schubert *lock = NULL; /* use after free will fail */ 389*be771a7bSCy Schubert LOCKRET(pthread_mutex_unlock(&e->lock)); 390*be771a7bSCy Schubert 391*be771a7bSCy Schubert /* contention, look at fraction in trouble. */ 392*be771a7bSCy Schubert if(e->history_count > 1 && 393*be771a7bSCy Schubert 1000*e->contention_count/e->history_count > contention_interest) { 394*be771a7bSCy Schubert log_info("lock created %s %s %d has contention %u of %u (%d%%)", 395*be771a7bSCy Schubert e->create_func, e->create_file, e->create_line, 396*be771a7bSCy Schubert (unsigned int)e->contention_count, 397*be771a7bSCy Schubert (unsigned int)e->history_count, 398*be771a7bSCy Schubert (int)(100*e->contention_count/e->history_count)); 399*be771a7bSCy Schubert } 400*be771a7bSCy Schubert 401*be771a7bSCy Schubert /* delete it */ 402*be771a7bSCy Schubert LOCKRET(pthread_mutex_destroy(&e->lock)); 403*be771a7bSCy Schubert prot_clear(e); 404*be771a7bSCy Schubert /* since nobody holds the lock - see check above, no need to unlink 405*be771a7bSCy Schubert * from the thread-held locks list. */ 406*be771a7bSCy Schubert switch(e->type) { 407*be771a7bSCy Schubert case check_lock_mutex: 408*be771a7bSCy Schubert LOCKRET(pthread_mutex_destroy(&e->u.mutex)); 409*be771a7bSCy Schubert break; 410*be771a7bSCy Schubert case check_lock_spinlock: 411*be771a7bSCy Schubert LOCKRET(pthread_spin_destroy(&e->u.spinlock)); 412*be771a7bSCy Schubert break; 413*be771a7bSCy Schubert case check_lock_rwlock: 414*be771a7bSCy Schubert LOCKRET(pthread_rwlock_destroy(&e->u.rwlock)); 415*be771a7bSCy Schubert break; 416*be771a7bSCy Schubert default: 417*be771a7bSCy Schubert log_assert(0); 418*be771a7bSCy Schubert } 419*be771a7bSCy Schubert memset(e, 0, sizeof(struct checked_lock)); 420*be771a7bSCy Schubert free(e); 421*be771a7bSCy Schubert } 422*be771a7bSCy Schubert 423*be771a7bSCy Schubert /** finish acquiring lock, shared between _(rd|wr||)lock() routines */ 424*be771a7bSCy Schubert static void 425*be771a7bSCy Schubert finish_acquire_lock(struct thr_check* thr, struct checked_lock* lock, 426*be771a7bSCy Schubert const char* func, const char* file, int line) 427*be771a7bSCy Schubert { 428*be771a7bSCy Schubert thr->waiting = NULL; 429*be771a7bSCy Schubert lock->wait_count --; 430*be771a7bSCy Schubert lock->holder = thr; 431*be771a7bSCy Schubert lock->hold_count ++; 432*be771a7bSCy Schubert lock->holder_func = func; 433*be771a7bSCy Schubert lock->holder_file = file; 434*be771a7bSCy Schubert lock->holder_line = line; 435*be771a7bSCy Schubert ordercheck_locklock(thr, lock); 436*be771a7bSCy Schubert 437*be771a7bSCy Schubert /* insert in thread lock list, as first */ 438*be771a7bSCy Schubert lock->prev_held_lock[thr->num] = NULL; 439*be771a7bSCy Schubert lock->next_held_lock[thr->num] = thr->holding_first; 440*be771a7bSCy Schubert if(thr->holding_first) 441*be771a7bSCy Schubert /* no need to lock it, since this thread already holds the 442*be771a7bSCy Schubert * lock (since it is on this list) and we only edit thr->num 443*be771a7bSCy Schubert * member in array. So it is safe. */ 444*be771a7bSCy Schubert thr->holding_first->prev_held_lock[thr->num] = lock; 445*be771a7bSCy Schubert else thr->holding_last = lock; 446*be771a7bSCy Schubert thr->holding_first = lock; 447*be771a7bSCy Schubert } 448*be771a7bSCy Schubert 449*be771a7bSCy Schubert /** 450*be771a7bSCy Schubert * Locking routine. 451*be771a7bSCy Schubert * @param type: as passed by user. 452*be771a7bSCy Schubert * @param lock: as passed by user. 453*be771a7bSCy Schubert * @param func: caller location. 454*be771a7bSCy Schubert * @param file: caller location. 455*be771a7bSCy Schubert * @param line: caller location. 456*be771a7bSCy Schubert * @param tryfunc: the pthread_mutex_trylock or similar function. 457*be771a7bSCy Schubert * @param timedfunc: the pthread_mutex_timedlock or similar function. 458*be771a7bSCy Schubert * Uses absolute timeout value. 459*be771a7bSCy Schubert * @param arg: what to pass to tryfunc and timedlock. 460*be771a7bSCy Schubert * @param exclusive: if lock must be exclusive (only one allowed). 461*be771a7bSCy Schubert * @param getwr: if attempts to get writelock (or readlock) for rwlocks. 462*be771a7bSCy Schubert */ 463*be771a7bSCy Schubert static void 464*be771a7bSCy Schubert checklock_lockit(enum check_lock_type type, struct checked_lock* lock, 465*be771a7bSCy Schubert const char* func, const char* file, int line, 466*be771a7bSCy Schubert int (*tryfunc)(void*), int (*timedfunc)(void*, struct timespec*), 467*be771a7bSCy Schubert void* arg, int exclusive, int getwr) 468*be771a7bSCy Schubert { 469*be771a7bSCy Schubert int err; 470*be771a7bSCy Schubert int contend = 0; 471*be771a7bSCy Schubert struct thr_check *thr = (struct thr_check*)pthread_getspecific( 472*be771a7bSCy Schubert thr_debug_key); 473*be771a7bSCy Schubert checktype(type, lock, func, file, line); 474*be771a7bSCy Schubert if(!thr) lock_error(lock, func, file, line, "no thread info"); 475*be771a7bSCy Schubert 476*be771a7bSCy Schubert acquire_locklock(lock, func, file, line); 477*be771a7bSCy Schubert lock->wait_count ++; 478*be771a7bSCy Schubert thr->waiting = lock; 479*be771a7bSCy Schubert if(exclusive && lock->hold_count > 0 && lock->holder == thr) 480*be771a7bSCy Schubert lock_error(lock, func, file, line, "thread already owns lock"); 481*be771a7bSCy Schubert if(type==check_lock_rwlock && getwr && lock->writeholder == thr) 482*be771a7bSCy Schubert lock_error(lock, func, file, line, "thread already has wrlock"); 483*be771a7bSCy Schubert LOCKRET(pthread_mutex_unlock(&lock->lock)); 484*be771a7bSCy Schubert 485*be771a7bSCy Schubert /* first try; if busy increase contention counter */ 486*be771a7bSCy Schubert if((err=tryfunc(arg))) { 487*be771a7bSCy Schubert struct timespec to; 488*be771a7bSCy Schubert if(err != EBUSY) log_err("trylock: %s", strerror(err)); 489*be771a7bSCy Schubert to.tv_sec = time(NULL) + CHECK_LOCK_TIMEOUT; 490*be771a7bSCy Schubert to.tv_nsec = 0; 491*be771a7bSCy Schubert if((err=timedfunc(arg, &to))) { 492*be771a7bSCy Schubert if(err == ETIMEDOUT) 493*be771a7bSCy Schubert lock_error(lock, func, file, line, 494*be771a7bSCy Schubert "timeout possible deadlock"); 495*be771a7bSCy Schubert log_err("timedlock: %s", strerror(err)); 496*be771a7bSCy Schubert } 497*be771a7bSCy Schubert contend ++; 498*be771a7bSCy Schubert } 499*be771a7bSCy Schubert /* got the lock */ 500*be771a7bSCy Schubert 501*be771a7bSCy Schubert acquire_locklock(lock, func, file, line); 502*be771a7bSCy Schubert lock->contention_count += contend; 503*be771a7bSCy Schubert lock->history_count++; 504*be771a7bSCy Schubert if(exclusive && lock->hold_count > 0) 505*be771a7bSCy Schubert lock_error(lock, func, file, line, "got nonexclusive lock"); 506*be771a7bSCy Schubert if(type==check_lock_rwlock && getwr && lock->writeholder) 507*be771a7bSCy Schubert lock_error(lock, func, file, line, "got nonexclusive wrlock"); 508*be771a7bSCy Schubert if(type==check_lock_rwlock && getwr) 509*be771a7bSCy Schubert lock->writeholder = thr; 510*be771a7bSCy Schubert /* check the memory areas for unauthorized changes, 511*be771a7bSCy Schubert * between last unlock time and current lock time. 512*be771a7bSCy Schubert * we check while holding the lock (threadsafe). 513*be771a7bSCy Schubert */ 514*be771a7bSCy Schubert if(getwr || exclusive) 515*be771a7bSCy Schubert prot_check(lock, func, file, line); 516*be771a7bSCy Schubert finish_acquire_lock(thr, lock, func, file, line); 517*be771a7bSCy Schubert LOCKRET(pthread_mutex_unlock(&lock->lock)); 518*be771a7bSCy Schubert } 519*be771a7bSCy Schubert 520*be771a7bSCy Schubert /** helper for rdlock: try */ 521*be771a7bSCy Schubert static int try_rd(void* arg) 522*be771a7bSCy Schubert { return pthread_rwlock_tryrdlock((pthread_rwlock_t*)arg); } 523*be771a7bSCy Schubert /** helper for rdlock: timed */ 524*be771a7bSCy Schubert static int timed_rd(void* arg, struct timespec* to) 525*be771a7bSCy Schubert { return pthread_rwlock_timedrdlock((pthread_rwlock_t*)arg, to); } 526*be771a7bSCy Schubert 527*be771a7bSCy Schubert /** check if OK, lock */ 528*be771a7bSCy Schubert void 529*be771a7bSCy Schubert checklock_rdlock(enum check_lock_type type, struct checked_lock* lock, 530*be771a7bSCy Schubert const char* func, const char* file, int line) 531*be771a7bSCy Schubert { 532*be771a7bSCy Schubert if(key_deleted) 533*be771a7bSCy Schubert return; 534*be771a7bSCy Schubert 535*be771a7bSCy Schubert if(verbose_locking && !(verbose_locking_not_loglock && 536*be771a7bSCy Schubert lock->create_thread == 0 && lock->create_instance == 0)) 537*be771a7bSCy Schubert fprintf(stderr, "checklock_rdlock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line); 538*be771a7bSCy Schubert log_assert(type == check_lock_rwlock); 539*be771a7bSCy Schubert checklock_lockit(type, lock, func, file, line, 540*be771a7bSCy Schubert try_rd, timed_rd, &lock->u.rwlock, 0, 0); 541*be771a7bSCy Schubert } 542*be771a7bSCy Schubert 543*be771a7bSCy Schubert /** helper for wrlock: try */ 544*be771a7bSCy Schubert static int try_wr(void* arg) 545*be771a7bSCy Schubert { return pthread_rwlock_trywrlock((pthread_rwlock_t*)arg); } 546*be771a7bSCy Schubert /** helper for wrlock: timed */ 547*be771a7bSCy Schubert static int timed_wr(void* arg, struct timespec* to) 548*be771a7bSCy Schubert { return pthread_rwlock_timedwrlock((pthread_rwlock_t*)arg, to); } 549*be771a7bSCy Schubert 550*be771a7bSCy Schubert /** check if OK, lock */ 551*be771a7bSCy Schubert void 552*be771a7bSCy Schubert checklock_wrlock(enum check_lock_type type, struct checked_lock* lock, 553*be771a7bSCy Schubert const char* func, const char* file, int line) 554*be771a7bSCy Schubert { 555*be771a7bSCy Schubert if(key_deleted) 556*be771a7bSCy Schubert return; 557*be771a7bSCy Schubert log_assert(type == check_lock_rwlock); 558*be771a7bSCy Schubert if(verbose_locking && !(verbose_locking_not_loglock && 559*be771a7bSCy Schubert lock->create_thread == 0 && lock->create_instance == 0)) 560*be771a7bSCy Schubert fprintf(stderr, "checklock_wrlock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line); 561*be771a7bSCy Schubert checklock_lockit(type, lock, func, file, line, 562*be771a7bSCy Schubert try_wr, timed_wr, &lock->u.rwlock, 0, 1); 563*be771a7bSCy Schubert } 564*be771a7bSCy Schubert 565*be771a7bSCy Schubert /** helper for lock mutex: try */ 566*be771a7bSCy Schubert static int try_mutex(void* arg) 567*be771a7bSCy Schubert { return pthread_mutex_trylock((pthread_mutex_t*)arg); } 568*be771a7bSCy Schubert /** helper for lock mutex: timed */ 569*be771a7bSCy Schubert static int timed_mutex(void* arg, struct timespec* to) 570*be771a7bSCy Schubert { return pthread_mutex_timedlock((pthread_mutex_t*)arg, to); } 571*be771a7bSCy Schubert 572*be771a7bSCy Schubert /** helper for lock spinlock: try */ 573*be771a7bSCy Schubert static int try_spinlock(void* arg) 574*be771a7bSCy Schubert { return pthread_spin_trylock((pthread_spinlock_t*)arg); } 575*be771a7bSCy Schubert /** helper for lock spinlock: timed */ 576*be771a7bSCy Schubert static int timed_spinlock(void* arg, struct timespec* to) 577*be771a7bSCy Schubert { 578*be771a7bSCy Schubert int err; 579*be771a7bSCy Schubert /* spin for 5 seconds. (ouch for the CPU, but it beats forever) */ 580*be771a7bSCy Schubert while( (err=try_spinlock(arg)) == EBUSY) { 581*be771a7bSCy Schubert #ifndef S_SPLINT_S 582*be771a7bSCy Schubert if(time(NULL) >= to->tv_sec) 583*be771a7bSCy Schubert return ETIMEDOUT; 584*be771a7bSCy Schubert usleep(1000); /* in 1/1000000s of a second */ 585*be771a7bSCy Schubert #endif 586*be771a7bSCy Schubert } 587*be771a7bSCy Schubert return err; 588*be771a7bSCy Schubert } 589*be771a7bSCy Schubert 590*be771a7bSCy Schubert /** check if OK, lock */ 591*be771a7bSCy Schubert void 592*be771a7bSCy Schubert checklock_lock(enum check_lock_type type, struct checked_lock* lock, 593*be771a7bSCy Schubert const char* func, const char* file, int line) 594*be771a7bSCy Schubert { 595*be771a7bSCy Schubert if(key_deleted) 596*be771a7bSCy Schubert return; 597*be771a7bSCy Schubert log_assert(type != check_lock_rwlock); 598*be771a7bSCy Schubert if(verbose_locking && !(verbose_locking_not_loglock && 599*be771a7bSCy Schubert lock->create_thread == 0 && lock->create_instance == 0)) 600*be771a7bSCy Schubert fprintf(stderr, "checklock_lock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line); 601*be771a7bSCy Schubert switch(type) { 602*be771a7bSCy Schubert case check_lock_mutex: 603*be771a7bSCy Schubert checklock_lockit(type, lock, func, file, line, 604*be771a7bSCy Schubert try_mutex, timed_mutex, &lock->u.mutex, 1, 0); 605*be771a7bSCy Schubert break; 606*be771a7bSCy Schubert case check_lock_spinlock: 607*be771a7bSCy Schubert /* void* cast needed because 'volatile' on some OS */ 608*be771a7bSCy Schubert checklock_lockit(type, lock, func, file, line, 609*be771a7bSCy Schubert try_spinlock, timed_spinlock, 610*be771a7bSCy Schubert (void*)&lock->u.spinlock, 1, 0); 611*be771a7bSCy Schubert break; 612*be771a7bSCy Schubert default: 613*be771a7bSCy Schubert log_assert(0); 614*be771a7bSCy Schubert } 615*be771a7bSCy Schubert } 616*be771a7bSCy Schubert 617*be771a7bSCy Schubert /** check if OK, unlock */ 618*be771a7bSCy Schubert void 619*be771a7bSCy Schubert checklock_unlock(enum check_lock_type type, struct checked_lock* lock, 620*be771a7bSCy Schubert const char* func, const char* file, int line) 621*be771a7bSCy Schubert { 622*be771a7bSCy Schubert struct thr_check *thr; 623*be771a7bSCy Schubert if(key_deleted) 624*be771a7bSCy Schubert return; 625*be771a7bSCy Schubert thr = (struct thr_check*)pthread_getspecific(thr_debug_key); 626*be771a7bSCy Schubert checktype(type, lock, func, file, line); 627*be771a7bSCy Schubert if(!thr) lock_error(lock, func, file, line, "no thread info"); 628*be771a7bSCy Schubert 629*be771a7bSCy Schubert acquire_locklock(lock, func, file, line); 630*be771a7bSCy Schubert /* was this thread even holding this lock? */ 631*be771a7bSCy Schubert if(thr->holding_first != lock && 632*be771a7bSCy Schubert lock->prev_held_lock[thr->num] == NULL) { 633*be771a7bSCy Schubert lock_error(lock, func, file, line, "unlock nonlocked lock"); 634*be771a7bSCy Schubert } 635*be771a7bSCy Schubert if(lock->hold_count <= 0) 636*be771a7bSCy Schubert lock_error(lock, func, file, line, "too many unlocks"); 637*be771a7bSCy Schubert 638*be771a7bSCy Schubert if(verbose_locking && !(verbose_locking_not_loglock && 639*be771a7bSCy Schubert lock->create_thread == 0 && lock->create_instance == 0)) 640*be771a7bSCy Schubert fprintf(stderr, "checklock_unlock lock %d %d %s:%d at %s:%d\n", lock->create_thread, lock->create_instance, lock->create_file, lock->create_line, file, line); 641*be771a7bSCy Schubert 642*be771a7bSCy Schubert /* store this point as last touched by */ 643*be771a7bSCy Schubert lock->holder = thr; 644*be771a7bSCy Schubert lock->hold_count --; 645*be771a7bSCy Schubert lock->holder_func = func; 646*be771a7bSCy Schubert lock->holder_file = file; 647*be771a7bSCy Schubert lock->holder_line = line; 648*be771a7bSCy Schubert 649*be771a7bSCy Schubert /* delete from thread holder list */ 650*be771a7bSCy Schubert /* no need to lock other lockstructs, because they are all on the 651*be771a7bSCy Schubert * held-locks list, and this thread holds their locks. 652*be771a7bSCy Schubert * we only touch the thr->num members, so it is safe. */ 653*be771a7bSCy Schubert if(thr->holding_first == lock) 654*be771a7bSCy Schubert thr->holding_first = lock->next_held_lock[thr->num]; 655*be771a7bSCy Schubert if(thr->holding_last == lock) 656*be771a7bSCy Schubert thr->holding_last = lock->prev_held_lock[thr->num]; 657*be771a7bSCy Schubert if(lock->next_held_lock[thr->num]) 658*be771a7bSCy Schubert lock->next_held_lock[thr->num]->prev_held_lock[thr->num] = 659*be771a7bSCy Schubert lock->prev_held_lock[thr->num]; 660*be771a7bSCy Schubert if(lock->prev_held_lock[thr->num]) 661*be771a7bSCy Schubert lock->prev_held_lock[thr->num]->next_held_lock[thr->num] = 662*be771a7bSCy Schubert lock->next_held_lock[thr->num]; 663*be771a7bSCy Schubert lock->next_held_lock[thr->num] = NULL; 664*be771a7bSCy Schubert lock->prev_held_lock[thr->num] = NULL; 665*be771a7bSCy Schubert 666*be771a7bSCy Schubert if(type==check_lock_rwlock && lock->writeholder == thr) { 667*be771a7bSCy Schubert lock->writeholder = NULL; 668*be771a7bSCy Schubert prot_store(lock); 669*be771a7bSCy Schubert } else if(type != check_lock_rwlock) { 670*be771a7bSCy Schubert /* store memory areas that are protected, for later checks */ 671*be771a7bSCy Schubert prot_store(lock); 672*be771a7bSCy Schubert } 673*be771a7bSCy Schubert LOCKRET(pthread_mutex_unlock(&lock->lock)); 674*be771a7bSCy Schubert 675*be771a7bSCy Schubert /* unlock it */ 676*be771a7bSCy Schubert switch(type) { 677*be771a7bSCy Schubert case check_lock_mutex: 678*be771a7bSCy Schubert LOCKRET(pthread_mutex_unlock(&lock->u.mutex)); 679*be771a7bSCy Schubert break; 680*be771a7bSCy Schubert case check_lock_spinlock: 681*be771a7bSCy Schubert LOCKRET(pthread_spin_unlock(&lock->u.spinlock)); 682*be771a7bSCy Schubert break; 683*be771a7bSCy Schubert case check_lock_rwlock: 684*be771a7bSCy Schubert LOCKRET(pthread_rwlock_unlock(&lock->u.rwlock)); 685*be771a7bSCy Schubert break; 686*be771a7bSCy Schubert default: 687*be771a7bSCy Schubert log_assert(0); 688*be771a7bSCy Schubert } 689*be771a7bSCy Schubert } 690*be771a7bSCy Schubert 691*be771a7bSCy Schubert void 692*be771a7bSCy Schubert checklock_set_output_name(const char* name) 693*be771a7bSCy Schubert { 694*be771a7bSCy Schubert output_name = name; 695*be771a7bSCy Schubert } 696*be771a7bSCy Schubert 697*be771a7bSCy Schubert /** open order info debug file, thr->num must be valid */ 698*be771a7bSCy Schubert static void 699*be771a7bSCy Schubert open_lockorder(struct thr_check* thr) 700*be771a7bSCy Schubert { 701*be771a7bSCy Schubert char buf[24]; 702*be771a7bSCy Schubert time_t t; 703*be771a7bSCy Schubert snprintf(buf, sizeof(buf), "%s.%d", output_name, thr->num); 704*be771a7bSCy Schubert thr->locks_created = thread_lockcount[thr->num]; 705*be771a7bSCy Schubert if(thr->locks_created == 0) { 706*be771a7bSCy Schubert thr->order_info = fopen(buf, "w"); 707*be771a7bSCy Schubert if(!thr->order_info) 708*be771a7bSCy Schubert fatal_exit("could not open %s: %s", buf, strerror(errno)); 709*be771a7bSCy Schubert } else { 710*be771a7bSCy Schubert /* There is already a file to append on with the previous 711*be771a7bSCy Schubert * thread information. */ 712*be771a7bSCy Schubert thr->order_info = fopen(buf, "a"); 713*be771a7bSCy Schubert if(!thr->order_info) 714*be771a7bSCy Schubert fatal_exit("could not open for append %s: %s", buf, strerror(errno)); 715*be771a7bSCy Schubert return; 716*be771a7bSCy Schubert } 717*be771a7bSCy Schubert 718*be771a7bSCy Schubert t = time(NULL); 719*be771a7bSCy Schubert /* write: <time_stamp> <runpid> <thread_num> */ 720*be771a7bSCy Schubert if(fwrite(&t, sizeof(t), 1, thr->order_info) != 1 || 721*be771a7bSCy Schubert fwrite(&thr->num, sizeof(thr->num), 1, thr->order_info) != 1 || 722*be771a7bSCy Schubert fwrite(&check_lock_pid, sizeof(check_lock_pid), 1, 723*be771a7bSCy Schubert thr->order_info) != 1) 724*be771a7bSCy Schubert log_err("fwrite: %s", strerror(errno)); 725*be771a7bSCy Schubert } 726*be771a7bSCy Schubert 727*be771a7bSCy Schubert /** checklock thread main, Inits thread structure */ 728*be771a7bSCy Schubert static void* checklock_main(void* arg) 729*be771a7bSCy Schubert { 730*be771a7bSCy Schubert struct thr_check* thr = (struct thr_check*)arg; 731*be771a7bSCy Schubert void* ret; 732*be771a7bSCy Schubert thr->id = pthread_self(); 733*be771a7bSCy Schubert /* Hack to get same numbers as in log file */ 734*be771a7bSCy Schubert thr->num = *(int*)(thr->arg); 735*be771a7bSCy Schubert log_assert(thr->num < THRDEBUG_MAX_THREADS); 736*be771a7bSCy Schubert /* as an aside, due to this, won't work for libunbound bg thread */ 737*be771a7bSCy Schubert if(thread_infos[thr->num] != NULL) 738*be771a7bSCy Schubert log_warn("thread warning, thr->num %d not NULL", thr->num); 739*be771a7bSCy Schubert thread_infos[thr->num] = thr; 740*be771a7bSCy Schubert LOCKRET(pthread_setspecific(thr_debug_key, thr)); 741*be771a7bSCy Schubert if(check_locking_order) 742*be771a7bSCy Schubert open_lockorder(thr); 743*be771a7bSCy Schubert ret = thr->func(thr->arg); 744*be771a7bSCy Schubert thread_lockcount[thr->num] = thr->locks_created; 745*be771a7bSCy Schubert thread_infos[thr->num] = NULL; 746*be771a7bSCy Schubert if(check_locking_order) 747*be771a7bSCy Schubert fclose(thr->order_info); 748*be771a7bSCy Schubert free(thr); 749*be771a7bSCy Schubert return ret; 750*be771a7bSCy Schubert } 751*be771a7bSCy Schubert 752*be771a7bSCy Schubert /** init the main thread */ 753*be771a7bSCy Schubert void checklock_start(void) 754*be771a7bSCy Schubert { 755*be771a7bSCy Schubert if(key_deleted) 756*be771a7bSCy Schubert return; 757*be771a7bSCy Schubert if(!key_created) { 758*be771a7bSCy Schubert struct thr_check* thisthr = (struct thr_check*)calloc(1, 759*be771a7bSCy Schubert sizeof(struct thr_check)); 760*be771a7bSCy Schubert if(!thisthr) 761*be771a7bSCy Schubert fatal_exit("thrcreate: out of memory"); 762*be771a7bSCy Schubert key_created = 1; 763*be771a7bSCy Schubert check_lock_pid = getpid(); 764*be771a7bSCy Schubert LOCKRET(pthread_key_create(&thr_debug_key, NULL)); 765*be771a7bSCy Schubert LOCKRET(pthread_setspecific(thr_debug_key, thisthr)); 766*be771a7bSCy Schubert thread_infos[0] = thisthr; 767*be771a7bSCy Schubert if(check_locking_order) 768*be771a7bSCy Schubert open_lockorder(thisthr); 769*be771a7bSCy Schubert } 770*be771a7bSCy Schubert } 771*be771a7bSCy Schubert 772*be771a7bSCy Schubert /** stop checklocks */ 773*be771a7bSCy Schubert void checklock_stop(void) 774*be771a7bSCy Schubert { 775*be771a7bSCy Schubert if(key_created) { 776*be771a7bSCy Schubert int i; 777*be771a7bSCy Schubert key_deleted = 1; 778*be771a7bSCy Schubert if(check_locking_order) 779*be771a7bSCy Schubert fclose(thread_infos[0]->order_info); 780*be771a7bSCy Schubert free(thread_infos[0]); 781*be771a7bSCy Schubert thread_infos[0] = NULL; 782*be771a7bSCy Schubert for(i = 0; i < THRDEBUG_MAX_THREADS; i++) 783*be771a7bSCy Schubert log_assert(thread_infos[i] == NULL); 784*be771a7bSCy Schubert /* should have been cleaned up. */ 785*be771a7bSCy Schubert LOCKRET(pthread_key_delete(thr_debug_key)); 786*be771a7bSCy Schubert key_created = 0; 787*be771a7bSCy Schubert } 788*be771a7bSCy Schubert } 789*be771a7bSCy Schubert 790*be771a7bSCy Schubert /** allocate debug info and create thread */ 791*be771a7bSCy Schubert void 792*be771a7bSCy Schubert checklock_thrcreate(pthread_t* id, void* (*func)(void*), void* arg) 793*be771a7bSCy Schubert { 794*be771a7bSCy Schubert struct thr_check* thr = (struct thr_check*)calloc(1, 795*be771a7bSCy Schubert sizeof(struct thr_check)); 796*be771a7bSCy Schubert if(!thr) 797*be771a7bSCy Schubert fatal_exit("thrcreate: out of memory"); 798*be771a7bSCy Schubert if(!key_created) { 799*be771a7bSCy Schubert checklock_start(); 800*be771a7bSCy Schubert } 801*be771a7bSCy Schubert thr->func = func; 802*be771a7bSCy Schubert thr->arg = arg; 803*be771a7bSCy Schubert LOCKRET(pthread_create(id, NULL, checklock_main, thr)); 804*be771a7bSCy Schubert } 805*be771a7bSCy Schubert 806*be771a7bSCy Schubert /** count number of thread infos */ 807*be771a7bSCy Schubert static int 808*be771a7bSCy Schubert count_thread_infos(void) 809*be771a7bSCy Schubert { 810*be771a7bSCy Schubert int cnt = 0; 811*be771a7bSCy Schubert int i; 812*be771a7bSCy Schubert for(i=0; i<THRDEBUG_MAX_THREADS; i++) 813*be771a7bSCy Schubert if(thread_infos[i]) 814*be771a7bSCy Schubert cnt++; 815*be771a7bSCy Schubert return cnt; 816*be771a7bSCy Schubert } 817*be771a7bSCy Schubert 818*be771a7bSCy Schubert /** print lots of info on a lock */ 819*be771a7bSCy Schubert static void 820*be771a7bSCy Schubert lock_debug_info(struct checked_lock* lock) 821*be771a7bSCy Schubert { 822*be771a7bSCy Schubert if(!lock) return; 823*be771a7bSCy Schubert log_info("+++ Lock %llx, %d %d create %s %s %d", 824*be771a7bSCy Schubert (unsigned long long)(size_t)lock, 825*be771a7bSCy Schubert lock->create_thread, lock->create_instance, 826*be771a7bSCy Schubert lock->create_func, lock->create_file, lock->create_line); 827*be771a7bSCy Schubert log_info("lock type: %s", 828*be771a7bSCy Schubert (lock->type==check_lock_mutex)?"mutex": ( 829*be771a7bSCy Schubert (lock->type==check_lock_spinlock)?"spinlock": ( 830*be771a7bSCy Schubert (lock->type==check_lock_rwlock)?"rwlock": "badtype"))); 831*be771a7bSCy Schubert log_info("lock contention %u, history:%u, hold:%d, wait:%d", 832*be771a7bSCy Schubert (unsigned)lock->contention_count, (unsigned)lock->history_count, 833*be771a7bSCy Schubert lock->hold_count, lock->wait_count); 834*be771a7bSCy Schubert log_info("last touch %s %s %d", lock->holder_func, lock->holder_file, 835*be771a7bSCy Schubert lock->holder_line); 836*be771a7bSCy Schubert log_info("holder thread %d, writeholder thread %d", 837*be771a7bSCy Schubert lock->holder?lock->holder->num:-1, 838*be771a7bSCy Schubert lock->writeholder?lock->writeholder->num:-1); 839*be771a7bSCy Schubert } 840*be771a7bSCy Schubert 841*be771a7bSCy Schubert /** print debug locks held by a thread */ 842*be771a7bSCy Schubert static void 843*be771a7bSCy Schubert held_debug_info(struct thr_check* thr, struct checked_lock* lock) 844*be771a7bSCy Schubert { 845*be771a7bSCy Schubert if(!lock) return; 846*be771a7bSCy Schubert lock_debug_info(lock); 847*be771a7bSCy Schubert held_debug_info(thr, lock->next_held_lock[thr->num]); 848*be771a7bSCy Schubert } 849*be771a7bSCy Schubert 850*be771a7bSCy Schubert /** print debug info for a thread */ 851*be771a7bSCy Schubert static void 852*be771a7bSCy Schubert thread_debug_info(struct thr_check* thr) 853*be771a7bSCy Schubert { 854*be771a7bSCy Schubert struct checked_lock* w = NULL; 855*be771a7bSCy Schubert struct checked_lock* f = NULL; 856*be771a7bSCy Schubert struct checked_lock* l = NULL; 857*be771a7bSCy Schubert if(!thr) return; 858*be771a7bSCy Schubert log_info("pthread id is %x", (int)thr->id); 859*be771a7bSCy Schubert log_info("thread func is %llx", (unsigned long long)(size_t)thr->func); 860*be771a7bSCy Schubert log_info("thread arg is %llx (%d)", 861*be771a7bSCy Schubert (unsigned long long)(size_t)thr->arg, 862*be771a7bSCy Schubert (thr->arg?*(int*)thr->arg:0)); 863*be771a7bSCy Schubert log_info("thread num is %d", thr->num); 864*be771a7bSCy Schubert log_info("locks created %d", thr->locks_created); 865*be771a7bSCy Schubert log_info("open file for lockinfo: %s", 866*be771a7bSCy Schubert thr->order_info?"yes, flushing":"no"); 867*be771a7bSCy Schubert fflush(thr->order_info); 868*be771a7bSCy Schubert w = thr->waiting; 869*be771a7bSCy Schubert f = thr->holding_first; 870*be771a7bSCy Schubert l = thr->holding_last; 871*be771a7bSCy Schubert log_info("thread waiting for a lock: %s %llx", w?"yes":"no", 872*be771a7bSCy Schubert (unsigned long long)(size_t)w); 873*be771a7bSCy Schubert lock_debug_info(w); 874*be771a7bSCy Schubert log_info("thread holding first: %s, last: %s", f?"yes":"no", 875*be771a7bSCy Schubert l?"yes":"no"); 876*be771a7bSCy Schubert held_debug_info(thr, f); 877*be771a7bSCy Schubert } 878*be771a7bSCy Schubert 879*be771a7bSCy Schubert static void 880*be771a7bSCy Schubert total_debug_info(void) 881*be771a7bSCy Schubert { 882*be771a7bSCy Schubert int i; 883*be771a7bSCy Schubert log_info("checklocks: supervising %d threads.", 884*be771a7bSCy Schubert count_thread_infos()); 885*be771a7bSCy Schubert if(!key_created) { 886*be771a7bSCy Schubert log_info("No thread debug key created yet"); 887*be771a7bSCy Schubert } 888*be771a7bSCy Schubert for(i=0; i<THRDEBUG_MAX_THREADS; i++) { 889*be771a7bSCy Schubert if(thread_infos[i]) { 890*be771a7bSCy Schubert log_info("*** Thread %d information: ***", i); 891*be771a7bSCy Schubert thread_debug_info(thread_infos[i]); 892*be771a7bSCy Schubert } 893*be771a7bSCy Schubert } 894*be771a7bSCy Schubert } 895*be771a7bSCy Schubert 896*be771a7bSCy Schubert /** signal handler for join timeout, Exits */ 897*be771a7bSCy Schubert static RETSIGTYPE joinalarm(int ATTR_UNUSED(sig)) 898*be771a7bSCy Schubert { 899*be771a7bSCy Schubert log_err("join thread timeout. hangup or deadlock. Info follows."); 900*be771a7bSCy Schubert total_debug_info(); 901*be771a7bSCy Schubert fatal_exit("join thread timeout. hangup or deadlock."); 902*be771a7bSCy Schubert } 903*be771a7bSCy Schubert 904*be771a7bSCy Schubert /** wait for thread with a timeout */ 905*be771a7bSCy Schubert void 906*be771a7bSCy Schubert checklock_thrjoin(pthread_t thread) 907*be771a7bSCy Schubert { 908*be771a7bSCy Schubert /* wait with a timeout */ 909*be771a7bSCy Schubert if(signal(SIGALRM, joinalarm) == SIG_ERR) 910*be771a7bSCy Schubert fatal_exit("signal(): %s", strerror(errno)); 911*be771a7bSCy Schubert (void)alarm(CHECK_JOIN_TIMEOUT); 912*be771a7bSCy Schubert LOCKRET(pthread_join(thread, NULL)); 913*be771a7bSCy Schubert (void)alarm(0); 914*be771a7bSCy Schubert } 915*be771a7bSCy Schubert 916*be771a7bSCy Schubert #endif /* USE_THREAD_DEBUG */ 917