2 * Copyright (C) 2008-2009 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
28 #include "lock_profiler.h"
30 typedef struct private_mutex_t private_mutex_t
;
31 typedef struct private_r_mutex_t private_r_mutex_t
;
32 typedef struct private_condvar_t private_condvar_t
;
35 * private data of mutex
37 struct private_mutex_t
{
45 * wrapped pthread mutex
47 pthread_mutex_t mutex
;
50 * is this a recursiv emutex, implementing private_r_mutex_t?
55 * profiling info, if enabled
57 lock_profile_t profile
;
61 * private data of mutex, extended by recursive locking information
63 struct private_r_mutex_t
{
66 * Extends private_mutex_t
68 private_mutex_t generic
;
71 * thread which currently owns mutex
76 * times we have locked the lock, stored per thread
82 * private data of condvar
84 struct private_condvar_t
{
92 * wrapped pthread condvar
94 pthread_cond_t condvar
;
101 * Implementation of mutex_t.lock.
103 static void lock(private_mutex_t
*this)
107 profiler_start(&this->profile
);
108 err
= pthread_mutex_lock(&this->mutex
);
111 DBG1(DBG_LIB
, "!!! MUTEX LOCK ERROR: %s !!!", strerror(err
));
113 profiler_end(&this->profile
);
117 * Implementation of mutex_t.unlock.
119 static void unlock(private_mutex_t
*this)
123 err
= pthread_mutex_unlock(&this->mutex
);
126 DBG1(DBG_LIB
, "!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err
));
131 * Implementation of mutex_t.lock.
133 static void lock_r(private_r_mutex_t
*this)
135 pthread_t self
= pthread_self();
137 if (this->thread
== self
)
142 times
= (uintptr_t)pthread_getspecific(this->times
);
143 pthread_setspecific(this->times
, (void*)times
+ 1);
147 lock(&this->generic
);
150 pthread_setspecific(this->times
, (void*)1);
155 * Implementation of mutex_t.unlock.
157 static void unlock_r(private_r_mutex_t
*this)
162 times
= (uintptr_t)pthread_getspecific(this->times
);
163 pthread_setspecific(this->times
, (void*)--times
);
168 unlock(&this->generic
);
173 * Implementation of mutex_t.destroy
175 static void mutex_destroy(private_mutex_t
*this)
177 profiler_cleanup(&this->profile
);
178 pthread_mutex_destroy(&this->mutex
);
183 * Implementation of mutex_t.destroy for recursive mutex'
185 static void mutex_destroy_r(private_r_mutex_t
*this)
187 profiler_cleanup(&this->generic
.profile
);
188 pthread_mutex_destroy(&this->generic
.mutex
);
189 pthread_key_delete(this->times
);
196 mutex_t
*mutex_create(mutex_type_t type
)
200 case MUTEX_TYPE_RECURSIVE
:
202 private_r_mutex_t
*this = malloc_thing(private_r_mutex_t
);
204 this->generic
.public.lock
= (void(*)(mutex_t
*))lock_r
;
205 this->generic
.public.unlock
= (void(*)(mutex_t
*))unlock_r
;
206 this->generic
.public.destroy
= (void(*)(mutex_t
*))mutex_destroy_r
;
208 pthread_mutex_init(&this->generic
.mutex
, NULL
);
209 pthread_key_create(&this->times
, NULL
);
210 this->generic
.recursive
= TRUE
;
211 profiler_init(&this->generic
.profile
);
214 return &this->generic
.public;
216 case MUTEX_TYPE_DEFAULT
:
219 private_mutex_t
*this = malloc_thing(private_mutex_t
);
221 this->public.lock
= (void(*)(mutex_t
*))lock
;
222 this->public.unlock
= (void(*)(mutex_t
*))unlock
;
223 this->public.destroy
= (void(*)(mutex_t
*))mutex_destroy
;
225 pthread_mutex_init(&this->mutex
, NULL
);
226 this->recursive
= FALSE
;
227 profiler_init(&this->profile
);
229 return &this->public;
237 * Implementation of condvar_t.wait.
239 static void _wait(private_condvar_t
*this, private_mutex_t
*mutex
)
241 if (mutex
->recursive
)
243 private_r_mutex_t
* recursive
= (private_r_mutex_t
*)mutex
;
245 /* mutex owner gets cleared during condvar wait */
246 recursive
->thread
= 0;
247 pthread_cond_wait(&this->condvar
, &mutex
->mutex
);
248 recursive
->thread
= pthread_self();
252 pthread_cond_wait(&this->condvar
, &mutex
->mutex
);
256 /* use the monotonic clock based version of this function if available */
257 #ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
258 #define pthread_cond_timedwait pthread_cond_timedwait_monotonic
262 * Implementation of condvar_t.timed_wait_abs.
264 static bool timed_wait_abs(private_condvar_t
*this, private_mutex_t
*mutex
,
270 ts
.tv_sec
= time
.tv_sec
;
271 ts
.tv_nsec
= time
.tv_usec
* 1000;
273 if (mutex
->recursive
)
275 private_r_mutex_t
* recursive
= (private_r_mutex_t
*)mutex
;
277 recursive
->thread
= 0;
278 timed_out
= pthread_cond_timedwait(&this->condvar
, &mutex
->mutex
,
280 recursive
->thread
= pthread_self();
284 timed_out
= pthread_cond_timedwait(&this->condvar
, &mutex
->mutex
,
291 * Implementation of condvar_t.timed_wait.
293 static bool timed_wait(private_condvar_t
*this, private_mutex_t
*mutex
,
305 tv
.tv_usec
+= ms
* 1000;
307 if (tv
.tv_usec
> 1000000 /* 1s */)
309 tv
.tv_usec
-= 1000000;
312 return timed_wait_abs(this, mutex
, tv
);
316 * Implementation of condvar_t.signal.
318 static void _signal(private_condvar_t
*this)
320 pthread_cond_signal(&this->condvar
);
324 * Implementation of condvar_t.broadcast.
326 static void broadcast(private_condvar_t
*this)
328 pthread_cond_broadcast(&this->condvar
);
332 * Implementation of condvar_t.destroy
334 static void condvar_destroy(private_condvar_t
*this)
336 pthread_cond_destroy(&this->condvar
);
343 condvar_t
*condvar_create(condvar_type_t type
)
347 case CONDVAR_TYPE_DEFAULT
:
350 private_condvar_t
*this = malloc_thing(private_condvar_t
);
352 this->public.wait
= (void(*)(condvar_t
*, mutex_t
*mutex
))_wait
;
353 this->public.timed_wait
= (bool(*)(condvar_t
*, mutex_t
*mutex
, u_int timeout
))timed_wait
;
354 this->public.timed_wait_abs
= (bool(*)(condvar_t
*, mutex_t
*mutex
, timeval_t time
))timed_wait_abs
;
355 this->public.signal
= (void(*)(condvar_t
*))_signal
;
356 this->public.broadcast
= (void(*)(condvar_t
*))broadcast
;
357 this->public.destroy
= (void(*)(condvar_t
*))condvar_destroy
;
359 #ifdef HAVE_PTHREAD_CONDATTR_INIT
361 pthread_condattr_t condattr
;
362 pthread_condattr_init(&condattr
);
363 #ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
364 pthread_condattr_setclock(&condattr
, CLOCK_MONOTONIC
);
366 pthread_cond_init(&this->condvar
, &condattr
);
367 pthread_condattr_destroy(&condattr
);
371 return &this->public;