diff options
author | Junyan He <junyan.he@intel.com> | 2016-04-22 16:11:58 +0800 |
---|---|---|
committer | Junyan He <junyan.he@intel.com> | 2016-04-22 16:11:58 +0800 |
commit | caabffe3a38337aadfce6c5c585f5c52ea69a342 (patch) | |
tree | 0bbb41791b6437fda76e8b42e2d4dbfce7ab926a | |
parent | ffbb5ac154757369c91b6d46e397c41e1666cb3d (diff) |
mutex
-rw-r--r-- | libclapi/cl_mutex.c | 200 | ||||
-rw-r--r-- | libclapi/cl_mutex.h | 7 |
2 files changed, 192 insertions, 15 deletions
diff --git a/libclapi/cl_mutex.c b/libclapi/cl_mutex.c index d6237065..ec4795a0 100644 --- a/libclapi/cl_mutex.c +++ b/libclapi/cl_mutex.c @@ -31,22 +31,47 @@ typedef struct _cl_mutex_log_item { struct { char* file; int line; + pthread_t tid; } holder; struct { char* file; int line; + pthread_t tid; } waiter[8]; + struct { + char* file; + int line; + pthread_t tid; + pthread_cond_t* cond; + } sleeper[8]; } _cl_mutex_log_item; typedef struct _cl_mutex_log_item* cl_mutex_log_item; static cl_mutex_log_item* cl_mutex_log_map; static int cl_mutex_log_map_size; +LOCAL void cl_mutex_debug_init(void) +{ + static int inited = 0; + if (inited) + return; + + pthread_mutex_init(&cl_mutex_log_lock, NULL); + + cl_mutex_log_map_size = 128; + cl_mutex_log_map = malloc(cl_mutex_log_map_size*sizeof(cl_mutex_log_item)); + memset(cl_mutex_log_map, 0, cl_mutex_log_map_size*sizeof(cl_mutex_log_item)); + cl_mutex_log_num = 0; + + inited = 1; +} + static int before_get_the_mutex(pthread_mutex_t* mutex, char* file, int line) { int i; int ret = -1; cl_mutex_log_item item = NULL; + pthread_t tid = pthread_self(); pthread_mutex_lock(&cl_mutex_log_lock); for (i = 0; i < cl_mutex_log_map_size; i++) { @@ -74,6 +99,7 @@ static int before_get_the_mutex(pthread_mutex_t* mutex, char* file, int line) memset(item, 0, sizeof(_cl_mutex_log_item)); item->waiter[0].file = file; item->waiter[0].line = line; + item->waiter[0].tid = tid; cl_mutex_log_map[i] = item; ret = 0; cl_mutex_log_num++; @@ -82,6 +108,7 @@ static int before_get_the_mutex(pthread_mutex_t* mutex, char* file, int line) if (item->waiter[i].file == NULL) { item->waiter[i].file = file; item->waiter[i].line = line; + item->waiter[i].tid = tid; ret = i; break; } @@ -93,10 +120,11 @@ static int before_get_the_mutex(pthread_mutex_t* mutex, char* file, int line) return ret; } -static void after_get_the_mutex(pthread_mutex_t* mutex, char* file, int line, int nth) +static void after_get_the_mutex(pthread_mutex_t* mutex, char* file, int line, int nth, int is_from_sleep) { int i; cl_mutex_log_item item = NULL; + pthread_t tid = pthread_self(); pthread_mutex_lock(&cl_mutex_log_lock); for (i = 0; i < cl_mutex_log_map_size; i++) { @@ -109,19 +137,32 @@ static void after_get_the_mutex(pthread_mutex_t* mutex, char* file, int line, in if (nth >= 0) { assert(nth < 8); - item->waiter[nth].file = NULL; - item->waiter[nth].line = 0; - assert(item->waiter[nth].file == file); - assert(item->waiter[nth].line == line); + if (is_from_sleep == 0) { + assert(item->waiter[nth].file == file); + assert(item->waiter[nth].line == line); + assert(item->waiter[nth].tid == tid); + item->waiter[nth].file = NULL; + item->waiter[nth].line = 0; + item->waiter[nth].tid = -1; + } else { + assert(item->sleeper[nth].file == file); + assert(item->sleeper[nth].line == line); + assert(item->sleeper[nth].tid == tid); + item->sleeper[nth].file = NULL; + item->sleeper[nth].line = 0; + item->sleeper[nth].tid = -1; + item->sleeper[nth].cond = NULL; + } } item->holder.file = file; item->holder.line = line; + item->holder.tid = tid; pthread_mutex_unlock(&cl_mutex_log_lock); } -static void before_release_the_mutex(pthread_mutex_t* mutex, char* file, int line, int free_it) +static void before_release_the_mutex(pthread_mutex_t* mutex, char* file, int line) { int i, j; cl_mutex_log_item item = NULL; @@ -151,6 +192,7 @@ static void before_release_the_mutex(pthread_mutex_t* mutex, char* file, int li item->holder.file = NULL; item->holder.line = 0; + item->holder.tid = -1; still_used = 0; for (j = 0; j < 8; j++) { @@ -158,9 +200,13 @@ static void before_release_the_mutex(pthread_mutex_t* mutex, char* file, int li still_used = 1; break; } + if (item->sleeper[j].file != NULL) { + still_used = 1; + break; + } } - if (free_it && still_used == 0) { + if (still_used == 0) { cl_mutex_log_map[i] = NULL; free(item); cl_mutex_log_num--; @@ -169,6 +215,58 @@ static void before_release_the_mutex(pthread_mutex_t* mutex, char* file, int li pthread_mutex_unlock(&cl_mutex_log_lock); } +static int before_sleep_on_the_mutex(pthread_cond_t* cond, pthread_mutex_t* mutex, char* file, int line) +{ + int i; + int ret; + cl_mutex_log_item item = NULL; + pthread_t tid = pthread_self(); + + pthread_mutex_lock(&cl_mutex_log_lock); + for (i = 0; i < cl_mutex_log_map_size; i++) { + if (cl_mutex_log_map[i]->mutex == mutex) { + item = cl_mutex_log_map[i]; + break; + } + } + + if (item == NULL) { + printf("At unlock point file: %s, line: %d, we can not find the locked mutex:%p item, fatal\n", + file, line, mutex); + assert(0); + return -1; + } + + if (item->holder.file == NULL) { + printf("At unlock point file: %s, line: %d, we can not find the locked mutex:%p info, fatal\n", + file, line, mutex); + assert(0); + return -1; + } + + assert(item->holder.file == file); + assert(item->holder.line == line); + assert(item->holder.tid == tid); + item->holder.file = NULL; + item->holder.line = 0; + item->holder.tid = -1; + + ret = -1; + for (i = 0; i < 8; i++) { + if (item->sleeper[i].file == NULL) { + item->sleeper[i].file = file; + item->sleeper[i].line = line; + item->sleeper[i].tid = tid; + item->sleeper[i].cond = cond; + ret = i; + break; + } + } + + pthread_mutex_unlock(&cl_mutex_log_lock); + return ret; +} + static int try_to_get_the_mutex(pthread_mutex_t* mutex) { struct timespec abs_time; @@ -187,6 +285,7 @@ static void handle_deadlock(pthread_mutex_t* mutex, char* file, int line) int i; int print_others; int num; + pthread_t tid = pthread_self(); pthread_mutex_lock(&cl_mutex_log_lock); for (i = 0; i < cl_mutex_log_map_size; i++) { @@ -202,8 +301,11 @@ static void handle_deadlock(pthread_mutex_t* mutex, char* file, int line) } else { print_others = 1; printf("We may dead lock at a mutex:%p, call lock point is" - "file: %s, line: %d.\nThe mutex is held by file: %s, line: %d\n", - mutex, file, line, item->holder.file, item->holder.line); + "file: %s, line: %d, thread id is %d.\nThe mutex is held by" + "file: %s, line: %d, thread is is %d\n", + mutex, file, line, (int)tid, item->holder.file, item->holder.line, + (int)item->holder.tid); + for (i = 0; i < 8; i++) { if (item->waiter[i].file) { if (print_others) { @@ -211,7 +313,22 @@ static void handle_deadlock(pthread_mutex_t* mutex, char* file, int line) printf("There are other waiters:\n"); } - printf(" file: %s, line %d\n", item->waiter[i].file, item->waiter[i].line); + printf(" file: %s, line: %d, thread id: %d\n", + item->waiter[i].file, item->waiter[i].line, (int)item->waiter[i].tid); + } + } + + print_others = 0; + for (i = 0; i < 8; i++) { + if (item->sleeper[i].file) { + if (print_others) { + print_others = 0; + printf("There are other sleepers:\n"); + } + + printf(" file: %s, line: %d, thread id: %d, cond: %p\n", + item->sleeper[i].file, item->sleeper[i].line, + (int)item->sleeper[i].tid, item->sleeper[i].cond); } } } @@ -238,26 +355,81 @@ LOCAL void cl_mutex_lock(pthread_mutex_t* mutex, char* file, int line) handle_deadlock(mutex, file, line); } - after_get_the_mutex(mutex, file, line, nth); + after_get_the_mutex(mutex, file, line, nth, 0); } LOCAL void cl_mutex_unlock(pthread_mutex_t* mutex, char* file, int line) { assert(mutex); - before_release_the_mutex(mutex, file, line, 1); + before_release_the_mutex(mutex, file, line); pthread_mutex_unlock(mutex); } LOCAL int cl_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex, char* file, int line) { int ret; + int nth; assert(mutex); assert(cond); - before_release_the_mutex(mutex, file, line, 0); + nth = before_sleep_on_the_mutex(cond, mutex, file, line); ret = pthread_cond_wait(cond, mutex); - after_get_the_mutex(mutex, file, line, -1); + after_get_the_mutex(mutex, file, line, nth, 1); return ret; } +LOCAL int cl_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime, char* file, int line) +{ + int ret; + int nth; + assert(mutex); + assert(cond); + + nth = before_sleep_on_the_mutex(cond, mutex, file, line); + ret = pthread_cond_timedwait(cond, mutex, abstime); + after_get_the_mutex(mutex, file, line, nth, 1); + + return ret; +} + +void cl_mutex_report(void) +{ + int i, j, num; + pthread_mutex_lock(&cl_mutex_log_lock); + if (cl_mutex_log_num == 0) { + pthread_mutex_unlock(&cl_mutex_log_lock); + return; + } + + printf("-------------------------------------------------------------------\n"); + num = 0; + for (i = 0; i < cl_mutex_log_map_size; i++) { + if (cl_mutex_log_map[i]) { + printf("The mutex %p still has users.\n", cl_mutex_log_map[i]->mutex); + if (cl_mutex_log_map[i]->holder.file) { + printf(" Holder: At file:%s, line: %d, thread id is: %d\n", + cl_mutex_log_map[i]->holder.file, cl_mutex_log_map[i]->holder.line, + (int)cl_mutex_log_map[i]->holder.tid); + } + + for (j = 0; j < 8; j++) { + printf(" Waiter: At file:%s, line: %d, thread id is: %d\n", + cl_mutex_log_map[i]->waiter[i].file, cl_mutex_log_map[i]->waiter[i].line, + (int)cl_mutex_log_map[i]->waiter[i].tid); + } + + for (j = 0; j < 8; j++) { + printf(" Sleeper: At file:%s, line: %d, thread id is: %d\n", + cl_mutex_log_map[i]->sleeper[i].file, cl_mutex_log_map[i]->sleeper[i].line, + (int)cl_mutex_log_map[i]->sleeper[i].tid); + } + num++; + } + } + printf("-------------------------------------------------------------------\n"); + assert(num == cl_mutex_log_num); + pthread_mutex_unlock(&cl_mutex_log_lock); +} + diff --git a/libclapi/cl_mutex.h b/libclapi/cl_mutex.h index 21fa44c0..7a5d3714 100644 --- a/libclapi/cl_mutex.h +++ b/libclapi/cl_mutex.h @@ -22,7 +22,8 @@ #include <stdlib.h> #include <pthread.h> -/* Return a valid pointer for the requested memory block size */ +extern void cl_mutex_debug_init(void); + extern void cl_mutex_lock(pthread_mutex_t* mutex, char* file, int line); #define CL_MUTEX_LOCK(mutex) cl_mutex_lock(mutex, __FILE__, __LINE__) @@ -32,4 +33,8 @@ extern void cl_mutex_unlock(pthread_mutex_t* mutex, char* file, int line); extern int cl_cond_wait(pthread_cond_t* cond, pthread_mutex_t* mutex, char* file, int line); #define CL_COND_WAIT(cond, mutex) cl_cond_wait(cond, mutex, __FILE__, __LINE__) +extern int cl_cond_timedwait(pthread_cond_t *cond, pthread_mutex_t *mutex, + const struct timespec *abstime, char* file, int line); +#define CL_COND_TIMEDWAIT(cond, mutex, abstime) cl_cond_timedwait(cond, mutex, abstime, __FILE__, __LINE__) + #endif /* __CL_MUTEX_H__ */ |