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