From f69b3a9fdcdad2031d38337782c05e1c5b74208b Mon Sep 17 00:00:00 2001 From: Jaroslav Kysela Date: Sat, 8 Dec 2018 18:44:31 +0100 Subject: [PATCH] tvh thread: add mutex magic check routines --- src/http.c | 2 +- src/idnode.c | 2 +- src/input/mpegts/linuxdvb/linuxdvb_ca.c | 4 +-- src/lang_codes.c | 2 +- src/spawn.c | 2 +- src/tvh_locale.c | 2 +- src/tvh_thread.c | 42 ++++++++++++++++++++++--- src/tvh_thread.h | 17 ++++++++++ src/webui/comet.c | 2 +- 9 files changed, 62 insertions(+), 13 deletions(-) diff --git a/src/http.c b/src/http.c index 13ec1d87d..af6521f75 100644 --- a/src/http.c +++ b/src/http.c @@ -33,7 +33,7 @@ void *http_server; static int http_server_running; -static tvh_mutex_t http_paths_mutex = { .mutex = PTHREAD_MUTEX_INITIALIZER }; +static tvh_mutex_t http_paths_mutex = TVH_THREAD_MUTEX_INITIALIZER; static http_path_list_t http_paths; static struct strtab HTTP_cmdtab[] = { diff --git a/src/idnode.c b/src/idnode.c index 29e4508c1..2e903d68f 100644 --- a/src/idnode.c +++ b/src/idnode.c @@ -52,7 +52,7 @@ static pthread_t save_tid; static int save_running; static mtimer_t save_timer; -static tvh_mutex_t idnode_lnotify_mutex = { .mutex = PTHREAD_MUTEX_INITIALIZER }; +static tvh_mutex_t idnode_lnotify_mutex = TVH_THREAD_MUTEX_INITIALIZER; static tvh_uuid_set_t idnode_lnotify_set; static tvh_uuid_set_t idnode_lnotify_title_set; diff --git a/src/input/mpegts/linuxdvb/linuxdvb_ca.c b/src/input/mpegts/linuxdvb/linuxdvb_ca.c index 60bc449b5..1a888b01f 100644 --- a/src/input/mpegts/linuxdvb/linuxdvb_ca.c +++ b/src/input/mpegts/linuxdvb/linuxdvb_ca.c @@ -41,8 +41,8 @@ #define TRANSPORT_RECOVERY 4 /* in seconds */ -static tvh_mutex_t linuxdvb_ca_mutex = { .mutex = PTHREAD_MUTEX_INITIALIZER }; -static tvh_mutex_t linuxdvb_capmt_mutex = { .mutex = PTHREAD_MUTEX_INITIALIZER }; +static tvh_mutex_t linuxdvb_ca_mutex = TVH_THREAD_MUTEX_INITIALIZER; +static tvh_mutex_t linuxdvb_capmt_mutex = TVH_THREAD_MUTEX_INITIALIZER; static th_pipe_t linuxdvb_ca_pipe; static pthread_t linuxdvb_ca_threadid; static mtimer_t linuxdvb_ca_thread_join_timer; diff --git a/src/lang_codes.c b/src/lang_codes.c index 9eeed12ee..8677f514c 100644 --- a/src/lang_codes.c +++ b/src/lang_codes.c @@ -500,7 +500,7 @@ lang_code_lookup_t* lang_codes_code2b = NULL; lang_code_lookup_t* lang_codes_code1 = NULL; lang_code_lookup_t* lang_codes_code2t = NULL; -tvh_mutex_t lang_code_split_mutex = { .mutex = PTHREAD_MUTEX_INITIALIZER }; +tvh_mutex_t lang_code_split_mutex = TVH_THREAD_MUTEX_INITIALIZER; RB_HEAD(,lang_code_list) lang_code_split_tree = { NULL, NULL, NULL, 0 }; /* ************************************************************************** diff --git a/src/spawn.c b/src/spawn.c index ca54ca4b1..b6ccb41f9 100644 --- a/src/spawn.c +++ b/src/spawn.c @@ -41,7 +41,7 @@ extern char **environ; -tvh_mutex_t spawn_mutex = { .mutex = PTHREAD_MUTEX_INITIALIZER }; +tvh_mutex_t spawn_mutex = TVH_THREAD_MUTEX_INITIALIZER; static LIST_HEAD(, spawn) spawns; diff --git a/src/tvh_locale.c b/src/tvh_locale.c index 9ad31ad8c..a7c5150f5 100644 --- a/src/tvh_locale.c +++ b/src/tvh_locale.c @@ -30,7 +30,7 @@ struct tvh_locale { #define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) -tvh_mutex_t tvh_gettext_mutex = { .mutex = PTHREAD_MUTEX_INITIALIZER }; +tvh_mutex_t tvh_gettext_mutex = TVH_THREAD_MUTEX_INITIALIZER; /* * diff --git a/src/tvh_thread.c b/src/tvh_thread.c index 83985c24c..c31997c70 100644 --- a/src/tvh_thread.c +++ b/src/tvh_thread.c @@ -30,6 +30,10 @@ static TAILQ_HEAD(, tvh_mutex) thrwatch_mutexes = TAILQ_HEAD_INITIALIZER(thrwatc static int64_t tvh_thread_crash_time; #endif +#if ENABLE_TRACE +static void tvh_thread_mutex_failed(tvh_mutex_t *mutex, const char *reason); +#endif + /* * thread routines */ @@ -134,14 +138,34 @@ tvh_thread_renice(int value) return ret; } +#if ENABLE_TRACE +static void tvh_mutex_check_magic(tvh_mutex_t *mutex) +{ + if (mutex && + mutex->magic1 == TVH_THREAD_MUTEX_MAGIC1 && + mutex->magic2 == TVH_THREAD_MUTEX_MAGIC2) + return; + tvh_thread_mutex_failed(mutex, "magic"); +} +#else +static inline void tvh_mutex_check_magic(tvh_mutex_t *mutex) +{ +} +#endif + int tvh_mutex_init(tvh_mutex_t *mutex, const pthread_mutexattr_t *attr) { memset(mutex, 0, sizeof(*mutex)); +#if ENABLE_TRACE + mutex->magic1 = TVH_THREAD_MUTEX_MAGIC1; + mutex->magic2 = TVH_THREAD_MUTEX_MAGIC2; +#endif return pthread_mutex_init(&mutex->mutex, attr); } int tvh_mutex_destroy(tvh_mutex_t *mutex) { + tvh_mutex_check_magic(mutex); return pthread_mutex_destroy(&mutex->mutex); } @@ -224,7 +248,9 @@ tvh_mutex_remove_from_waiters(tvh_mutex_waiter_t *w) #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); + tvh_mutex_waiter_t *w; + tvh_mutex_check_magic(mutex); + 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) @@ -236,6 +262,7 @@ int tvh__mutex_lock(tvh_mutex_t *mutex, const char *filename, int lineno) #if ENABLE_TRACE int tvh__mutex_trylock(tvh_mutex_t *mutex, const char *filename, int lineno) { + tvh_mutex_check_magic(mutex); int r = pthread_mutex_trylock(&mutex->mutex); if (r == 0) tvh_mutex_add_to_list(mutex, filename, lineno); @@ -246,8 +273,8 @@ int tvh__mutex_trylock(tvh_mutex_t *mutex, const char *filename, int lineno) #if ENABLE_TRACE int tvh__mutex_unlock(tvh_mutex_t *mutex) { - int r; - r = pthread_mutex_unlock(&mutex->mutex); + tvh_mutex_check_magic(mutex); + int r = pthread_mutex_unlock(&mutex->mutex); if (r == 0) tvh_mutex_remove_from_list(mutex, NULL, NULL); return r; @@ -261,6 +288,7 @@ tvh_mutex_timedlock int64_t finish = getfastmonoclock() + usec; int retcode; + tvh_mutex_check_magic(mutex); while ((retcode = pthread_mutex_trylock (&mutex->mutex)) == EBUSY) { if (getfastmonoclock() >= finish) return ETIMEDOUT; @@ -328,6 +356,7 @@ tvh_cond_wait #if ENABLE_TRACE const char *filename = NULL; int lineno = -1; + tvh_mutex_check_magic(mutex); if (tvh_thread_debug > 0) tvh_mutex_remove_from_list(mutex, &filename, &lineno); #endif @@ -348,6 +377,7 @@ tvh_cond_timedwait #if ENABLE_TRACE const char *filename = NULL; int lineno = -1; + tvh_mutex_check_magic(mutex); if (tvh_thread_debug > 0) tvh_mutex_remove_from_list(mutex, &filename, &lineno); #endif @@ -388,6 +418,7 @@ int tvh_cond_timedwait_ts(tvh_cond_t *cond, tvh_mutex_t *mutex, struct timespec #if ENABLE_TRACE const char *filename = NULL; int lineno = -1; + tvh_mutex_check_magic(mutex); if (tvh_thread_debug > 0) tvh_mutex_remove_from_list(mutex, &filename, &lineno); #endif @@ -434,13 +465,14 @@ static void tvh_thread_deadlock_write(htsbuf_queue_t *q) #endif #if ENABLE_TRACE -static void tvh_thread_mutex_deadlock(tvh_mutex_t *mutex) +static void tvh_thread_mutex_failed(tvh_mutex_t *mutex, const char *reason) { htsbuf_queue_t q; tvh_mutex_t *m; tvh_mutex_waiter_t *w; htsbuf_queue_init(&q, 0); + htsbuf_qprintf(&q, "REASON: %s\n", reason); 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); @@ -468,7 +500,7 @@ static void *tvh_thread_watch_thread(void *aux) mutex = TAILQ_LAST(&thrwatch_mutexes, tvh_mutex_queue); if (mutex && mutex->tstamp + sec2mono(5) < now) { pthread_mutex_unlock(&thrwatch_mutex); - tvh_thread_mutex_deadlock(mutex); + tvh_thread_mutex_failed(mutex, "deadlock"); } pthread_mutex_unlock(&thrwatch_mutex); if (tvh_thread_debug == 12345678 && tvh_thread_crash_time < getfastmonoclock()) { diff --git a/src/tvh_thread.h b/src/tvh_thread.h index b8031528b..d3a01f18d 100644 --- a/src/tvh_thread.h +++ b/src/tvh_thread.h @@ -25,6 +25,9 @@ #include "queue.h" #include "build.h" +#define TVH_THREAD_MUTEX_MAGIC1 0xd76a338a +#define TVH_THREAD_MUTEX_MAGIC2 0xf93a6421 + typedef struct { pthread_cond_t cond; } tvh_cond_t; @@ -44,12 +47,14 @@ typedef struct tvh_mutex_waiter { typedef struct tvh_mutex { pthread_mutex_t mutex; #if ENABLE_TRACE + uint32_t magic1; long tid; const char *filename; int lineno; int64_t tstamp; LIST_HEAD(, tvh_mutex_waiter) waiters; TAILQ_ENTRY(tvh_mutex) link; + uint32_t magic2; #endif } tvh_mutex_t; @@ -73,6 +78,18 @@ lock_assert0(tvh_mutex_t *l, const char *file, int line) #define lock_assert(l) lock_assert0(l, __FILE__, __LINE__) +#if ENABLE_TRACE +#define TVH_THREAD_MUTEX_INITIALIZER { \ + .magic1 = TVH_THREAD_MUTEX_MAGIC1, \ + .magic2 = TVH_THREAD_MUTEX_MAGIC2, \ + .mutex = PTHREAD_MUTEX_INITIALIZER, \ +} +#else +#define TVH_THREAD_MUTEX_INITIALIZER { \ + .mutex = PTHREAD_MUTEX_INITIALIZER, \ +} +#endif + /* * */ diff --git a/src/webui/comet.c b/src/webui/comet.c index 4dd7e2db5..5e0ff26ec 100644 --- a/src/webui/comet.c +++ b/src/webui/comet.c @@ -31,7 +31,7 @@ #include "tcp.h" #include "memoryinfo.h" -static tvh_mutex_t comet_mutex = { .mutex = PTHREAD_MUTEX_INITIALIZER }; +static tvh_mutex_t comet_mutex = TVH_THREAD_MUTEX_INITIALIZER; static tvh_cond_t comet_cond; static int comet_waiting; -- 2.47.2