2004-07-04 00:46:49 +00:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
|
2004-07-06 01:22:18 +00:00
|
|
|
#include <config.h>
|
2004-07-04 00:46:49 +00:00
|
|
|
#include <lladd/common.h>
|
|
|
|
|
2004-07-06 01:22:18 +00:00
|
|
|
#include "latches.h"
|
2004-07-04 00:46:49 +00:00
|
|
|
|
2004-07-06 01:22:18 +00:00
|
|
|
#include <pbl/pbl.h>
|
|
|
|
#include <errno.h>
|
2004-07-04 00:46:49 +00:00
|
|
|
|
|
|
|
#undef pthread_mutex_t
|
|
|
|
#undef pthread_mutex_init
|
|
|
|
#undef pthread_mutex_destroy
|
|
|
|
#undef pthread_mutex_lock
|
|
|
|
#undef pthread_mutex_trylock
|
|
|
|
#undef pthread_mutex_unlock
|
2004-07-20 00:15:17 +00:00
|
|
|
#undef pthread_cond_timedwait
|
|
|
|
#undef pthread_cond_wait
|
2004-07-04 00:46:49 +00:00
|
|
|
|
|
|
|
int __lladd_pthread_mutex_init(lladd_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr,
|
|
|
|
const char * file, int line, const char * name) {
|
|
|
|
|
|
|
|
mutex->file = file;
|
|
|
|
mutex->line = line;
|
|
|
|
mutex->name = name;
|
|
|
|
|
|
|
|
init_tuple(&(mutex->tup));
|
|
|
|
|
|
|
|
mutex->lockpoints = pblHtCreate();
|
|
|
|
|
|
|
|
return pthread_mutex_init(&(mutex->mutex), mutexattr);
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
int __lladd_pthread_mutex_lock(lladd_pthread_mutex_t *mutex, char * file, int line) {
|
|
|
|
long blockCount = 0;
|
|
|
|
int ret;
|
|
|
|
char * location;
|
|
|
|
int location_length = asprintf(&location, "%s %d", file, line);
|
|
|
|
|
2004-07-06 01:22:18 +00:00
|
|
|
/* DEBUG("Acquire mutex: %s %d\n", file, line);*/
|
|
|
|
|
2004-07-04 00:46:49 +00:00
|
|
|
while(EBUSY == (ret = pthread_mutex_trylock(&(mutex->mutex)))) {
|
|
|
|
blockCount ++;
|
|
|
|
pthread_yield();
|
2004-07-06 01:22:18 +00:00
|
|
|
|
2004-07-20 00:15:17 +00:00
|
|
|
if(blockCount >= 10000 && ! (blockCount % 10000)) {
|
|
|
|
DEBUG("Spinning at %s:%d, %ld times. Held by: %s\n", file, line, blockCount, mutex->last_acquired_at);
|
2004-07-06 01:22:18 +00:00
|
|
|
}
|
|
|
|
|
2004-07-04 00:46:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
profile_tuple * tup = pblHtLookup(mutex->lockpoints, location, location_length+1);
|
|
|
|
|
|
|
|
mutex->last_acquired_at = location;
|
|
|
|
|
|
|
|
if(!tup) {
|
|
|
|
tup = malloc(sizeof(profile_tuple));
|
|
|
|
|
|
|
|
init_tuple(tup);
|
|
|
|
|
|
|
|
pblHtInsert(mutex->lockpoints, location, location_length+1, tup);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
acquired_lock(&(mutex->tup), blockCount);
|
|
|
|
acquired_lock(tup, blockCount);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
int __lladd_pthread_mutex_unlock(lladd_pthread_mutex_t *mutex) {
|
|
|
|
|
|
|
|
profile_tuple * tup = pblHtLookup(mutex->lockpoints, mutex->last_acquired_at, strlen(mutex->last_acquired_at)+1);
|
|
|
|
|
|
|
|
released_lock(tup);
|
|
|
|
released_lock(&(mutex->tup));
|
|
|
|
|
|
|
|
free(mutex->last_acquired_at);
|
|
|
|
|
|
|
|
return pthread_mutex_unlock(&(mutex->mutex));
|
|
|
|
|
|
|
|
}
|
|
|
|
int __lladd_pthread_mutex_destroy(lladd_pthread_mutex_t *mutex) {
|
|
|
|
|
|
|
|
/* Dump profiling info to stdout */
|
|
|
|
|
|
|
|
profile_tuple * tup;
|
|
|
|
|
|
|
|
printf("Free mutex %s Init: %s %d\n ", mutex->name, mutex->file, mutex->line);
|
|
|
|
print_profile_tuple(&(mutex->tup));
|
|
|
|
printf("\n Lock points: [mean, stddev, max] \n");
|
|
|
|
|
|
|
|
/* Now, iterate over all of the lockpoints: */
|
|
|
|
|
|
|
|
for(tup = pblHtFirst(mutex->lockpoints); tup; tup = pblHtNext(mutex->lockpoints)) {
|
|
|
|
printf("\t%s ", (char*)pblHtCurrentKey(mutex->lockpoints));
|
|
|
|
print_profile_tuple(tup);
|
|
|
|
printf("\n");
|
|
|
|
free(tup);
|
|
|
|
}
|
|
|
|
|
|
|
|
pblHtDelete(mutex->lockpoints);
|
|
|
|
|
|
|
|
|
|
|
|
return pthread_mutex_destroy(&(mutex->mutex));
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2004-07-20 00:15:17 +00:00
|
|
|
/**
|
|
|
|
@todo The profiled version of pthread_cond_wait isn't really implemented, so it throws off the mutex statistics.
|
|
|
|
*/
|
|
|
|
int __lladd_pthread_cond_wait(pthread_cond_t *cond, lladd_pthread_mutex_t *mutex,
|
|
|
|
char * file, int line, char * cond_name, char * mutex_name) {
|
2004-07-20 03:40:57 +00:00
|
|
|
int ret;
|
|
|
|
char * location;
|
|
|
|
int location_length;
|
|
|
|
|
|
|
|
profile_tuple * tup = pblHtLookup(mutex->lockpoints, mutex->last_acquired_at, strlen(mutex->last_acquired_at)+1);
|
|
|
|
|
|
|
|
released_lock(tup);
|
|
|
|
released_lock(&(mutex->tup));
|
|
|
|
|
|
|
|
free(mutex->last_acquired_at);
|
|
|
|
|
|
|
|
ret = pthread_cond_wait(cond, &mutex->mutex);
|
|
|
|
|
|
|
|
location_length = asprintf(&location, "%s %d", file, line);
|
|
|
|
|
|
|
|
tup = pblHtLookup(mutex->lockpoints, location, location_length+1);
|
|
|
|
|
|
|
|
mutex->last_acquired_at = location;
|
|
|
|
|
|
|
|
if(!tup) {
|
|
|
|
tup = malloc(sizeof(profile_tuple));
|
|
|
|
|
|
|
|
init_tuple(tup);
|
|
|
|
|
|
|
|
pblHtInsert(mutex->lockpoints, location, location_length+1, tup);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
acquired_lock(&(mutex->tup), 0);
|
|
|
|
acquired_lock(tup, 0);
|
|
|
|
|
|
|
|
return ret;
|
2004-07-20 00:15:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int __lladd_pthread_cond_timedwait(pthread_cond_t *cond, lladd_pthread_mutex_t *mutex, void *abstime,
|
|
|
|
char * file, int line, char * cond_name, char * mutex_name) {
|
|
|
|
return pthread_cond_timedwait(cond, &mutex->mutex, abstime);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2004-07-04 00:46:49 +00:00
|
|
|
#undef rwl
|
|
|
|
#undef initlock
|
|
|
|
#undef readlock
|
|
|
|
#undef writelock
|
|
|
|
#undef readunlock
|
|
|
|
#undef writeunlock
|
|
|
|
#undef deletelock
|
2004-07-20 00:15:17 +00:00
|
|
|
#undef unlock
|
|
|
|
#undef downgradelock
|
2004-07-04 00:46:49 +00:00
|
|
|
|
|
|
|
__profile_rwl *__profile_rw_initlock (char * file, int line) {
|
|
|
|
__profile_rwl * ret = malloc(sizeof(__profile_rwl));
|
|
|
|
|
|
|
|
ret->file = file;
|
|
|
|
ret->line = line;
|
|
|
|
|
|
|
|
init_tuple(&(ret->tup));
|
|
|
|
|
|
|
|
ret->lockpoints = pblHtCreate();
|
|
|
|
|
|
|
|
ret->lock = initlock();
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
/*static pthread_mutex_t __profile_rwl_mutex = PTHREAD_MUTEX_INITIALIZER;*/
|
|
|
|
|
|
|
|
/**
|
|
|
|
@todo For now, we only profile write locks...
|
|
|
|
*/
|
|
|
|
void __profile_readlock (__profile_rwl *lock, int d, char * file, int line) {
|
2004-07-06 01:22:18 +00:00
|
|
|
|
|
|
|
/* DEBUG("Read lock: %s %d\n", file, line); */
|
|
|
|
|
2004-07-04 00:46:49 +00:00
|
|
|
readlock(lock->lock, d);
|
|
|
|
|
2004-07-20 00:15:17 +00:00
|
|
|
|
2004-07-04 00:46:49 +00:00
|
|
|
}
|
|
|
|
void __profile_writelock (__profile_rwl *lock, int d, char * file, int line) {
|
|
|
|
|
|
|
|
char * location;
|
|
|
|
int location_length = asprintf(&location, "write %s %d", file, line);
|
|
|
|
|
|
|
|
profile_tuple * tup;
|
|
|
|
|
2004-07-06 01:22:18 +00:00
|
|
|
/* DEBUG("Write lock: %s %d\n", file, line); */
|
|
|
|
|
|
|
|
|
2004-07-04 00:46:49 +00:00
|
|
|
/** @todo Should we spin instead of using the more efficient rwl
|
|
|
|
implementation, or should we see how many times we were woken
|
|
|
|
before obtaining the lock? */
|
|
|
|
|
|
|
|
writelock(lock->lock, d);
|
|
|
|
|
|
|
|
/* pthread_mutex_lock(__profile_rwl_mutex); */
|
|
|
|
|
|
|
|
tup = pblHtLookup(lock->lockpoints, location, location_length+1);
|
|
|
|
|
|
|
|
lock->last_acquired_at = location;
|
|
|
|
|
|
|
|
if(!tup) {
|
|
|
|
tup = malloc(sizeof(profile_tuple));
|
|
|
|
|
|
|
|
init_tuple(tup);
|
|
|
|
|
|
|
|
pblHtInsert(lock->lockpoints, location, location_length+1, tup);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
acquired_lock(&(lock->tup), -1);
|
|
|
|
acquired_lock(tup, -1);
|
|
|
|
|
|
|
|
/* pthread_mutex_unlock(__profile_rwl_mutex);*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
void __profile_readunlock (__profile_rwl *lock) {
|
|
|
|
|
|
|
|
readunlock(lock->lock);
|
|
|
|
|
|
|
|
}
|
|
|
|
void __profile_writeunlock (__profile_rwl *lock) {
|
|
|
|
|
|
|
|
profile_tuple * tup = pblHtLookup(lock->lockpoints, lock->last_acquired_at, strlen(lock->last_acquired_at)+1);
|
|
|
|
|
|
|
|
released_lock(tup);
|
|
|
|
released_lock(&(lock->tup));
|
|
|
|
|
|
|
|
free(lock->last_acquired_at);
|
|
|
|
|
|
|
|
writeunlock(lock->lock);
|
|
|
|
|
|
|
|
}
|
2004-07-20 00:15:17 +00:00
|
|
|
|
|
|
|
void __profile_unlock (__profile_rwl * lock) {
|
|
|
|
if(lock->lock->writers) {
|
|
|
|
__profile_writeunlock(lock);
|
|
|
|
} else {
|
|
|
|
__profile_readunlock(lock);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void __profile_downgradelock (__profile_rwl * lock) {
|
|
|
|
profile_tuple * tup = pblHtLookup(lock->lockpoints, lock->last_acquired_at, strlen(lock->last_acquired_at)+1);
|
|
|
|
|
|
|
|
released_lock(tup);
|
|
|
|
released_lock(&(lock->tup));
|
|
|
|
|
|
|
|
free(lock->last_acquired_at);
|
|
|
|
|
|
|
|
downgradelock(lock->lock);
|
|
|
|
}
|
|
|
|
|
2004-07-04 00:46:49 +00:00
|
|
|
void __profile_deletelock (__profile_rwl *lock) {
|
|
|
|
|
|
|
|
profile_tuple * tup;
|
|
|
|
|
|
|
|
printf("Free rwl init: %s %d\n ", lock->file, lock->line);
|
|
|
|
print_profile_tuple(&(lock->tup));
|
|
|
|
printf("\n Lock points: [mean, stddev, max] \n");
|
|
|
|
|
|
|
|
for(tup = pblHtFirst(lock->lockpoints); tup; tup = pblHtNext(lock->lockpoints)) {
|
|
|
|
printf("\t%s ", (char*)pblHtCurrentKey(lock->lockpoints));
|
|
|
|
print_profile_tuple(tup);
|
|
|
|
printf("\n");
|
|
|
|
free(tup);
|
|
|
|
}
|
|
|
|
|
|
|
|
pblHtDelete(lock->lockpoints);
|
|
|
|
|
|
|
|
deletelock(lock->lock);
|
|
|
|
}
|
|
|
|
|