Commit c1a723e0 authored by Rémi Denis-Courmont's avatar 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).
parent 4a9086ff
...@@ -54,7 +54,7 @@ static void vlc_interrupt_destructor(void *data) ...@@ -54,7 +54,7 @@ static void vlc_interrupt_destructor(void *data)
#endif #endif
static unsigned vlc_interrupt_refs = 0; 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; static vlc_threadvar_t vlc_interrupt_var;
/** /**
...@@ -62,7 +62,7 @@ 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) 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); assert(vlc_interrupt_refs < UINT_MAX);
if (vlc_interrupt_refs++ == 0) if (vlc_interrupt_refs++ == 0)
#ifndef NDEBUG #ifndef NDEBUG
...@@ -70,7 +70,7 @@ void vlc_interrupt_init(vlc_interrupt_t *ctx) ...@@ -70,7 +70,7 @@ void vlc_interrupt_init(vlc_interrupt_t *ctx)
#else #else
vlc_threadvar_create(&vlc_interrupt_var, NULL); vlc_threadvar_create(&vlc_interrupt_var, NULL);
#endif #endif
vlc_mutex_unlock(&vlc_interrupt_lock); vlc_rwlock_unlock(&vlc_interrupt_lock);
vlc_mutex_init(&ctx->lock); vlc_mutex_init(&ctx->lock);
ctx->interrupted = false; ctx->interrupted = false;
...@@ -99,11 +99,11 @@ void vlc_interrupt_deinit(vlc_interrupt_t *ctx) ...@@ -99,11 +99,11 @@ void vlc_interrupt_deinit(vlc_interrupt_t *ctx)
assert(!ctx->attached); assert(!ctx->attached);
vlc_mutex_destroy(&ctx->lock); vlc_mutex_destroy(&ctx->lock);
vlc_mutex_lock(&vlc_interrupt_lock); vlc_rwlock_wrlock(&vlc_interrupt_lock);
assert(vlc_interrupt_refs > 0); assert(vlc_interrupt_refs > 0);
if (--vlc_interrupt_refs == 0) if (--vlc_interrupt_refs == 0)
vlc_threadvar_delete(&vlc_interrupt_var); 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) void vlc_interrupt_destroy(vlc_interrupt_t *ctx)
...@@ -132,6 +132,12 @@ vlc_interrupt_t *vlc_interrupt_set(vlc_interrupt_t *newctx) ...@@ -132,6 +132,12 @@ vlc_interrupt_t *vlc_interrupt_set(vlc_interrupt_t *newctx)
{ {
vlc_interrupt_t *oldctx; 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); oldctx = vlc_threadvar_get(vlc_interrupt_var);
#ifndef NDEBUG #ifndef NDEBUG
if (oldctx != NULL) if (oldctx != NULL)
...@@ -152,7 +158,13 @@ vlc_interrupt_t *vlc_interrupt_set(vlc_interrupt_t *newctx) ...@@ -152,7 +158,13 @@ vlc_interrupt_t *vlc_interrupt_set(vlc_interrupt_t *newctx)
static vlc_interrupt_t *vlc_interrupt_get(void) 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;
} }
/** /**
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment