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
;
99 METHOD(mutex_t
, lock
, void,
100 private_mutex_t
*this)
104 profiler_start(&this->profile
);
105 err
= pthread_mutex_lock(&this->mutex
);
108 DBG1(DBG_LIB
, "!!! MUTEX LOCK ERROR: %s !!!", strerror(err
));
110 profiler_end(&this->profile
);
113 METHOD(mutex_t
, unlock
, void,
114 private_mutex_t
*this)
118 err
= pthread_mutex_unlock(&this->mutex
);
121 DBG1(DBG_LIB
, "!!! MUTEX UNLOCK ERROR: %s !!!", strerror(err
));
125 METHOD(mutex_t
, lock_r
, void,
126 private_r_mutex_t
*this)
128 pthread_t self
= pthread_self();
130 if (this->thread
== self
)
135 times
= (uintptr_t)pthread_getspecific(this->times
);
136 pthread_setspecific(this->times
, (void*)times
+ 1);
140 lock(&this->generic
);
143 pthread_setspecific(this->times
, (void*)1);
147 METHOD(mutex_t
, unlock_r
, void,
148 private_r_mutex_t
*this)
153 times
= (uintptr_t)pthread_getspecific(this->times
);
154 pthread_setspecific(this->times
, (void*)--times
);
159 unlock(&this->generic
);
163 METHOD(mutex_t
, mutex_destroy
, void,
164 private_mutex_t
*this)
166 profiler_cleanup(&this->profile
);
167 pthread_mutex_destroy(&this->mutex
);
171 METHOD(mutex_t
, mutex_destroy_r
, void,
172 private_r_mutex_t
*this)
174 profiler_cleanup(&this->generic
.profile
);
175 pthread_mutex_destroy(&this->generic
.mutex
);
176 pthread_key_delete(this->times
);
183 mutex_t
*mutex_create(mutex_type_t type
)
187 case MUTEX_TYPE_RECURSIVE
:
189 private_r_mutex_t
*this;
196 .destroy
= _mutex_destroy_r
,
202 pthread_mutex_init(&this->generic
.mutex
, NULL
);
203 pthread_key_create(&this->times
, NULL
);
204 profiler_init(&this->generic
.profile
);
206 return &this->generic
.public;
208 case MUTEX_TYPE_DEFAULT
:
211 private_mutex_t
*this;
217 .destroy
= _mutex_destroy
,
221 pthread_mutex_init(&this->mutex
, NULL
);
222 profiler_init(&this->profile
);
224 return &this->public;
230 METHOD(condvar_t
, wait_
, void,
231 private_condvar_t
*this, private_mutex_t
*mutex
)
233 if (mutex
->recursive
)
235 private_r_mutex_t
* recursive
= (private_r_mutex_t
*)mutex
;
237 /* mutex owner gets cleared during condvar wait */
238 recursive
->thread
= 0;
239 pthread_cond_wait(&this->condvar
, &mutex
->mutex
);
240 recursive
->thread
= pthread_self();
244 pthread_cond_wait(&this->condvar
, &mutex
->mutex
);
248 /* use the monotonic clock based version of this function if available */
249 #ifdef HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC
250 #define pthread_cond_timedwait pthread_cond_timedwait_monotonic
253 METHOD(condvar_t
, timed_wait_abs
, bool,
254 private_condvar_t
*this, private_mutex_t
*mutex
, timeval_t time
)
259 ts
.tv_sec
= time
.tv_sec
;
260 ts
.tv_nsec
= time
.tv_usec
* 1000;
262 if (mutex
->recursive
)
264 private_r_mutex_t
* recursive
= (private_r_mutex_t
*)mutex
;
266 recursive
->thread
= 0;
267 timed_out
= pthread_cond_timedwait(&this->condvar
, &mutex
->mutex
,
269 recursive
->thread
= pthread_self();
273 timed_out
= pthread_cond_timedwait(&this->condvar
, &mutex
->mutex
,
279 METHOD(condvar_t
, timed_wait
, bool,
280 private_condvar_t
*this, private_mutex_t
*mutex
, u_int timeout
)
291 tv
.tv_usec
+= ms
* 1000;
293 if (tv
.tv_usec
> 1000000 /* 1s */)
295 tv
.tv_usec
-= 1000000;
298 return timed_wait_abs(this, mutex
, tv
);
301 METHOD(condvar_t
, signal_
, void,
302 private_condvar_t
*this)
304 pthread_cond_signal(&this->condvar
);
307 METHOD(condvar_t
, broadcast
, void,
308 private_condvar_t
*this)
310 pthread_cond_broadcast(&this->condvar
);
313 METHOD(condvar_t
, condvar_destroy
, void,
314 private_condvar_t
*this)
316 pthread_cond_destroy(&this->condvar
);
323 condvar_t
*condvar_create(condvar_type_t type
)
327 case CONDVAR_TYPE_DEFAULT
:
330 private_condvar_t
*this;
334 .wait
= (void*)_wait_
,
335 .timed_wait
= (void*)_timed_wait
,
336 .timed_wait_abs
= (void*)_timed_wait_abs
,
338 .broadcast
= _broadcast
,
339 .destroy
= _condvar_destroy
,
343 #ifdef HAVE_PTHREAD_CONDATTR_INIT
345 pthread_condattr_t condattr
;
346 pthread_condattr_init(&condattr
);
347 #ifdef HAVE_CONDATTR_CLOCK_MONOTONIC
348 pthread_condattr_setclock(&condattr
, CLOCK_MONOTONIC
);
350 pthread_cond_init(&this->condvar
, &condattr
);
351 pthread_condattr_destroy(&condattr
);
355 return &this->public;