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
*/
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);
}
#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)
#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);
#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;
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;
#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
#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
#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
#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);
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()) {
#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;
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;
#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
+
/*
*
*/