[vlc-commits] interrupt: fix interruptible functions without any interrupt context

Rémi Denis-Courmont git at videolan.org
Mon Dec 21 19:56:04 CET 2015


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Mon Dec 21 20:53:55 2015 +0200| [c1a723e0b003fd1011c36cd4df802e64b118accd] | committer: Rémi Denis-Courmont

interrupt: fix interruptible functions without any interrupt context

If there are no interrupt contexts in the whole process, then the
thread variable is uninitialized. This adds a check.

Using thread_local would be much simpler and faster (but C11 threads).

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

 src/misc/interrupt.c |   24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/src/misc/interrupt.c b/src/misc/interrupt.c
index b78f8b0..979d5f3 100644
--- a/src/misc/interrupt.c
+++ b/src/misc/interrupt.c
@@ -54,7 +54,7 @@ static void vlc_interrupt_destructor(void *data)
 #endif
 
 static unsigned vlc_interrupt_refs = 0;
-static vlc_mutex_t vlc_interrupt_lock = VLC_STATIC_MUTEX;
+static vlc_rwlock_t vlc_interrupt_lock = VLC_STATIC_RWLOCK;
 static vlc_threadvar_t vlc_interrupt_var;
 
 /**
@@ -62,7 +62,7 @@ static vlc_threadvar_t vlc_interrupt_var;
  */
 void vlc_interrupt_init(vlc_interrupt_t *ctx)
 {
-    vlc_mutex_lock(&vlc_interrupt_lock);
+    vlc_rwlock_wrlock(&vlc_interrupt_lock);
     assert(vlc_interrupt_refs < UINT_MAX);
     if (vlc_interrupt_refs++ == 0)
 #ifndef NDEBUG
@@ -70,7 +70,7 @@ void vlc_interrupt_init(vlc_interrupt_t *ctx)
 #else
         vlc_threadvar_create(&vlc_interrupt_var, NULL);
 #endif
-    vlc_mutex_unlock(&vlc_interrupt_lock);
+    vlc_rwlock_unlock(&vlc_interrupt_lock);
 
     vlc_mutex_init(&ctx->lock);
     ctx->interrupted = false;
@@ -99,11 +99,11 @@ void vlc_interrupt_deinit(vlc_interrupt_t *ctx)
     assert(!ctx->attached);
     vlc_mutex_destroy(&ctx->lock);
 
-    vlc_mutex_lock(&vlc_interrupt_lock);
+    vlc_rwlock_wrlock(&vlc_interrupt_lock);
     assert(vlc_interrupt_refs > 0);
     if (--vlc_interrupt_refs == 0)
         vlc_threadvar_delete(&vlc_interrupt_var);
-    vlc_mutex_unlock(&vlc_interrupt_lock);
+    vlc_rwlock_unlock(&vlc_interrupt_lock);
 }
 
 void vlc_interrupt_destroy(vlc_interrupt_t *ctx)
@@ -132,6 +132,12 @@ vlc_interrupt_t *vlc_interrupt_set(vlc_interrupt_t *newctx)
 {
     vlc_interrupt_t *oldctx;
 
+    /* This function is called to push or pop an interrupt context. Either way
+     * either newctx or oldctx (or both) are non-NULL. Thus vlc_interrupt_refs
+     * must be larger than zero and vlc_interrupt_var must be valid. And so the
+     * read/write lock is not needed. */
+    assert(vlc_interrupt_refs > 0);
+
     oldctx = vlc_threadvar_get(vlc_interrupt_var);
 #ifndef NDEBUG
     if (oldctx != NULL)
@@ -152,7 +158,13 @@ vlc_interrupt_t *vlc_interrupt_set(vlc_interrupt_t *newctx)
 
 static vlc_interrupt_t *vlc_interrupt_get(void)
 {
-    return vlc_threadvar_get(vlc_interrupt_var);
+    vlc_interrupt_t *ctx = NULL;
+
+    vlc_rwlock_rdlock(&vlc_interrupt_lock);
+    if (vlc_interrupt_refs > 0)
+        ctx = vlc_threadvar_get(vlc_interrupt_var);
+    vlc_rwlock_unlock(&vlc_interrupt_lock);
+    return ctx;
 }
 
 /**



More information about the vlc-commits mailing list