summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJunyan He <junyan.he@intel.com>2016-04-22 16:11:58 +0800
committerJunyan He <junyan.he@intel.com>2016-04-22 16:11:58 +0800
commitcaabffe3a38337aadfce6c5c585f5c52ea69a342 (patch)
tree0bbb41791b6437fda76e8b42e2d4dbfce7ab926a
parentffbb5ac154757369c91b6d46e397c41e1666cb3d (diff)
mutex
-rw-r--r--libclapi/cl_mutex.c200
-rw-r--r--libclapi/cl_mutex.h7
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__ */