From bc14d7f7cd2bae3a9759822570a652c504fce249 Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Thu, 6 Dec 2018 17:49:32 +0100 Subject: [PATCH] tvh_thread: show also waiters --- src/tvh_thread.c | 122 +++++++++++++++++++++++++++++++---------------- src/tvh_thread.h | 13 ++++- 2 files changed, 93 insertions(+), 42 deletions(-) diff --git a/src/tvh_thread.c b/src/tvh_thread.c index 1e961f9e7..83985c24c 100644 --- a/src/tvh_thread.c +++ b/src/tvh_thread.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -44,24 +45,17 @@ thread_state { char name[17]; }; -#if ENABLE_TRACE -static void -thread_get_name(pthread_t tid, char *buf, int len) +static inline int +thread_get_tid(void) { - buf[0] = '?'; - buf[1] = '\0'; -#if defined(PLATFORM_LINUX) - /* Set name */ - if (len >= 16) - prctl(PR_GET_NAME, buf); -#elif defined(PLATFORM_FREEBSD) - /* Get name of thread */ - //pthread_get_name_np(tid, buf); ??? -#elif defined(PLATFORM_DARWIN) - // ??? +#ifdef SYS_gettid + return syscall(SYS_gettid); +#elif ENABLE_ANDROID + return gettid(); +#else + return -1; #endif } -#endif static void * thread_wrapper(void *p) @@ -127,13 +121,8 @@ int tvh_thread_renice(int value) { int ret = 0; -#ifdef SYS_gettid - pid_t tid; - tid = syscall(SYS_gettid); - ret = setpriority(PRIO_PROCESS, tid, value); -#elif ENABLE_ANDROID - pid_t tid; - tid = gettid(); +#if defined(SYS_gettid) || ENABLE_ANDROID + pid_t tid = thread_get_tid(); ret = setpriority(PRIO_PROCESS, tid, value); #elif defined(PLATFORM_DARWIN) /* Currently not possible */ @@ -161,7 +150,7 @@ static void tvh_mutex_add_to_list(tvh_mutex_t *mutex, const char *filename, int { pthread_mutex_lock(&thrwatch_mutex); if (filename != NULL) { - mutex->thread = pthread_self(); + mutex->tid = thread_get_tid(); mutex->filename = filename; mutex->lineno = lineno; } @@ -202,10 +191,42 @@ static void tvh_mutex_remove_from_list(tvh_mutex_t *mutex, const char **filename } #endif +#if ENABLE_TRACE +static tvh_mutex_waiter_t * +tvh_mutex_add_to_waiters(tvh_mutex_t *mutex, const char *filename, int lineno) +{ + tvh_mutex_waiter_t *w = malloc(sizeof(*w)); + + pthread_mutex_lock(&thrwatch_mutex); + if (filename != NULL) { + w->tid = thread_get_tid(); + w->filename = filename; + w->lineno = lineno; + } + w->tstamp = getfastmonoclock(); + LIST_INSERT_HEAD(&mutex->waiters, w, link); + pthread_mutex_unlock(&thrwatch_mutex); + return w; +} +#endif + +#if ENABLE_TRACE +static void +tvh_mutex_remove_from_waiters(tvh_mutex_waiter_t *w) +{ + pthread_mutex_lock(&thrwatch_mutex); + LIST_REMOVE(w, link); + free(w); + pthread_mutex_unlock(&thrwatch_mutex); +} +#endif + #if ENABLE_TRACE int tvh__mutex_lock(tvh_mutex_t *mutex, const char *filename, int lineno) { + tvh_mutex_waiter_t *w = tvh_mutex_add_to_waiters(mutex, filename, lineno); int r = pthread_mutex_lock(&mutex->mutex); + tvh_mutex_remove_from_waiters(w); if (r == 0) tvh_mutex_add_to_list(mutex, filename, lineno); return r; @@ -386,32 +407,51 @@ tvh_mutex_not_held(const char *file, int line) } #if ENABLE_TRACE -static void tvh_thread_mutex_deadlock(tvh_mutex_t *mutex) +static void tvh_thread_deadlock_write(htsbuf_queue_t *q) { - int fd = hts_settings_open_file(HTS_SETTINGS_OPEN_WRITE | HTS_SETTINGS_OPEN_DIRECT, "mutex-deadlock.txt"); - if (fd < 0) fd = fileno(stderr); -#if defined(PLATFORM_LINUX) && __GLIBC__ - int sid = mutex->mutex.__data.__owner; /* unportable */ -#else - int sid = -1; -#endif - char name[256], *s; - htsbuf_queue_t q; size_t l; + char *s, *s2, *saveptr; + const int fd_stderr = fileno(stderr); + int fd = hts_settings_open_file(HTS_SETTINGS_OPEN_WRITE | HTS_SETTINGS_OPEN_DIRECT, "mutex-deadlock.txt"); + if (fd < 0) fd = fd_stderr; - thread_get_name(mutex->thread, name, sizeof(name)); - - htsbuf_queue_init(&q, 0); - htsbuf_qprintf(&q, "Thread %i: %s\n", sid, name); - htsbuf_qprintf(&q, " locked in: %s:%i\n", mutex->filename, mutex->lineno); - - s = htsbuf_to_string(&q); + s = htsbuf_to_string(q); l = s ? strlen(s) : 0; if (l > 0) { tvh_write(fd, s, l); - tvh_write(STDERR_FILENO, s, l); + if (fd != fd_stderr) + tvh_write(fd_stderr, s, l); + } + + saveptr = NULL; + for (; ; s = NULL) { + s2 = strtok_r(s, "\n", &saveptr); + if (s2 == NULL) + break; + tvhdbg(LS_THREAD, "%s", s2); } +} +#endif + +#if ENABLE_TRACE +static void tvh_thread_mutex_deadlock(tvh_mutex_t *mutex) +{ + htsbuf_queue_t q; + tvh_mutex_t *m; + tvh_mutex_waiter_t *w; + htsbuf_queue_init(&q, 0); + htsbuf_qprintf(&q, "mutex %p locked in: %s:%i (thread %ld)\n", mutex, mutex->filename, mutex->lineno, mutex->tid); + LIST_FOREACH(w, &mutex->waiters, link) + htsbuf_qprintf(&q, "mutex %p waiting in: %s:%i (thread %ld)\n", mutex, w->filename, w->lineno, w->tid); + TAILQ_FOREACH(m, &thrwatch_mutexes, link) { + if (m == mutex) continue; + htsbuf_qprintf(&q, "mutex %p other in: %s:%i (thread %ld)\n", mutex, mutex->filename, mutex->lineno, mutex->tid); + LIST_FOREACH(w, &m->waiters, link) + htsbuf_qprintf(&q, "mutex %p waiting in: %s:%i (thread %ld)\n", mutex, w->filename, w->lineno, w->tid); + } + tvh_thread_deadlock_write(&q); + tvh_safe_usleep(2000000); abort(); } #endif diff --git a/src/tvh_thread.h b/src/tvh_thread.h index 1e1ad8949..b8031528b 100644 --- a/src/tvh_thread.h +++ b/src/tvh_thread.h @@ -31,13 +31,24 @@ typedef struct { TAILQ_HEAD(tvh_mutex_queue, tvh_mutex); +#if ENABLE_TRACE +typedef struct tvh_mutex_waiter { + LIST_ENTRY(tvh_mutex_waiter) link; + long tid; + const char *filename; + int lineno; + int64_t tstamp; +} tvh_mutex_waiter_t; +#endif + typedef struct tvh_mutex { pthread_mutex_t mutex; #if ENABLE_TRACE - pthread_t thread; + long tid; const char *filename; int lineno; int64_t tstamp; + LIST_HEAD(, tvh_mutex_waiter) waiters; TAILQ_ENTRY(tvh_mutex) link; #endif } tvh_mutex_t; -- 2.47.2