2 * testcode/checklocks.c - wrapper on locks that checks access.
4 * Copyright (c) 2007, NLnet Labs. All rights reserved.
6 * This software is open source.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
12 * Redistributions of source code must retain the above copyright notice,
13 * this list of conditions and the following disclaimer.
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.
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.
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.
38 #include "util/locks.h" /* include before checklocks.h */
39 #include "testcode/checklocks.h"
43 * Locks that are checked.
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.
50 * - debug status print, of thread lock stacks, and current waiting.
52 #ifdef USE_THREAD_DEBUG
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 */
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_t 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 /** do we check locking order */
68 int check_locking_order
= 1;
69 /** the pid of this runset, reasonably unique. */
70 static pid_t check_lock_pid
;
72 /** print all possible debug info on the state of the system */
73 static void total_debug_info(void);
75 /** print pretty lock error and exit */
76 static void lock_error(struct checked_lock
* lock
,
77 const char* func
, const char* file
, int line
, const char* err
)
79 log_err("lock error (description follows)");
80 log_err("Created at %s %s:%d", lock
->create_func
,
81 lock
->create_file
, lock
->create_line
);
82 if(lock
->holder_func
&& lock
->holder_file
)
83 log_err("Previously %s %s:%d", lock
->holder_func
,
84 lock
->holder_file
, lock
->holder_line
);
85 log_err("At %s %s:%d", func
, file
, line
);
86 log_err("Error for %s lock: %s",
87 (lock
->type
==check_lock_mutex
)?"mutex": (
88 (lock
->type
==check_lock_spinlock
)?"spinlock": (
89 (lock
->type
==check_lock_rwlock
)?"rwlock": "badtype")), err
);
90 log_err("complete status display:");
92 fatal_exit("bailing out");
96 * Obtain lock on debug lock structure. This could be a deadlock by the caller.
97 * The debug code itself does not deadlock. Anyway, check with timeouts.
98 * @param lock: on what to acquire lock.
99 * @param func: user level caller identification.
100 * @param file: user level caller identification.
101 * @param line: user level caller identification.
104 acquire_locklock(struct checked_lock
* lock
,
105 const char* func
, const char* file
, int line
)
110 /* first try; inc contention counter if not immediately */
111 if((err
= pthread_mutex_trylock(&lock
->lock
))) {
114 else fatal_exit("error in mutex_trylock: %s", strerror(err
));
117 return; /* immediate success */
118 to
.tv_sec
= time(NULL
) + CHECK_LOCK_TIMEOUT
;
120 err
= pthread_mutex_timedlock(&lock
->lock
, &to
);
122 log_err("in acquiring locklock: %s", strerror(err
));
123 lock_error(lock
, func
, file
, line
, "acquire locklock");
125 /* since we hold the lock, we can edit the contention_count */
126 lock
->contention_count
+= contend
;
129 /** add protected region */
131 lock_protect(void *p
, void* area
, size_t size
)
133 struct checked_lock
* lock
= *(struct checked_lock
**)p
;
134 struct protected_area
* e
= (struct protected_area
*)malloc(
135 sizeof(struct protected_area
));
137 fatal_exit("lock_protect: out of memory");
140 e
->hold
= malloc(size
);
142 fatal_exit("lock_protect: out of memory");
143 memcpy(e
->hold
, e
->region
, e
->size
);
145 acquire_locklock(lock
, __func__
, __FILE__
, __LINE__
);
146 e
->next
= lock
->prot
;
148 LOCKRET(pthread_mutex_unlock(&lock
->lock
));
151 /** remove protected region */
153 lock_unprotect(void* mangled
, void* area
)
155 struct checked_lock
* lock
= *(struct checked_lock
**)mangled
;
156 struct protected_area
* p
, **prevp
;
159 acquire_locklock(lock
, __func__
, __FILE__
, __LINE__
);
163 if(p
->region
== area
) {
167 LOCKRET(pthread_mutex_unlock(&lock
->lock
));
173 LOCKRET(pthread_mutex_unlock(&lock
->lock
));
177 * Check protected memory region. Memory compare. Exit on error.
178 * @param lock: which lock to check.
179 * @param func: location we are now (when failure is detected).
180 * @param file: location we are now (when failure is detected).
181 * @param line: location we are now (when failure is detected).
184 prot_check(struct checked_lock
* lock
,
185 const char* func
, const char* file
, int line
)
187 struct protected_area
* p
= lock
->prot
;
189 if(memcmp(p
->hold
, p
->region
, p
->size
) != 0) {
190 log_hex("memory prev", p
->hold
, p
->size
);
191 log_hex("memory here", p
->region
, p
->size
);
192 lock_error(lock
, func
, file
, line
,
193 "protected area modified");
199 /** Copy protected memory region */
201 prot_store(struct checked_lock
* lock
)
203 struct protected_area
* p
= lock
->prot
;
205 memcpy(p
->hold
, p
->region
, p
->size
);
210 /** get memory held by lock */
212 lock_get_mem(void* pp
)
215 struct checked_lock
* lock
= *(struct checked_lock
**)pp
;
216 struct protected_area
* p
;
217 s
= sizeof(struct checked_lock
);
218 acquire_locklock(lock
, __func__
, __FILE__
, __LINE__
);
219 for(p
= lock
->prot
; p
; p
= p
->next
) {
220 s
+= sizeof(struct protected_area
);
223 LOCKRET(pthread_mutex_unlock(&lock
->lock
));
227 /** write lock trace info to file, while you hold those locks */
229 ordercheck_locklock(struct thr_check
* thr
, struct checked_lock
* lock
)
232 if(!check_locking_order
) return;
233 if(!thr
->holding_first
) return; /* no older lock, no info */
234 /* write: <lock id held> <lock id new> <file> <line> */
235 info
[0] = thr
->holding_first
->create_thread
;
236 info
[1] = thr
->holding_first
->create_instance
;
237 info
[2] = lock
->create_thread
;
238 info
[3] = lock
->create_instance
;
239 if(fwrite(info
, 4*sizeof(int), 1, thr
->order_info
) != 1 ||
240 fwrite(lock
->holder_file
, strlen(lock
->holder_file
)+1, 1,
241 thr
->order_info
) != 1 ||
242 fwrite(&lock
->holder_line
, sizeof(int), 1,
243 thr
->order_info
) != 1)
244 log_err("fwrite: %s", strerror(errno
));
247 /** write ordercheck lock creation details to file */
249 ordercheck_lockcreate(struct thr_check
* thr
, struct checked_lock
* lock
)
251 /* write: <ffff = create> <lock id> <file> <line> */
253 if(!check_locking_order
) return;
255 if( fwrite(&cmd
, sizeof(int), 1, thr
->order_info
) != 1 ||
256 fwrite(&lock
->create_thread
, sizeof(int), 1,
257 thr
->order_info
) != 1 ||
258 fwrite(&lock
->create_instance
, sizeof(int), 1,
259 thr
->order_info
) != 1 ||
260 fwrite(lock
->create_file
, strlen(lock
->create_file
)+1, 1,
261 thr
->order_info
) != 1 ||
262 fwrite(&lock
->create_line
, sizeof(int), 1,
263 thr
->order_info
) != 1)
264 log_err("fwrite: %s", strerror(errno
));
267 /** alloc struct, init lock empty */
269 checklock_init(enum check_lock_type type
, struct checked_lock
** lock
,
270 const char* func
, const char* file
, int line
)
272 struct checked_lock
* e
= (struct checked_lock
*)calloc(1,
273 sizeof(struct checked_lock
));
274 struct thr_check
*thr
= (struct thr_check
*)pthread_getspecific(
277 fatal_exit("%s %s %d: out of memory", func
, file
, line
);
279 /* this is called when log_init() calls lock_init()
280 * functions, and the test check code has not yet
281 * been initialised. But luckily, the checklock_start()
282 * routine can be called multiple times without ill effect.
285 thr
= (struct thr_check
*)pthread_getspecific(thr_debug_key
);
288 fatal_exit("%s %s %d: lock_init no thread info", func
, file
,
292 e
->create_func
= func
;
293 e
->create_file
= file
;
294 e
->create_line
= line
;
295 e
->create_thread
= thr
->num
;
296 e
->create_instance
= thr
->locks_created
++;
297 ordercheck_lockcreate(thr
, e
);
298 LOCKRET(pthread_mutex_init(&e
->lock
, NULL
));
300 case check_lock_mutex
:
301 LOCKRET(pthread_mutex_init(&e
->u
.mutex
, NULL
));
303 case check_lock_spinlock
:
304 LOCKRET(pthread_spin_init(&e
->u
.spinlock
, PTHREAD_PROCESS_PRIVATE
));
306 case check_lock_rwlock
:
307 LOCKRET(pthread_rwlock_init(&e
->u
.rwlock
, NULL
));
314 /** delete prot items */
316 prot_clear(struct checked_lock
* lock
)
318 struct protected_area
* p
=lock
->prot
, *np
;
327 /** check if type is OK for the lock given */
329 checktype(enum check_lock_type type
, struct checked_lock
* lock
,
330 const char* func
, const char* file
, int line
)
333 fatal_exit("use of null/deleted lock at %s %s:%d",
335 if(type
!= lock
->type
) {
336 lock_error(lock
, func
, file
, line
, "wrong lock type");
340 /** check if OK, free struct */
342 checklock_destroy(enum check_lock_type type
, struct checked_lock
** lock
,
343 const char* func
, const char* file
, int line
)
345 const size_t contention_interest
= 1; /* promille contented locks */
346 struct checked_lock
* e
;
352 checktype(type
, e
, func
, file
, line
);
354 /* check if delete is OK */
355 acquire_locklock(e
, func
, file
, line
);
356 if(e
->hold_count
!= 0)
357 lock_error(e
, func
, file
, line
, "delete while locked.");
358 if(e
->wait_count
!= 0)
359 lock_error(e
, func
, file
, line
, "delete while waited on.");
360 prot_check(e
, func
, file
, line
);
361 *lock
= NULL
; /* use after free will fail */
362 LOCKRET(pthread_mutex_unlock(&e
->lock
));
364 /* contention, look at fraction in trouble. */
365 if(e
->history_count
> 1 &&
366 1000*e
->contention_count
/e
->history_count
> contention_interest
) {
367 log_info("lock created %s %s %d has contention %u of %u (%d%%)",
368 e
->create_func
, e
->create_file
, e
->create_line
,
369 (unsigned int)e
->contention_count
,
370 (unsigned int)e
->history_count
,
371 (int)(100*e
->contention_count
/e
->history_count
));
375 LOCKRET(pthread_mutex_destroy(&e
->lock
));
377 /* since nobody holds the lock - see check above, no need to unlink
378 * from the thread-held locks list. */
380 case check_lock_mutex
:
381 LOCKRET(pthread_mutex_destroy(&e
->u
.mutex
));
383 case check_lock_spinlock
:
384 LOCKRET(pthread_spin_destroy(&e
->u
.spinlock
));
386 case check_lock_rwlock
:
387 LOCKRET(pthread_rwlock_destroy(&e
->u
.rwlock
));
392 memset(e
, 0, sizeof(struct checked_lock
));
396 /** finish acquiring lock, shared between _(rd|wr||)lock() routines */
398 finish_acquire_lock(struct thr_check
* thr
, struct checked_lock
* lock
,
399 const char* func
, const char* file
, int line
)
405 lock
->holder_func
= func
;
406 lock
->holder_file
= file
;
407 lock
->holder_line
= line
;
408 ordercheck_locklock(thr
, lock
);
410 /* insert in thread lock list, as first */
411 lock
->prev_held_lock
[thr
->num
] = NULL
;
412 lock
->next_held_lock
[thr
->num
] = thr
->holding_first
;
413 if(thr
->holding_first
)
414 /* no need to lock it, since this thread already holds the
415 * lock (since it is on this list) and we only edit thr->num
416 * member in array. So it is safe. */
417 thr
->holding_first
->prev_held_lock
[thr
->num
] = lock
;
418 else thr
->holding_last
= lock
;
419 thr
->holding_first
= lock
;
424 * @param type: as passed by user.
425 * @param lock: as passed by user.
426 * @param func: caller location.
427 * @param file: caller location.
428 * @param line: caller location.
429 * @param tryfunc: the pthread_mutex_trylock or similar function.
430 * @param timedfunc: the pthread_mutex_timedlock or similar function.
431 * Uses absolute timeout value.
432 * @param arg: what to pass to tryfunc and timedlock.
433 * @param exclusive: if lock must be exlusive (only one allowed).
434 * @param getwr: if attempts to get writelock (or readlock) for rwlocks.
437 checklock_lockit(enum check_lock_type type
, struct checked_lock
* lock
,
438 const char* func
, const char* file
, int line
,
439 int (*tryfunc
)(void*), int (*timedfunc
)(void*, struct timespec
*),
440 void* arg
, int exclusive
, int getwr
)
444 struct thr_check
*thr
= (struct thr_check
*)pthread_getspecific(
446 checktype(type
, lock
, func
, file
, line
);
447 if(!thr
) lock_error(lock
, func
, file
, line
, "no thread info");
449 acquire_locklock(lock
, func
, file
, line
);
452 if(exclusive
&& lock
->hold_count
> 0 && lock
->holder
== thr
)
453 lock_error(lock
, func
, file
, line
, "thread already owns lock");
454 if(type
==check_lock_rwlock
&& getwr
&& lock
->writeholder
== thr
)
455 lock_error(lock
, func
, file
, line
, "thread already has wrlock");
456 LOCKRET(pthread_mutex_unlock(&lock
->lock
));
458 /* first try; if busy increase contention counter */
459 if((err
=tryfunc(arg
))) {
461 if(err
!= EBUSY
) log_err("trylock: %s", strerror(err
));
462 to
.tv_sec
= time(NULL
) + CHECK_LOCK_TIMEOUT
;
464 if((err
=timedfunc(arg
, &to
))) {
466 lock_error(lock
, func
, file
, line
,
467 "timeout possible deadlock");
468 log_err("timedlock: %s", strerror(err
));
474 acquire_locklock(lock
, func
, file
, line
);
475 lock
->contention_count
+= contend
;
476 lock
->history_count
++;
477 if(exclusive
&& lock
->hold_count
> 0)
478 lock_error(lock
, func
, file
, line
, "got nonexclusive lock");
479 if(type
==check_lock_rwlock
&& getwr
&& lock
->writeholder
)
480 lock_error(lock
, func
, file
, line
, "got nonexclusive wrlock");
481 if(type
==check_lock_rwlock
&& getwr
)
482 lock
->writeholder
= thr
;
483 /* check the memory areas for unauthorized changes,
484 * between last unlock time and current lock time.
485 * we check while holding the lock (threadsafe).
487 if(getwr
|| exclusive
)
488 prot_check(lock
, func
, file
, line
);
489 finish_acquire_lock(thr
, lock
, func
, file
, line
);
490 LOCKRET(pthread_mutex_unlock(&lock
->lock
));
493 /** helper for rdlock: try */
494 static int try_rd(void* arg
)
495 { return pthread_rwlock_tryrdlock((pthread_rwlock_t
*)arg
); }
496 /** helper for rdlock: timed */
497 static int timed_rd(void* arg
, struct timespec
* to
)
498 { return pthread_rwlock_timedrdlock((pthread_rwlock_t
*)arg
, to
); }
500 /** check if OK, lock */
502 checklock_rdlock(enum check_lock_type type
, struct checked_lock
* lock
,
503 const char* func
, const char* file
, int line
)
506 log_assert(type
== check_lock_rwlock
);
507 checklock_lockit(type
, lock
, func
, file
, line
,
508 try_rd
, timed_rd
, &lock
->u
.rwlock
, 0, 0);
511 /** helper for wrlock: try */
512 static int try_wr(void* arg
)
513 { return pthread_rwlock_trywrlock((pthread_rwlock_t
*)arg
); }
514 /** helper for wrlock: timed */
515 static int timed_wr(void* arg
, struct timespec
* to
)
516 { return pthread_rwlock_timedwrlock((pthread_rwlock_t
*)arg
, to
); }
518 /** check if OK, lock */
520 checklock_wrlock(enum check_lock_type type
, struct checked_lock
* lock
,
521 const char* func
, const char* file
, int line
)
523 log_assert(type
== check_lock_rwlock
);
524 checklock_lockit(type
, lock
, func
, file
, line
,
525 try_wr
, timed_wr
, &lock
->u
.rwlock
, 0, 1);
528 /** helper for lock mutex: try */
529 static int try_mutex(void* arg
)
530 { return pthread_mutex_trylock((pthread_mutex_t
*)arg
); }
531 /** helper for lock mutex: timed */
532 static int timed_mutex(void* arg
, struct timespec
* to
)
533 { return pthread_mutex_timedlock((pthread_mutex_t
*)arg
, to
); }
535 /** helper for lock spinlock: try */
536 static int try_spinlock(void* arg
)
537 { return pthread_spin_trylock((pthread_spinlock_t
*)arg
); }
538 /** helper for lock spinlock: timed */
539 static int timed_spinlock(void* arg
, struct timespec
* to
)
542 /* spin for 5 seconds. (ouch for the CPU, but it beats forever) */
543 while( (err
=try_spinlock(arg
)) == EBUSY
) {
545 if(time(NULL
) >= to
->tv_sec
)
547 usleep(1000); /* in 1/1000000s of a second */
553 /** check if OK, lock */
555 checklock_lock(enum check_lock_type type
, struct checked_lock
* lock
,
556 const char* func
, const char* file
, int line
)
558 log_assert(type
!= check_lock_rwlock
);
560 case check_lock_mutex
:
561 checklock_lockit(type
, lock
, func
, file
, line
,
562 try_mutex
, timed_mutex
, &lock
->u
.mutex
, 1, 0);
564 case check_lock_spinlock
:
565 /* void* cast needed because 'volatile' on some OS */
566 checklock_lockit(type
, lock
, func
, file
, line
,
567 try_spinlock
, timed_spinlock
,
568 (void*)&lock
->u
.spinlock
, 1, 0);
575 /** check if OK, unlock */
577 checklock_unlock(enum check_lock_type type
, struct checked_lock
* lock
,
578 const char* func
, const char* file
, int line
)
580 struct thr_check
*thr
= (struct thr_check
*)pthread_getspecific(
582 checktype(type
, lock
, func
, file
, line
);
583 if(!thr
) lock_error(lock
, func
, file
, line
, "no thread info");
585 acquire_locklock(lock
, func
, file
, line
);
586 /* was this thread even holding this lock? */
587 if(thr
->holding_first
!= lock
&&
588 lock
->prev_held_lock
[thr
->num
] == NULL
) {
589 lock_error(lock
, func
, file
, line
, "unlock nonlocked lock");
591 if(lock
->hold_count
<= 0)
592 lock_error(lock
, func
, file
, line
, "too many unlocks");
594 /* store this point as last touched by */
597 lock
->holder_func
= func
;
598 lock
->holder_file
= file
;
599 lock
->holder_line
= line
;
601 /* delete from thread holder list */
602 /* no need to lock other lockstructs, because they are all on the
603 * held-locks list, and this thread holds their locks.
604 * we only touch the thr->num members, so it is safe. */
605 if(thr
->holding_first
== lock
)
606 thr
->holding_first
= lock
->next_held_lock
[thr
->num
];
607 if(thr
->holding_last
== lock
)
608 thr
->holding_last
= lock
->prev_held_lock
[thr
->num
];
609 if(lock
->next_held_lock
[thr
->num
])
610 lock
->next_held_lock
[thr
->num
]->prev_held_lock
[thr
->num
] =
611 lock
->prev_held_lock
[thr
->num
];
612 if(lock
->prev_held_lock
[thr
->num
])
613 lock
->prev_held_lock
[thr
->num
]->next_held_lock
[thr
->num
] =
614 lock
->next_held_lock
[thr
->num
];
615 lock
->next_held_lock
[thr
->num
] = NULL
;
616 lock
->prev_held_lock
[thr
->num
] = NULL
;
618 if(type
==check_lock_rwlock
&& lock
->writeholder
== thr
) {
619 lock
->writeholder
= NULL
;
621 } else if(type
!= check_lock_rwlock
) {
622 /* store memory areas that are protected, for later checks */
625 LOCKRET(pthread_mutex_unlock(&lock
->lock
));
629 case check_lock_mutex
:
630 LOCKRET(pthread_mutex_unlock(&lock
->u
.mutex
));
632 case check_lock_spinlock
:
633 LOCKRET(pthread_spin_unlock(&lock
->u
.spinlock
));
635 case check_lock_rwlock
:
636 LOCKRET(pthread_rwlock_unlock(&lock
->u
.rwlock
));
643 /** open order info debug file, thr->num must be valid */
645 open_lockorder(struct thr_check
* thr
)
649 snprintf(buf
, sizeof(buf
), "ublocktrace.%d", thr
->num
);
650 thr
->order_info
= fopen(buf
, "w");
652 fatal_exit("could not open %s: %s", buf
, strerror(errno
));
653 thr
->locks_created
= 0;
655 /* write: <time_stamp> <runpid> <thread_num> */
656 if(fwrite(&t
, sizeof(t
), 1, thr
->order_info
) != 1 ||
657 fwrite(&thr
->num
, sizeof(thr
->num
), 1, thr
->order_info
) != 1 ||
658 fwrite(&check_lock_pid
, sizeof(check_lock_pid
), 1,
659 thr
->order_info
) != 1)
660 log_err("fwrite: %s", strerror(errno
));
663 /** checklock thread main, Inits thread structure */
664 static void* checklock_main(void* arg
)
666 struct thr_check
* thr
= (struct thr_check
*)arg
;
668 thr
->id
= pthread_self();
669 /* Hack to get same numbers as in log file */
670 thr
->num
= *(int*)(thr
->arg
);
671 log_assert(thr
->num
< THRDEBUG_MAX_THREADS
);
672 /* as an aside, due to this, won't work for libunbound bg thread */
673 if(thread_infos
[thr
->num
] != NULL
)
674 log_warn("thread warning, thr->num %d not NULL", thr
->num
);
675 thread_infos
[thr
->num
] = thr
;
676 LOCKRET(pthread_setspecific(thr_debug_key
, thr
));
677 if(check_locking_order
)
679 ret
= thr
->func(thr
->arg
);
680 thread_infos
[thr
->num
] = NULL
;
681 if(check_locking_order
)
682 fclose(thr
->order_info
);
687 /** init the main thread */
688 void checklock_start(void)
693 struct thr_check
* thisthr
= (struct thr_check
*)calloc(1,
694 sizeof(struct thr_check
));
696 fatal_exit("thrcreate: out of memory");
698 check_lock_pid
= getpid();
699 LOCKRET(pthread_key_create(&thr_debug_key
, NULL
));
700 LOCKRET(pthread_setspecific(thr_debug_key
, thisthr
));
701 thread_infos
[0] = thisthr
;
702 if(check_locking_order
)
703 open_lockorder(thisthr
);
707 /** stop checklocks */
708 void checklock_stop(void)
713 if(check_locking_order
)
714 fclose(thread_infos
[0]->order_info
);
715 free(thread_infos
[0]);
716 thread_infos
[0] = NULL
;
717 for(i
= 0; i
< THRDEBUG_MAX_THREADS
; i
++)
718 log_assert(thread_infos
[i
] == NULL
);
719 /* should have been cleaned up. */
720 LOCKRET(pthread_key_delete(thr_debug_key
));
725 /** allocate debug info and create thread */
727 checklock_thrcreate(pthread_t
* id
, void* (*func
)(void*), void* arg
)
729 struct thr_check
* thr
= (struct thr_check
*)calloc(1,
730 sizeof(struct thr_check
));
732 fatal_exit("thrcreate: out of memory");
738 LOCKRET(pthread_create(id
, NULL
, checklock_main
, thr
));
741 /** count number of thread infos */
743 count_thread_infos(void)
747 for(i
=0; i
<THRDEBUG_MAX_THREADS
; i
++)
753 /** print lots of info on a lock */
755 lock_debug_info(struct checked_lock
* lock
)
758 log_info("+++ Lock %x, %d %d create %s %s %d", (int)lock
,
759 lock
->create_thread
, lock
->create_instance
,
760 lock
->create_func
, lock
->create_file
, lock
->create_line
);
761 log_info("lock type: %s",
762 (lock
->type
==check_lock_mutex
)?"mutex": (
763 (lock
->type
==check_lock_spinlock
)?"spinlock": (
764 (lock
->type
==check_lock_rwlock
)?"rwlock": "badtype")));
765 log_info("lock contention %u, history:%u, hold:%d, wait:%d",
766 (unsigned)lock
->contention_count
, (unsigned)lock
->history_count
,
767 lock
->hold_count
, lock
->wait_count
);
768 log_info("last touch %s %s %d", lock
->holder_func
, lock
->holder_file
,
770 log_info("holder thread %d, writeholder thread %d",
771 lock
->holder
?lock
->holder
->num
:-1,
772 lock
->writeholder
?lock
->writeholder
->num
:-1);
775 /** print debug locks held by a thread */
777 held_debug_info(struct thr_check
* thr
, struct checked_lock
* lock
)
780 lock_debug_info(lock
);
781 held_debug_info(thr
, lock
->next_held_lock
[thr
->num
]);
784 /** print debug info for a thread */
786 thread_debug_info(struct thr_check
* thr
)
788 struct checked_lock
* w
= NULL
;
789 struct checked_lock
* f
= NULL
;
790 struct checked_lock
* l
= NULL
;
792 log_info("pthread id is %x", (int)thr
->id
);
793 log_info("thread func is %x", (int)thr
->func
);
794 log_info("thread arg is %x (%d)", (int)thr
->arg
,
795 (thr
->arg
?*(int*)thr
->arg
:0));
796 log_info("thread num is %d", thr
->num
);
797 log_info("locks created %d", thr
->locks_created
);
798 log_info("open file for lockinfo: %s",
799 thr
->order_info
?"yes, flushing":"no");
800 fflush(thr
->order_info
);
802 f
= thr
->holding_first
;
803 l
= thr
->holding_last
;
804 log_info("thread waiting for a lock: %s %x", w
?"yes":"no", (int)w
);
806 log_info("thread holding first: %s, last: %s", f
?"yes":"no",
808 held_debug_info(thr
, f
);
812 total_debug_info(void)
815 log_info("checklocks: supervising %d threads.",
816 count_thread_infos());
818 log_info("No thread debug key created yet");
820 for(i
=0; i
<THRDEBUG_MAX_THREADS
; i
++) {
821 if(thread_infos
[i
]) {
822 log_info("*** Thread %d information: ***", i
);
823 thread_debug_info(thread_infos
[i
]);
828 /** signal handler for join timeout, Exits */
829 static RETSIGTYPE
joinalarm(int ATTR_UNUSED(sig
))
831 log_err("join thread timeout. hangup or deadlock. Info follows.");
833 fatal_exit("join thread timeout. hangup or deadlock.");
836 /** wait for thread with a timeout */
838 checklock_thrjoin(pthread_t thread
)
840 /* wait with a timeout */
841 if(signal(SIGALRM
, joinalarm
) == SIG_ERR
)
842 fatal_exit("signal(): %s", strerror(errno
));
843 (void)alarm(CHECK_JOIN_TIMEOUT
);
844 LOCKRET(pthread_join(thread
, NULL
));
848 #endif /* USE_THREAD_DEBUG */