[vlc-commits] misc: better lock assertion back-end

Rémi Denis-Courmont git at videolan.org
Sun Oct 21 13:01:23 CEST 2018


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sat Oct 20 22:24:37 2018 +0300| [ff7544ed09afc47eb54926453c7e4b94f58a2401] | committer: Rémi Denis-Courmont

misc: better lock assertion back-end

This tracks the locks manually, which is a lot slower but compared
to the existing vlc_assert_locked():
 - The performance is not a major problem in debug builds.
 - Assertion can be made that a mutex is _not_ locked.
 - The state of a static mutex can be asserted.
 - The implementation is not POSIX-specific.
 - The pointed to the asserted lock is properly const.
 - The implementation does not trip valgrind.
 - The implementation will not trip sanitizers.

Also the implementation is still lock-free and thread-safe.

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=ff7544ed09afc47eb54926453c7e4b94f58a2401
---

 src/libvlc.h       | 22 +++++++++++++++
 src/misc/threads.c | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 104 insertions(+)

diff --git a/src/libvlc.h b/src/libvlc.h
index cf95961cdd..18243ce4c0 100644
--- a/src/libvlc.h
+++ b/src/libvlc.h
@@ -58,6 +58,28 @@ void vlc_threads_setup (libvlc_int_t *);
 void vlc_trace (const char *fn, const char *file, unsigned line);
 #define vlc_backtrace() vlc_trace(__func__, __FILE__, __LINE__)
 
+#ifndef NDEBUG
+/**
+ * Marks a mutex locked.
+ */
+void vlc_mutex_mark(const vlc_mutex_t *);
+
+/**
+ * Unmarks a mutex.
+ */
+void vlc_mutex_unmark(const vlc_mutex_t *);
+
+/**
+ * Checks if a mutex is marked.
+ */
+bool vlc_mutex_marked(const vlc_mutex_t *);
+#else
+# define vlc_mutex_mark(m) ((void)(m))
+# define vlc_mutex_unmark(m) ((void)(m))
+#endif
+
+#define vlc_mutex_assert(m) assert(vlc_mutex_marked(m))
+
 #if (defined (LIBVLC_USE_PTHREAD) || defined(__ANDROID__) || defined (__APPLE__)) && !defined (NDEBUG)
 void vlc_assert_locked (vlc_mutex_t *);
 #else
diff --git a/src/misc/threads.c b/src/misc/threads.c
index 9e99ab0d02..e0d95e53aa 100644
--- a/src/misc/threads.c
+++ b/src/misc/threads.c
@@ -26,6 +26,7 @@
 #include <errno.h>
 
 #include <vlc_common.h>
+#include "libvlc.h"
 
 /*** Global locks ***/
 
@@ -51,6 +52,87 @@ void vlc_global_mutex (unsigned n, bool acquire)
         vlc_mutex_unlock (lock);
 }
 
+#ifndef NDEBUG
+# include <search.h>
+
+struct vlc_lock_mark
+{
+    const void *object;
+    uintptr_t refs;
+};
+
+static int vlc_lock_mark_cmp(const void *a, const void *b)
+{
+    const struct vlc_lock_mark *ma = a, *mb = b;
+
+    if (ma->object == mb->object)
+        return 0;
+
+    return ((uintptr_t)(ma->object) > (uintptr_t)(mb->object)) ? +1 : -1;
+}
+
+static void vlc_lock_mark(const void *lock, void **rootp)
+{
+    struct vlc_lock_mark *mark = malloc(sizeof (*mark));
+    if (unlikely(mark == NULL))
+        abort();
+
+    mark->object = lock;
+    mark->refs = 0;
+
+    struct vlc_lock_mark **entry = tsearch(mark, rootp, vlc_lock_mark_cmp);
+    if (unlikely(entry == NULL))
+        abort();
+
+    if (unlikely(*entry != mark)) {
+        /* Recursive locking: lock is already in the tree */
+        free(mark);
+        mark = *entry;
+    }
+
+    mark->refs++;
+}
+
+static void vlc_lock_unmark(const void *lock, void **rootp)
+{
+    struct vlc_lock_mark *mark = &(struct vlc_lock_mark){ lock, 0 };
+    struct vlc_lock_mark **entry = tfind(mark, rootp, vlc_lock_mark_cmp);
+
+    assert(entry != NULL);
+    mark = *entry;
+    assert(mark->refs > 0);
+
+    if (likely(--mark->refs == 0)) {
+        tdelete(mark, rootp, vlc_lock_mark_cmp);
+        free(mark);
+    }
+}
+
+static bool vlc_lock_marked(const void *lock, void **rootp)
+{
+    struct vlc_lock_mark *mark = &(struct vlc_lock_mark){ lock, 0 };
+
+    return tfind(mark, rootp, vlc_lock_mark_cmp) != NULL;
+}
+
+static _Thread_local void *vlc_mutex_marks = NULL;
+
+void vlc_mutex_mark(const vlc_mutex_t *mutex)
+{
+    vlc_lock_mark(mutex, &vlc_mutex_marks);
+}
+
+void vlc_mutex_unmark(const vlc_mutex_t *mutex)
+{
+    vlc_lock_unmark(mutex, &vlc_mutex_marks);
+}
+
+bool vlc_mutex_marked(const vlc_mutex_t *mutex)
+{
+    return vlc_lock_marked(mutex, &vlc_mutex_marks);
+}
+#endif
+
 #if defined (_WIN32) && (_WIN32_WINNT < _WIN32_WINNT_WIN8)
 /* Cannot define OS version-dependent stuff in public headers */
 # undef LIBVLC_NEED_SLEEP



More information about the vlc-commits mailing list