wrapped rwlock with profiling support
This commit is contained in:
+157
-65
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include <library.h>
|
#include <library.h>
|
||||||
#include <debug.h>
|
#include <debug.h>
|
||||||
#include <utils/backtrace.h>
|
|
||||||
|
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@@ -27,14 +26,77 @@
|
|||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
typedef struct private_mutex_t private_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)
|
* Do not report mutexes with an overall waiting time smaller than this (in us)
|
||||||
*/
|
*/
|
||||||
#define PROFILE_TRESHHOLD 1000
|
#define PROFILE_TRESHHOLD 1000
|
||||||
|
|
||||||
typedef struct private_mutex_t private_mutex_t;
|
#include <utils/backtrace.h>
|
||||||
typedef struct private_r_mutex_t private_r_mutex_t;
|
|
||||||
typedef struct private_condvar_t private_condvar_t;
|
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
|
* private data of mutex
|
||||||
@@ -51,22 +113,15 @@ struct private_mutex_t {
|
|||||||
*/
|
*/
|
||||||
pthread_mutex_t mutex;
|
pthread_mutex_t mutex;
|
||||||
|
|
||||||
#ifdef LOCK_PROFILER
|
|
||||||
/**
|
|
||||||
* 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;
|
|
||||||
#endif /* LOCK_PROFILER */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* is this a recursiv emutex, implementing private_r_mutex_t?
|
* is this a recursiv emutex, implementing private_r_mutex_t?
|
||||||
*/
|
*/
|
||||||
bool recursive;
|
bool recursive;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* profiling info, if enabled
|
||||||
|
*/
|
||||||
|
lock_profile_t profile;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -106,65 +161,39 @@ struct private_condvar_t {
|
|||||||
pthread_cond_t condvar;
|
pthread_cond_t condvar;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef LOCK_PROFILER
|
|
||||||
/**
|
/**
|
||||||
* Print and cleanup mutex profiler
|
* private data of rwlock
|
||||||
*/
|
*/
|
||||||
static void profiler_cleanup(private_mutex_t *this)
|
struct private_rwlock_t {
|
||||||
{
|
|
||||||
if (this->waited.tv_sec > 0 ||
|
|
||||||
this->waited.tv_usec > PROFILE_TRESHHOLD)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "waited %d.%06ds in mutex, created at:",
|
|
||||||
this->waited.tv_sec, this->waited.tv_usec);
|
|
||||||
this->backtrace->log(this->backtrace, stderr);
|
|
||||||
}
|
|
||||||
this->backtrace->destroy(this->backtrace);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize mutex profiler
|
* public functions
|
||||||
*/
|
*/
|
||||||
static void profiler_init(private_mutex_t *this)
|
rwlock_t public;
|
||||||
{
|
|
||||||
this->backtrace = backtrace_create(3);
|
/**
|
||||||
timerclear(&this->waited);
|
* wrapped pthread rwlock
|
||||||
}
|
*/
|
||||||
|
pthread_rwlock_t rwlock;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* profiling info, if enabled
|
||||||
|
*/
|
||||||
|
lock_profile_t profile;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of mutex_t.lock.
|
* Implementation of mutex_t.lock.
|
||||||
*/
|
*/
|
||||||
static void lock(private_mutex_t *this)
|
static void lock(private_mutex_t *this)
|
||||||
{
|
{
|
||||||
struct timeval start, end, diff;
|
profiler_start(&this->profile);
|
||||||
|
|
||||||
gettimeofday(&start, NULL);
|
|
||||||
if (pthread_mutex_lock(&this->mutex))
|
if (pthread_mutex_lock(&this->mutex))
|
||||||
{
|
{
|
||||||
DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", "");
|
DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", "");
|
||||||
}
|
}
|
||||||
gettimeofday(&end, NULL);
|
profiler_end(&this->profile);
|
||||||
|
|
||||||
timersub(&end, &start, &diff);
|
|
||||||
timeradd(&this->waited, &diff, &this->waited);
|
|
||||||
}
|
}
|
||||||
#else /* !LOCK_PROFILER */
|
|
||||||
|
|
||||||
/** dummy implementations */
|
|
||||||
static void profiler_cleanup(private_mutex_t *this) {}
|
|
||||||
static void profiler_init(private_mutex_t *this) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Implementation of mutex_t.lock.
|
|
||||||
*/
|
|
||||||
static void lock(private_mutex_t *this)
|
|
||||||
{
|
|
||||||
if (pthread_mutex_lock(&this->mutex))
|
|
||||||
{
|
|
||||||
DBG1("!!!! MUTEX %sLOCK ERROR, your code is buggy !!!", "");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif /* LOCK_PROFILER */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implementation of mutex_t.unlock.
|
* Implementation of mutex_t.unlock.
|
||||||
@@ -224,7 +253,7 @@ static void unlock_r(private_r_mutex_t *this)
|
|||||||
*/
|
*/
|
||||||
static void mutex_destroy(private_mutex_t *this)
|
static void mutex_destroy(private_mutex_t *this)
|
||||||
{
|
{
|
||||||
profiler_cleanup(this);
|
profiler_cleanup(&this->profile);
|
||||||
pthread_mutex_destroy(&this->mutex);
|
pthread_mutex_destroy(&this->mutex);
|
||||||
free(this);
|
free(this);
|
||||||
}
|
}
|
||||||
@@ -234,7 +263,7 @@ static void mutex_destroy(private_mutex_t *this)
|
|||||||
*/
|
*/
|
||||||
static void mutex_destroy_r(private_r_mutex_t *this)
|
static void mutex_destroy_r(private_r_mutex_t *this)
|
||||||
{
|
{
|
||||||
profiler_cleanup(&this->generic);
|
profiler_cleanup(&this->generic.profile);
|
||||||
pthread_mutex_destroy(&this->generic.mutex);
|
pthread_mutex_destroy(&this->generic.mutex);
|
||||||
pthread_key_delete(this->times);
|
pthread_key_delete(this->times);
|
||||||
free(this);
|
free(this);
|
||||||
@@ -258,7 +287,7 @@ mutex_t *mutex_create(mutex_type_t type)
|
|||||||
pthread_mutex_init(&this->generic.mutex, NULL);
|
pthread_mutex_init(&this->generic.mutex, NULL);
|
||||||
pthread_key_create(&this->times, NULL);
|
pthread_key_create(&this->times, NULL);
|
||||||
this->generic.recursive = TRUE;
|
this->generic.recursive = TRUE;
|
||||||
profiler_init(&this->generic);
|
profiler_init(&this->generic.profile);
|
||||||
this->thread = 0;
|
this->thread = 0;
|
||||||
|
|
||||||
return &this->generic.public;
|
return &this->generic.public;
|
||||||
@@ -274,7 +303,7 @@ mutex_t *mutex_create(mutex_type_t type)
|
|||||||
|
|
||||||
pthread_mutex_init(&this->mutex, NULL);
|
pthread_mutex_init(&this->mutex, NULL);
|
||||||
this->recursive = FALSE;
|
this->recursive = FALSE;
|
||||||
profiler_init(this);
|
profiler_init(&this->profile);
|
||||||
|
|
||||||
return &this->public;
|
return &this->public;
|
||||||
}
|
}
|
||||||
@@ -391,3 +420,66 @@ 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.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.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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,8 +23,10 @@
|
|||||||
|
|
||||||
typedef struct mutex_t mutex_t;
|
typedef struct mutex_t mutex_t;
|
||||||
typedef struct condvar_t condvar_t;
|
typedef struct condvar_t condvar_t;
|
||||||
|
typedef struct rwlock_t rwlock_t;
|
||||||
typedef enum mutex_type_t mutex_type_t;
|
typedef enum mutex_type_t mutex_type_t;
|
||||||
typedef enum condvar_type_t condvar_type_t;
|
typedef enum condvar_type_t condvar_type_t;
|
||||||
|
typedef enum rwlock_type_t rwlock_type_t;
|
||||||
|
|
||||||
#include <library.h>
|
#include <library.h>
|
||||||
|
|
||||||
@@ -46,6 +48,14 @@ enum condvar_type_t {
|
|||||||
CONDVAR_DEFAULT = 0,
|
CONDVAR_DEFAULT = 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of read-write lock.
|
||||||
|
*/
|
||||||
|
enum rwlock_type_t {
|
||||||
|
/** default condvar */
|
||||||
|
RWLOCK_DEFAULT = 0,
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mutex wrapper implements simple, portable and advanced mutex functions.
|
* Mutex wrapper implements simple, portable and advanced mutex functions.
|
||||||
*/
|
*/
|
||||||
@@ -104,6 +114,32 @@ struct condvar_t {
|
|||||||
void (*destroy)(condvar_t *this);
|
void (*destroy)(condvar_t *this);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read-Write lock wrapper.
|
||||||
|
*/
|
||||||
|
struct rwlock_t {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire the read lock.
|
||||||
|
*/
|
||||||
|
void (*read_lock)(rwlock_t *this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Acquire the write lock.
|
||||||
|
*/
|
||||||
|
void (*write_lock)(rwlock_t *this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Release any acquired lock.
|
||||||
|
*/
|
||||||
|
void (*unlock)(rwlock_t *this);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroy the read-write lock.
|
||||||
|
*/
|
||||||
|
void (*destroy)(rwlock_t *this);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a mutex instance.
|
* Create a mutex instance.
|
||||||
*
|
*
|
||||||
@@ -120,4 +156,12 @@ mutex_t *mutex_create(mutex_type_t type);
|
|||||||
*/
|
*/
|
||||||
condvar_t *condvar_create(condvar_type_t type);
|
condvar_t *condvar_create(condvar_type_t type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a read-write lock instance.
|
||||||
|
*
|
||||||
|
* @param type type of rwlock to create
|
||||||
|
* @return unlocked rwlock instance
|
||||||
|
*/
|
||||||
|
rwlock_t *rwlock_create(rwlock_type_t type);
|
||||||
|
|
||||||
#endif /* MUTEX_H_ @}*/
|
#endif /* MUTEX_H_ @}*/
|
||||||
|
|||||||
Reference in New Issue
Block a user