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