1#define _GNU_SOURCE
2#include <pthread.h>
3#include <stdio.h>
4#include <dlfcn.h>
5#include <stdlib.h>
6#include <sysexits.h>
7#include <unistd.h>
8#include "include/liblockdep/mutex.h"
9#include "../../include/linux/rbtree.h"
10
11
12
13
14
15
16
17
18
19struct lock_lookup {
20 void *orig;
21 struct lockdep_map dep_map;
22
23
24
25
26
27
28
29
30
31 struct lock_class_key key;
32 struct rb_node node;
33#define LIBLOCKDEP_MAX_LOCK_NAME 22
34 char name[LIBLOCKDEP_MAX_LOCK_NAME];
35};
36
37
38static struct rb_root locks = RB_ROOT;
39static pthread_rwlock_t locks_rwlock = PTHREAD_RWLOCK_INITIALIZER;
40
41
42
43#ifdef __GLIBC__
44extern int __pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
45extern int __pthread_mutex_lock(pthread_mutex_t *mutex);
46extern int __pthread_mutex_trylock(pthread_mutex_t *mutex);
47extern int __pthread_mutex_unlock(pthread_mutex_t *mutex);
48extern int __pthread_mutex_destroy(pthread_mutex_t *mutex);
49#else
50#define __pthread_mutex_init NULL
51#define __pthread_mutex_lock NULL
52#define __pthread_mutex_trylock NULL
53#define __pthread_mutex_unlock NULL
54#define __pthread_mutex_destroy NULL
55#endif
56static int (*ll_pthread_mutex_init)(pthread_mutex_t *mutex,
57 const pthread_mutexattr_t *attr) = __pthread_mutex_init;
58static int (*ll_pthread_mutex_lock)(pthread_mutex_t *mutex) = __pthread_mutex_lock;
59static int (*ll_pthread_mutex_trylock)(pthread_mutex_t *mutex) = __pthread_mutex_trylock;
60static int (*ll_pthread_mutex_unlock)(pthread_mutex_t *mutex) = __pthread_mutex_unlock;
61static int (*ll_pthread_mutex_destroy)(pthread_mutex_t *mutex) = __pthread_mutex_destroy;
62
63
64
65#ifdef __GLIBC__
66extern int __pthread_rwlock_init(pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr);
67extern int __pthread_rwlock_destroy(pthread_rwlock_t *rwlock);
68extern int __pthread_rwlock_wrlock(pthread_rwlock_t *rwlock);
69extern int __pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock);
70extern int __pthread_rwlock_rdlock(pthread_rwlock_t *rwlock);
71extern int __pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock);
72extern int __pthread_rwlock_unlock(pthread_rwlock_t *rwlock);
73#else
74#define __pthread_rwlock_init NULL
75#define __pthread_rwlock_destroy NULL
76#define __pthread_rwlock_wrlock NULL
77#define __pthread_rwlock_trywrlock NULL
78#define __pthread_rwlock_rdlock NULL
79#define __pthread_rwlock_tryrdlock NULL
80#define __pthread_rwlock_unlock NULL
81#endif
82
83static int (*ll_pthread_rwlock_init)(pthread_rwlock_t *rwlock,
84 const pthread_rwlockattr_t *attr) = __pthread_rwlock_init;
85static int (*ll_pthread_rwlock_destroy)(pthread_rwlock_t *rwlock) = __pthread_rwlock_destroy;
86static int (*ll_pthread_rwlock_rdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_rdlock;
87static int (*ll_pthread_rwlock_tryrdlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_tryrdlock;
88static int (*ll_pthread_rwlock_trywrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_trywrlock;
89static int (*ll_pthread_rwlock_wrlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_wrlock;
90static int (*ll_pthread_rwlock_unlock)(pthread_rwlock_t *rwlock) = __pthread_rwlock_unlock;
91
92enum { none, prepare, done, } __init_state;
93static void init_preload(void);
94static void try_init_preload(void)
95{
96 if (__init_state != done)
97 init_preload();
98}
99
100static struct rb_node **__get_lock_node(void *lock, struct rb_node **parent)
101{
102 struct rb_node **node = &locks.rb_node;
103 struct lock_lookup *l;
104
105 *parent = NULL;
106
107 while (*node) {
108 l = rb_entry(*node, struct lock_lookup, node);
109
110 *parent = *node;
111 if (lock < l->orig)
112 node = &l->node.rb_left;
113 else if (lock > l->orig)
114 node = &l->node.rb_right;
115 else
116 return node;
117 }
118
119 return node;
120}
121
122#ifndef LIBLOCKDEP_STATIC_ENTRIES
123#define LIBLOCKDEP_STATIC_ENTRIES 1024
124#endif
125
126static struct lock_lookup __locks[LIBLOCKDEP_STATIC_ENTRIES];
127static int __locks_nr;
128
129static inline bool is_static_lock(struct lock_lookup *lock)
130{
131 return lock >= __locks && lock < __locks + ARRAY_SIZE(__locks);
132}
133
134static struct lock_lookup *alloc_lock(void)
135{
136 if (__init_state != done) {
137
138
139
140
141
142
143
144
145
146
147
148
149 int idx = __locks_nr++;
150 if (idx >= ARRAY_SIZE(__locks)) {
151 dprintf(STDERR_FILENO,
152 "LOCKDEP error: insufficient LIBLOCKDEP_STATIC_ENTRIES\n");
153 exit(EX_UNAVAILABLE);
154 }
155 return __locks + idx;
156 }
157
158 return malloc(sizeof(struct lock_lookup));
159}
160
161static inline void free_lock(struct lock_lookup *lock)
162{
163 if (likely(!is_static_lock(lock)))
164 free(lock);
165}
166
167
168
169
170
171
172
173
174static struct lock_lookup *__get_lock(void *lock)
175{
176 struct rb_node **node, *parent;
177 struct lock_lookup *l;
178
179 ll_pthread_rwlock_rdlock(&locks_rwlock);
180 node = __get_lock_node(lock, &parent);
181 ll_pthread_rwlock_unlock(&locks_rwlock);
182 if (*node) {
183 return rb_entry(*node, struct lock_lookup, node);
184 }
185
186
187 l = alloc_lock();
188 if (l == NULL)
189 return NULL;
190
191 l->orig = lock;
192
193
194
195
196
197
198 sprintf(l->name, "%p", lock);
199 lockdep_init_map(&l->dep_map, l->name, &l->key, 0);
200
201 ll_pthread_rwlock_wrlock(&locks_rwlock);
202
203 node = __get_lock_node(lock, &parent);
204 rb_link_node(&l->node, parent, node);
205 rb_insert_color(&l->node, &locks);
206 ll_pthread_rwlock_unlock(&locks_rwlock);
207
208 return l;
209}
210
211static void __del_lock(struct lock_lookup *lock)
212{
213 ll_pthread_rwlock_wrlock(&locks_rwlock);
214 rb_erase(&lock->node, &locks);
215 ll_pthread_rwlock_unlock(&locks_rwlock);
216 free_lock(lock);
217}
218
219int pthread_mutex_init(pthread_mutex_t *mutex,
220 const pthread_mutexattr_t *attr)
221{
222 int r;
223
224
225
226
227
228
229
230
231
232
233
234 try_init_preload();
235
236 r = ll_pthread_mutex_init(mutex, attr);
237 if (r == 0)
238
239
240
241
242
243 __get_lock(mutex);
244
245 return r;
246}
247
248int pthread_mutex_lock(pthread_mutex_t *mutex)
249{
250 int r;
251
252 try_init_preload();
253
254 lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 1, NULL,
255 (unsigned long)_RET_IP_);
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270 r = ll_pthread_mutex_lock(mutex);
271 if (r)
272 lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_);
273
274 return r;
275}
276
277int pthread_mutex_trylock(pthread_mutex_t *mutex)
278{
279 int r;
280
281 try_init_preload();
282
283 lock_acquire(&__get_lock(mutex)->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_);
284 r = ll_pthread_mutex_trylock(mutex);
285 if (r)
286 lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_);
287
288 return r;
289}
290
291int pthread_mutex_unlock(pthread_mutex_t *mutex)
292{
293 int r;
294
295 try_init_preload();
296
297 lock_release(&__get_lock(mutex)->dep_map, 0, (unsigned long)_RET_IP_);
298
299
300
301
302
303 r = ll_pthread_mutex_unlock(mutex);
304 if (r)
305 lock_acquire(&__get_lock(mutex)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_);
306
307 return r;
308}
309
310int pthread_mutex_destroy(pthread_mutex_t *mutex)
311{
312 try_init_preload();
313
314
315
316
317
318
319 debug_check_no_locks_freed(mutex, sizeof(*mutex));
320 __del_lock(__get_lock(mutex));
321 return ll_pthread_mutex_destroy(mutex);
322}
323
324
325int pthread_rwlock_init(pthread_rwlock_t *rwlock,
326 const pthread_rwlockattr_t *attr)
327{
328 int r;
329
330 try_init_preload();
331
332 r = ll_pthread_rwlock_init(rwlock, attr);
333 if (r == 0)
334 __get_lock(rwlock);
335
336 return r;
337}
338
339int pthread_rwlock_destroy(pthread_rwlock_t *rwlock)
340{
341 try_init_preload();
342
343 debug_check_no_locks_freed(rwlock, sizeof(*rwlock));
344 __del_lock(__get_lock(rwlock));
345 return ll_pthread_rwlock_destroy(rwlock);
346}
347
348int pthread_rwlock_rdlock(pthread_rwlock_t *rwlock)
349{
350 int r;
351
352 init_preload();
353
354 lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 2, 1, NULL, (unsigned long)_RET_IP_);
355 r = ll_pthread_rwlock_rdlock(rwlock);
356 if (r)
357 lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_);
358
359 return r;
360}
361
362int pthread_rwlock_tryrdlock(pthread_rwlock_t *rwlock)
363{
364 int r;
365
366 init_preload();
367
368 lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 2, 1, NULL, (unsigned long)_RET_IP_);
369 r = ll_pthread_rwlock_tryrdlock(rwlock);
370 if (r)
371 lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_);
372
373 return r;
374}
375
376int pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
377{
378 int r;
379
380 init_preload();
381
382 lock_acquire(&__get_lock(rwlock)->dep_map, 0, 1, 0, 1, NULL, (unsigned long)_RET_IP_);
383 r = ll_pthread_rwlock_trywrlock(rwlock);
384 if (r)
385 lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_);
386
387 return r;
388}
389
390int pthread_rwlock_wrlock(pthread_rwlock_t *rwlock)
391{
392 int r;
393
394 init_preload();
395
396 lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_);
397 r = ll_pthread_rwlock_wrlock(rwlock);
398 if (r)
399 lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_);
400
401 return r;
402}
403
404int pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
405{
406 int r;
407
408 init_preload();
409
410 lock_release(&__get_lock(rwlock)->dep_map, 0, (unsigned long)_RET_IP_);
411 r = ll_pthread_rwlock_unlock(rwlock);
412 if (r)
413 lock_acquire(&__get_lock(rwlock)->dep_map, 0, 0, 0, 1, NULL, (unsigned long)_RET_IP_);
414
415 return r;
416}
417
418__attribute__((constructor)) static void init_preload(void)
419{
420 if (__init_state == done)
421 return;
422
423#ifndef __GLIBC__
424 __init_state = prepare;
425
426 ll_pthread_mutex_init = dlsym(RTLD_NEXT, "pthread_mutex_init");
427 ll_pthread_mutex_lock = dlsym(RTLD_NEXT, "pthread_mutex_lock");
428 ll_pthread_mutex_trylock = dlsym(RTLD_NEXT, "pthread_mutex_trylock");
429 ll_pthread_mutex_unlock = dlsym(RTLD_NEXT, "pthread_mutex_unlock");
430 ll_pthread_mutex_destroy = dlsym(RTLD_NEXT, "pthread_mutex_destroy");
431
432 ll_pthread_rwlock_init = dlsym(RTLD_NEXT, "pthread_rwlock_init");
433 ll_pthread_rwlock_destroy = dlsym(RTLD_NEXT, "pthread_rwlock_destroy");
434 ll_pthread_rwlock_rdlock = dlsym(RTLD_NEXT, "pthread_rwlock_rdlock");
435 ll_pthread_rwlock_tryrdlock = dlsym(RTLD_NEXT, "pthread_rwlock_tryrdlock");
436 ll_pthread_rwlock_wrlock = dlsym(RTLD_NEXT, "pthread_rwlock_wrlock");
437 ll_pthread_rwlock_trywrlock = dlsym(RTLD_NEXT, "pthread_rwlock_trywrlock");
438 ll_pthread_rwlock_unlock = dlsym(RTLD_NEXT, "pthread_rwlock_unlock");
439#endif
440
441 __init_state = done;
442}
443