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
27 #include "lock_profiler.h"
29 typedef struct private_mutex_t private_mutex_t
;
30 typedef struct private_r_mutex_t private_r_mutex_t
;
31 typedef struct private_condvar_t private_condvar_t
;
34 * private data of mutex
36 struct private_mutex_t
{
44 * wrapped pthread mutex
46 pthread_mutex_t mutex
;
49 * is this a recursiv emutex, implementing private_r_mutex_t?
54 * profiling info, if enabled
56 lock_profile_t profile
;
60 * private data of mutex, extended by recursive locking information
62 struct private_r_mutex_t
{
65 * Extends private_mutex_t
67 private_mutex_t generic
;
70 * thread which currently owns mutex
75 * times we have locked the lock, stored per thread
81 * private data of condvar
83 struct private_condvar_t
{
91 * wrapped pthread condvar
93 pthread_cond_t condvar
;
100 * Implementation of mutex_t.lock.
102 static void lock(private_mutex_t
*this)
106 profiler_start(&this->profile
);
107 err
= pthread_mutex_lock(&this->mutex
);
110 DBG1("!!! MUTEX LOCK ERROR: %s !!!", strerror(err
));
112 profiler_end(&this->profile
);
116 * Implementation of mutex_t.unlock.
118 static void unlock(private_mutex_t
*this)
122 err
= pthread_mutex_unlock(&this->mutex
);
125 DBG1("!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err
));
130 * Implementation of mutex_t.lock.
132 static void lock_r(private_r_mutex_t
*this)
134 pthread_t self
= pthread_self();
136 if (this->thread
== self
)
141 times
= (uintptr_t)pthread_getspecific(this->times
);
142 pthread_setspecific(this->times
, (void*)times
+ 1);
146 lock(&this->generic
);
149 pthread_setspecific(this->times
, (void*)1);
154 * Implementation of mutex_t.unlock.
156 static void unlock_r(private_r_mutex_t
*this)
161 times
= (uintptr_t)pthread_getspecific(this->times
);
162 pthread_setspecific(this->times
, (void*)--times
);
167 unlock(&this->generic
);
172 * Implementation of mutex_t.destroy
174 static void mutex_destroy(private_mutex_t
*this)
176 profiler_cleanup(&this->profile
);
177 pthread_mutex_destroy(&this->mutex
);
182 * Implementation of mutex_t.destroy for recursive mutex'
184 static void mutex_destroy_r(private_r_mutex_t
*this)
186 profiler_cleanup(&this->generic
.profile
);
187 pthread_mutex_destroy(&this->generic
.mutex
);
188 pthread_key_delete(this->times
);
195 mutex_t
*mutex_create(mutex_type_t type
)
199 case MUTEX_TYPE_RECURSIVE
:
201 private_r_mutex_t
*this = malloc_thing(private_r_mutex_t
);
203 this->generic
.public.lock
= (void(*)(mutex_t
*))lock_r
;
204 this->generic
.public.unlock
= (void(*)(mutex_t
*))unlock_r
;
205 this->generic
.public.destroy
= (void(*)(mutex_t
*))mutex_destroy_r
;
207 pthread_mutex_init(&this->generic
.mutex
, NULL
);
208 pthread_key_create(&this->times
, NULL
);
209 this->generic
.recursive
= TRUE
;
210 profiler_init(&this->generic
.profile
);
213 return &this->generic
.public;
215 case MUTEX_TYPE_DEFAULT
:
218 private_mutex_t
*this = malloc_thing(private_mutex_t
);
220 this->public.lock
= (void(*)(mutex_t
*))lock
;
221 this->public.unlock
= (void(*)(mutex_t
*))unlock
;
222 this->public.destroy
= (void(*)(mutex_t
*))mutex_destroy
;
224 pthread_mutex_init(&this->mutex
, NULL
);
225 this->recursive
= FALSE
;
226 profiler_init(&this->profile
);
228 return &this->public;
236 * Implementation of condvar_t.wait.
238 static void _wait(private_condvar_t
*this, private_mutex_t
*mutex
)
240 if (mutex
->recursive
)
242 private_r_mutex_t
* recursive
= (private_r_mutex_t
*)mutex
;
244 /* mutex owner gets cleared during condvar wait */
245 recursive
->thread
= 0;
246 pthread_cond_wait(&this->condvar
, &mutex
->mutex
);
247 recursive
->thread
= pthread_self();
251 pthread_cond_wait(&this->condvar
, &mutex
->mutex
);
256 * Implementation of condvar_t.timed_wait_abs.
258 static bool timed_wait_abs(private_condvar_t
*this, private_mutex_t
*mutex
,
264 ts
.tv_sec
= time
.tv_sec
;
265 ts
.tv_nsec
= time
.tv_usec
* 1000;
267 if (mutex
->recursive
)
269 private_r_mutex_t
* recursive
= (private_r_mutex_t
*)mutex
;
271 recursive
->thread
= 0;
272 timed_out
= pthread_cond_timedwait(&this->condvar
, &mutex
->mutex
,
274 recursive
->thread
= pthread_self();
278 timed_out
= pthread_cond_timedwait(&this->condvar
, &mutex
->mutex
,
285 * Implementation of condvar_t.timed_wait.
287 static bool timed_wait(private_condvar_t
*this, private_mutex_t
*mutex
,
299 tv
.tv_usec
+= ms
* 1000;
301 if (tv
.tv_usec
> 1000000 /* 1s */)
303 tv
.tv_usec
-= 1000000;
306 return timed_wait_abs(this, mutex
, tv
);
310 * Implementation of condvar_t.signal.
312 static void _signal(private_condvar_t
*this)
314 pthread_cond_signal(&this->condvar
);
318 * Implementation of condvar_t.broadcast.
320 static void broadcast(private_condvar_t
*this)
322 pthread_cond_broadcast(&this->condvar
);
326 * Implementation of condvar_t.destroy
328 static void condvar_destroy(private_condvar_t
*this)
330 pthread_cond_destroy(&this->condvar
);
337 condvar_t
*condvar_create(condvar_type_t type
)
341 case CONDVAR_TYPE_DEFAULT
:
344 private_condvar_t
*this = malloc_thing(private_condvar_t
);
346 this->public.wait
= (void(*)(condvar_t
*, mutex_t
*mutex
))_wait
;
347 this->public.timed_wait
= (bool(*)(condvar_t
*, mutex_t
*mutex
, u_int timeout
))timed_wait
;
348 this->public.timed_wait_abs
= (bool(*)(condvar_t
*, mutex_t
*mutex
, timeval_t time
))timed_wait_abs
;
349 this->public.signal
= (void(*)(condvar_t
*))_signal
;
350 this->public.broadcast
= (void(*)(condvar_t
*))broadcast
;
351 this->public.destroy
= (void(*)(condvar_t
*))condvar_destroy
;
353 #ifdef HAVE_PTHREAD_CONDATTR_INIT
355 pthread_condattr_t condattr
;
356 pthread_condattr_init(&condattr
);
357 #ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
358 pthread_condattr_setclock(&condattr
, CLOCK_MONOTONIC
);
360 pthread_cond_init(&this->condvar
, &condattr
);
361 pthread_condattr_destroy(&condattr
);
365 return &this->public;