xref: /freebsd/contrib/unbound/testcode/checklocks.c (revision be771a7b7f4580a30d99e41a5bb1b93a385a119d)
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