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