#include <fcntl.h>
#include <sys/stat.h>
#include <sys/resource.h>
+#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
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)
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 */
{
pthread_mutex_lock(&thrwatch_mutex);
if (filename != NULL) {
- mutex->thread = pthread_self();
+ mutex->tid = thread_get_tid();
mutex->filename = filename;
mutex->lineno = lineno;
}
}
#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;
}
#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