2 * Copyright (C) 2008 Tobias Brunner
3 * Copyright (C) 2008 Martin Willi
4 * Hochschule fuer Technik Rapperswil
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
31 typedef struct private_mutex_t private_mutex_t
;
32 typedef struct private_r_mutex_t private_r_mutex_t
;
33 typedef struct private_condvar_t private_condvar_t
;
34 typedef struct private_rwlock_t private_rwlock_t
;
39 * Do not report mutexes with an overall waiting time smaller than this (in us)
41 #define PROFILE_TRESHHOLD 1000
43 #include <utils/backtrace.h>
45 typedef struct lock_profile_t lock_profile_t
;
47 struct lock_profile_t
{
50 * how long threads have waited for the lock in this mutex so far
52 struct timeval waited
;
55 * backtrace where mutex has been created
57 backtrace_t
*backtrace
;
61 * Print and cleanup mutex profiler
63 static void profiler_cleanup(lock_profile_t
*profile
)
65 if (profile
->waited
.tv_sec
> 0 ||
66 profile
->waited
.tv_usec
> PROFILE_TRESHHOLD
)
68 fprintf(stderr
, "%d.%06ds in lock created at:",
69 profile
->waited
.tv_sec
, profile
->waited
.tv_usec
);
70 profile
->backtrace
->log(profile
->backtrace
, stderr
);
72 profile
->backtrace
->destroy(profile
->backtrace
);
76 * Initialize mutex profiler
78 static void profiler_init(lock_profile_t
*profile
)
80 profile
->backtrace
= backtrace_create(3);
81 timerclear(&profile
->waited
);
84 #define profiler_start(profile) { \
85 struct timeval _start, _end, _diff; \
86 gettimeofday(&_start, NULL);
88 #define profiler_end(profile) \
89 gettimeofday(&_end, NULL); \
90 timersub(&_end, &_start, &_diff); \
91 timeradd(&(profile)->waited, &_diff, &(profile)->waited); }
93 #else /* !LOCK_PROFILER */
95 #define lock_profile_t struct {}
96 #define profiler_cleanup(...) {}
97 #define profiler_init(...) {}
98 #define profiler_start(...) {}
99 #define profiler_end(...) {}
101 #endif /* LOCK_PROFILER */
104 * private data of mutex
106 struct private_mutex_t
{
114 * wrapped pthread mutex
116 pthread_mutex_t mutex
;
119 * is this a recursiv emutex, implementing private_r_mutex_t?
124 * profiling info, if enabled
126 lock_profile_t profile
;
130 * private data of mutex, extended by recursive locking information
132 struct private_r_mutex_t
{
135 * Extends private_mutex_t
137 private_mutex_t generic
;
140 * thread which currently owns mutex
145 * times we have locked the lock, stored per thread
151 * private data of condvar
153 struct private_condvar_t
{
161 * wrapped pthread condvar
163 pthread_cond_t condvar
;
167 * private data of rwlock
169 struct private_rwlock_t
{
177 * wrapped pthread rwlock
179 pthread_rwlock_t rwlock
;
182 * profiling info, if enabled
184 lock_profile_t profile
;
188 * Implementation of mutex_t.lock.
190 static void lock(private_mutex_t
*this)
192 profiler_start(&this->profile
);
193 if (pthread_mutex_lock(&this->mutex
))
195 DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", "");
197 profiler_end(&this->profile
);
201 * Implementation of mutex_t.unlock.
203 static void unlock(private_mutex_t
*this)
205 if (pthread_mutex_unlock(&this->mutex
))
207 DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", "UN");
212 * Implementation of mutex_t.lock.
214 static void lock_r(private_r_mutex_t
*this)
216 pthread_t self
= pthread_self();
218 if (this->thread
== self
)
223 times
= (uintptr_t)pthread_getspecific(this->times
);
224 pthread_setspecific(this->times
, (void*)times
+ 1);
228 lock(&this->generic
);
231 pthread_setspecific(this->times
, (void*)1);
236 * Implementation of mutex_t.unlock.
238 static void unlock_r(private_r_mutex_t
*this)
243 times
= (uintptr_t)pthread_getspecific(this->times
);
244 pthread_setspecific(this->times
, (void*)--times
);
249 unlock(&this->generic
);
254 * Implementation of mutex_t.destroy
256 static void mutex_destroy(private_mutex_t
*this)
258 profiler_cleanup(&this->profile
);
259 pthread_mutex_destroy(&this->mutex
);
264 * Implementation of mutex_t.destroy for recursive mutex'
266 static void mutex_destroy_r(private_r_mutex_t
*this)
268 profiler_cleanup(&this->generic
.profile
);
269 pthread_mutex_destroy(&this->generic
.mutex
);
270 pthread_key_delete(this->times
);
277 mutex_t
*mutex_create(mutex_type_t type
)
281 case MUTEX_RECURSIVE
:
283 private_r_mutex_t
*this = malloc_thing(private_r_mutex_t
);
285 this->generic
.public.lock
= (void(*)(mutex_t
*))lock_r
;
286 this->generic
.public.unlock
= (void(*)(mutex_t
*))unlock_r
;
287 this->generic
.public.destroy
= (void(*)(mutex_t
*))mutex_destroy_r
;
289 pthread_mutex_init(&this->generic
.mutex
, NULL
);
290 pthread_key_create(&this->times
, NULL
);
291 this->generic
.recursive
= TRUE
;
292 profiler_init(&this->generic
.profile
);
295 return &this->generic
.public;
300 private_mutex_t
*this = malloc_thing(private_mutex_t
);
302 this->public.lock
= (void(*)(mutex_t
*))lock
;
303 this->public.unlock
= (void(*)(mutex_t
*))unlock
;
304 this->public.destroy
= (void(*)(mutex_t
*))mutex_destroy
;
306 pthread_mutex_init(&this->mutex
, NULL
);
307 this->recursive
= FALSE
;
308 profiler_init(&this->profile
);
310 return &this->public;
316 * Implementation of condvar_t.wait.
318 static void wait(private_condvar_t
*this, private_mutex_t
*mutex
)
320 if (mutex
->recursive
)
322 private_r_mutex_t
* recursive
= (private_r_mutex_t
*)mutex
;
324 /* mutex owner gets cleared during condvar wait */
325 recursive
->thread
= 0;
326 pthread_cond_wait(&this->condvar
, &mutex
->mutex
);
327 recursive
->thread
= pthread_self();
331 pthread_cond_wait(&this->condvar
, &mutex
->mutex
);
336 * Implementation of condvar_t.timed_wait_abs.
338 static bool timed_wait_abs(private_condvar_t
*this, private_mutex_t
*mutex
,
344 ts
.tv_sec
= time
.tv_sec
;
345 ts
.tv_nsec
= time
.tv_usec
* 1000;
347 if (mutex
->recursive
)
349 private_r_mutex_t
* recursive
= (private_r_mutex_t
*)mutex
;
351 recursive
->thread
= 0;
352 timed_out
= pthread_cond_timedwait(&this->condvar
, &mutex
->mutex
,
354 recursive
->thread
= pthread_self();
358 timed_out
= pthread_cond_timedwait(&this->condvar
, &mutex
->mutex
,
365 * Implementation of condvar_t.timed_wait.
367 static bool timed_wait(private_condvar_t
*this, private_mutex_t
*mutex
,
373 gettimeofday(&tv
, NULL
);
379 tv
.tv_usec
+= ms
* 1000;
381 if (tv
.tv_usec
> 1000000 /* 1s */)
383 tv
.tv_usec
-= 1000000;
386 return timed_wait_abs(this, mutex
, tv
);
390 * Implementation of condvar_t.signal.
392 static void signal(private_condvar_t
*this)
394 pthread_cond_signal(&this->condvar
);
398 * Implementation of condvar_t.broadcast.
400 static void broadcast(private_condvar_t
*this)
402 pthread_cond_broadcast(&this->condvar
);
406 * Implementation of condvar_t.destroy
408 static void condvar_destroy(private_condvar_t
*this)
410 pthread_cond_destroy(&this->condvar
);
417 condvar_t
*condvar_create(condvar_type_t type
)
421 case CONDVAR_DEFAULT
:
424 private_condvar_t
*this = malloc_thing(private_condvar_t
);
426 this->public.wait
= (void(*)(condvar_t
*, mutex_t
*mutex
))wait
;
427 this->public.timed_wait
= (bool(*)(condvar_t
*, mutex_t
*mutex
, u_int timeout
))timed_wait
;
428 this->public.timed_wait_abs
= (bool(*)(condvar_t
*, mutex_t
*mutex
, timeval_t time
))timed_wait_abs
;
429 this->public.signal
= (void(*)(condvar_t
*))signal
;
430 this->public.broadcast
= (void(*)(condvar_t
*))broadcast
;
431 this->public.destroy
= (void(*)(condvar_t
*))condvar_destroy
;
433 pthread_cond_init(&this->condvar
, NULL
);
435 return &this->public;
441 * Implementation of rwlock_t.read_lock
443 static void read_lock(private_rwlock_t
*this)
445 profiler_start(&this->profile
);
446 pthread_rwlock_rdlock(&this->rwlock
);
447 profiler_end(&this->profile
);
451 * Implementation of rwlock_t.write_lock
453 static void write_lock(private_rwlock_t
*this)
455 profiler_start(&this->profile
);
456 pthread_rwlock_wrlock(&this->rwlock
);
457 profiler_end(&this->profile
);
461 * Implementation of rwlock_t.try_write_lock
463 static bool try_write_lock(private_rwlock_t
*this)
465 return pthread_rwlock_trywrlock(&this->rwlock
) == 0;
469 * Implementation of rwlock_t.unlock
471 static void rw_unlock(private_rwlock_t
*this)
473 pthread_rwlock_unlock(&this->rwlock
);
477 * Implementation of rwlock_t.destroy
479 static void rw_destroy(private_rwlock_t
*this)
481 pthread_rwlock_destroy(&this->rwlock
);
482 profiler_cleanup(&this->profile
);
489 rwlock_t
*rwlock_create(rwlock_type_t type
)
496 private_rwlock_t
*this = malloc_thing(private_rwlock_t
);
498 this->public.read_lock
= (void(*)(rwlock_t
*))read_lock
;
499 this->public.write_lock
= (void(*)(rwlock_t
*))write_lock
;
500 this->public.try_write_lock
= (bool(*)(rwlock_t
*))try_write_lock
;
501 this->public.unlock
= (void(*)(rwlock_t
*))rw_unlock
;
502 this->public.destroy
= (void(*)(rwlock_t
*))rw_destroy
;
504 pthread_rwlock_init(&this->rwlock
, NULL
);
505 profiler_init(&this->profile
);
507 return &this->public;