vlc | branch: master | Rémi Denis-Courmont <[email protected]> | 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 _______________________________________________ vlc-commits mailing list [email protected] https://mailman.videolan.org/listinfo/vlc-commits
