]> git.ipfire.org Git - thirdparty/tvheadend.git/commitdiff
tvh_thread: show also waiters
authorJaroslav Kysela <perex@perex.cz>
Thu, 6 Dec 2018 16:49:32 +0000 (17:49 +0100)
committerJaroslav Kysela <perex@perex.cz>
Thu, 6 Dec 2018 16:49:32 +0000 (17:49 +0100)
src/tvh_thread.c
src/tvh_thread.h

index 1e961f9e7d05239c12dd6aaf012b6af0a151bff5..83985c24cc4ae89785a920f71927b2c4c5b4b842 100644 (file)
@@ -5,6 +5,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/resource.h>
+#include <sys/types.h>
 #include <unistd.h>
 #include <signal.h>
 
@@ -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
index 1e1ad89496a6c74c3ad8b6996fa462e20dbbda31..b8031528bbf9c5b060e7002345478c33d3187f31 100644 (file)
@@ -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;