From 2db1ef4ac8928944958712923b9c89c263a337d2 Mon Sep 17 00:00:00 2001 From: Rene Mayrhofer Date: Fri, 5 Dec 2008 16:44:41 +0000 Subject: - Updated to new upstream. --- src/libstrongswan/utils/mutex.c | 280 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 254 insertions(+), 26 deletions(-) (limited to 'src/libstrongswan/utils/mutex.c') diff --git a/src/libstrongswan/utils/mutex.c b/src/libstrongswan/utils/mutex.c index 425389b4f..ddb0d2df6 100644 --- a/src/libstrongswan/utils/mutex.c +++ b/src/libstrongswan/utils/mutex.c @@ -12,24 +12,92 @@ * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * for more details. * - * $Id: mutex.c 3589 2008-03-13 14:14:44Z martin $ + * $Id: mutex.c 4591 2008-11-05 16:12:54Z martin $ */ -#include "mutex.h" - -#include -#include - +#define _GNU_SOURCE #include #include +#include #include #include +#include "mutex.h" + +#include +#include typedef struct private_mutex_t private_mutex_t; -typedef struct private_n_mutex_t private_n_mutex_t; typedef struct private_r_mutex_t private_r_mutex_t; typedef struct private_condvar_t private_condvar_t; +typedef struct private_rwlock_t private_rwlock_t; + +#ifdef LOCK_PROFILER + +/** + * Do not report mutexes with an overall waiting time smaller than this (in us) + */ +#define PROFILE_TRESHHOLD 1000 + +#include + +typedef struct lock_profile_t lock_profile_t; + +struct lock_profile_t { + + /** + * how long threads have waited for the lock in this mutex so far + */ + struct timeval waited; + + /** + * backtrace where mutex has been created + */ + backtrace_t *backtrace; +}; + +/** + * Print and cleanup mutex profiler + */ +static void profiler_cleanup(lock_profile_t *profile) +{ + if (profile->waited.tv_sec > 0 || + profile->waited.tv_usec > PROFILE_TRESHHOLD) + { + fprintf(stderr, "%d.%06ds in lock created at:", + profile->waited.tv_sec, profile->waited.tv_usec); + profile->backtrace->log(profile->backtrace, stderr); + } + profile->backtrace->destroy(profile->backtrace); +} + +/** + * Initialize mutex profiler + */ +static void profiler_init(lock_profile_t *profile) +{ + profile->backtrace = backtrace_create(3); + timerclear(&profile->waited); +} + +#define profiler_start(profile) { \ + struct timeval _start, _end, _diff; \ + gettimeofday(&_start, NULL); + +#define profiler_end(profile) \ + gettimeofday(&_end, NULL); \ + timersub(&_end, &_start, &_diff); \ + timeradd(&(profile)->waited, &_diff, &(profile)->waited); } + +#else /* !LOCK_PROFILER */ + +#define lock_profile_t struct {} +#define profiler_cleanup(...) {} +#define profiler_init(...) {} +#define profiler_start(...) {} +#define profiler_end(...) {} + +#endif /* LOCK_PROFILER */ /** * private data of mutex @@ -45,6 +113,16 @@ struct private_mutex_t { * wrapped pthread mutex */ pthread_mutex_t mutex; + + /** + * is this a recursiv emutex, implementing private_r_mutex_t? + */ + bool recursive; + + /** + * profiling info, if enabled + */ + lock_profile_t profile; }; /** @@ -53,7 +131,7 @@ struct private_mutex_t { struct private_r_mutex_t { /** - * public functions + * Extends private_mutex_t */ private_mutex_t generic; @@ -63,9 +141,9 @@ struct private_r_mutex_t { pthread_t thread; /** - * times we have locked the lock + * times we have locked the lock, stored per thread */ - int times; + pthread_key_t times; }; /** @@ -84,15 +162,38 @@ struct private_condvar_t { pthread_cond_t condvar; }; +/** + * private data of rwlock + */ +struct private_rwlock_t { + + /** + * public functions + */ + rwlock_t public; + + /** + * wrapped pthread rwlock + */ + pthread_rwlock_t rwlock; + + /** + * profiling info, if enabled + */ + lock_profile_t profile; +}; + /** * Implementation of mutex_t.lock. */ static void lock(private_mutex_t *this) { + profiler_start(&this->profile); if (pthread_mutex_lock(&this->mutex)) { DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", ""); } + profiler_end(&this->profile); } /** @@ -115,12 +216,19 @@ static void lock_r(private_r_mutex_t *this) if (this->thread == self) { - this->times++; - return; + uintptr_t times; + + /* times++ */ + times = (uintptr_t)pthread_getspecific(this->times); + pthread_setspecific(this->times, (void*)times + 1); + } + else + { + lock(&this->generic); + this->thread = self; + /* times = 1 */ + pthread_setspecific(this->times, (void*)1); } - lock(&this->generic); - this->thread = self; - this->times = 1; } /** @@ -128,7 +236,13 @@ static void lock_r(private_r_mutex_t *this) */ static void unlock_r(private_r_mutex_t *this) { - if (--this->times == 0) + uintptr_t times; + + /* times-- */ + times = (uintptr_t)pthread_getspecific(this->times); + pthread_setspecific(this->times, (void*)--times); + + if (times == 0) { this->thread = 0; unlock(&this->generic); @@ -140,10 +254,22 @@ static void unlock_r(private_r_mutex_t *this) */ static void mutex_destroy(private_mutex_t *this) { + profiler_cleanup(&this->profile); pthread_mutex_destroy(&this->mutex); free(this); } +/** + * Implementation of mutex_t.destroy for recursive mutex' + */ +static void mutex_destroy_r(private_r_mutex_t *this) +{ + profiler_cleanup(&this->generic.profile); + pthread_mutex_destroy(&this->generic.mutex); + pthread_key_delete(this->times); + free(this); +} + /* * see header file */ @@ -154,15 +280,17 @@ mutex_t *mutex_create(mutex_type_t type) case MUTEX_RECURSIVE: { private_r_mutex_t *this = malloc_thing(private_r_mutex_t); - + this->generic.public.lock = (void(*)(mutex_t*))lock_r; this->generic.public.unlock = (void(*)(mutex_t*))unlock_r; - this->generic.public.destroy = (void(*)(mutex_t*))mutex_destroy; - + this->generic.public.destroy = (void(*)(mutex_t*))mutex_destroy_r; + pthread_mutex_init(&this->generic.mutex, NULL); + pthread_key_create(&this->times, NULL); + this->generic.recursive = TRUE; + profiler_init(&this->generic.profile); this->thread = 0; - this->times = 0; - + return &this->generic.public; } case MUTEX_DEFAULT: @@ -173,9 +301,11 @@ mutex_t *mutex_create(mutex_type_t type) this->public.lock = (void(*)(mutex_t*))lock; this->public.unlock = (void(*)(mutex_t*))unlock; this->public.destroy = (void(*)(mutex_t*))mutex_destroy; - + pthread_mutex_init(&this->mutex, NULL); - + this->recursive = FALSE; + profiler_init(&this->profile); + return &this->public; } } @@ -186,7 +316,19 @@ mutex_t *mutex_create(mutex_type_t type) */ static void wait(private_condvar_t *this, private_mutex_t *mutex) { - pthread_cond_wait(&this->condvar, &mutex->mutex); + if (mutex->recursive) + { + private_r_mutex_t* recursive = (private_r_mutex_t*)mutex; + + /* mutex owner gets cleared during condvar wait */ + recursive->thread = 0; + pthread_cond_wait(&this->condvar, &mutex->mutex); + recursive->thread = pthread_self(); + } + else + { + pthread_cond_wait(&this->condvar, &mutex->mutex); + } } /** @@ -198,6 +340,7 @@ static bool timed_wait(private_condvar_t *this, private_mutex_t *mutex, struct timespec ts; struct timeval tv; u_int s, ms; + bool timed_out; gettimeofday(&tv, NULL); @@ -211,8 +354,21 @@ static bool timed_wait(private_condvar_t *this, private_mutex_t *mutex, ts.tv_nsec -= 1000000000; ts.tv_sec++; } - return (pthread_cond_timedwait(&this->condvar, &mutex->mutex, - &ts) == ETIMEDOUT); + if (mutex->recursive) + { + private_r_mutex_t* recursive = (private_r_mutex_t*)mutex; + + recursive->thread = 0; + timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex, + &ts) == ETIMEDOUT; + recursive->thread = pthread_self(); + } + else + { + timed_out = pthread_cond_timedwait(&this->condvar, &mutex->mutex, + &ts) == ETIMEDOUT; + } + return timed_out; } /** @@ -265,3 +421,75 @@ condvar_t *condvar_create(condvar_type_t type) } } +/** + * Implementation of rwlock_t.read_lock + */ +static void read_lock(private_rwlock_t *this) +{ + profiler_start(&this->profile); + pthread_rwlock_rdlock(&this->rwlock); + profiler_end(&this->profile); +} + +/** + * Implementation of rwlock_t.write_lock + */ +static void write_lock(private_rwlock_t *this) +{ + profiler_start(&this->profile); + pthread_rwlock_wrlock(&this->rwlock); + profiler_end(&this->profile); +} + +/** + * Implementation of rwlock_t.try_write_lock + */ +static bool try_write_lock(private_rwlock_t *this) +{ + return pthread_rwlock_trywrlock(&this->rwlock) == 0; +} + +/** + * Implementation of rwlock_t.unlock + */ +static void rw_unlock(private_rwlock_t *this) +{ + pthread_rwlock_unlock(&this->rwlock); +} + +/** + * Implementation of rwlock_t.destroy + */ +static void rw_destroy(private_rwlock_t *this) +{ + pthread_rwlock_destroy(&this->rwlock); + profiler_cleanup(&this->profile); + free(this); +} + +/* + * see header file + */ +rwlock_t *rwlock_create(rwlock_type_t type) +{ + switch (type) + { + case RWLOCK_DEFAULT: + default: + { + private_rwlock_t *this = malloc_thing(private_rwlock_t); + + this->public.read_lock = (void(*)(rwlock_t*))read_lock; + this->public.write_lock = (void(*)(rwlock_t*))write_lock; + this->public.try_write_lock = (bool(*)(rwlock_t*))try_write_lock; + this->public.unlock = (void(*)(rwlock_t*))rw_unlock; + this->public.destroy = (void(*)(rwlock_t*))rw_destroy; + + pthread_rwlock_init(&this->rwlock, NULL); + profiler_init(&this->profile); + + return &this->public; + } + } +} + -- cgit v1.2.3