[vlc-commits] thread: rewrite semaphores with an atomic variable
Rémi Denis-Courmont
git at videolan.org
Mon Feb 17 17:54:57 CET 2020
vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Feb 16 18:45:37 2020 +0200| [68daa568c45c1b41c42516514969225c5f171752] | committer: Rémi Denis-Courmont
thread: rewrite semaphores with an atomic variable
This replaces the generic/fallback implementation of VLC semaphores
based on a condition variable, a mutex and a value, with a lighter
implementation using just an atomic variable.
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=68daa568c45c1b41c42516514969225c5f171752
---
include/vlc_threads.h | 11 +++++++----
src/misc/threads.c | 49 ++++++++++++++++++++++++++-----------------------
2 files changed, 33 insertions(+), 27 deletions(-)
diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 1b3cb278e4..688855ca72 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -350,11 +350,11 @@ typedef struct vlc_timer *vlc_timer_t;
#endif
-#ifdef LIBVLC_NEED_CONDVAR
#ifndef __cplusplus
#include <stdatomic.h>
#endif
+#ifdef LIBVLC_NEED_CONDVAR
typedef struct
{
union {
@@ -370,9 +370,12 @@ typedef struct
#ifdef LIBVLC_NEED_SEMAPHORE
typedef struct vlc_sem
{
- vlc_mutex_t lock;
- vlc_cond_t wait;
- unsigned value;
+ union {
+#ifndef __cplusplus
+ atomic_uint value;
+#endif
+ int dummy;
+ };
} vlc_sem_t;
#endif
diff --git a/src/misc/threads.c b/src/misc/threads.c
index 7855ae11b9..82bd5b60fc 100644
--- a/src/misc/threads.c
+++ b/src/misc/threads.c
@@ -24,6 +24,8 @@
#include <assert.h>
#include <errno.h>
+#include <limits.h>
+#include <stdatomic.h>
#include <vlc_common.h>
#include "libvlc.h"
@@ -396,45 +398,46 @@ void vlc_rwlock_unlock (vlc_rwlock_t *lock)
#ifdef LIBVLC_NEED_SEMAPHORE
/*** Generic semaphores ***/
-#include <limits.h>
-#include <errno.h>
void vlc_sem_init (vlc_sem_t *sem, unsigned value)
{
- vlc_mutex_init (&sem->lock);
- vlc_cond_init (&sem->wait);
- sem->value = value;
+ atomic_init(&sem->value, value);
}
void vlc_sem_destroy (vlc_sem_t *sem)
{
- vlc_cond_destroy (&sem->wait);
- vlc_mutex_destroy (&sem->lock);
+ (void) sem;
}
int vlc_sem_post (vlc_sem_t *sem)
{
- int ret = 0;
+ unsigned exp = atomic_load_explicit(&sem->value, memory_order_relaxed);
- vlc_mutex_lock (&sem->lock);
- if (likely(sem->value != UINT_MAX))
- sem->value++;
- else
- ret = EOVERFLOW;
- vlc_mutex_unlock (&sem->lock);
- vlc_cond_signal (&sem->wait);
+ do
+ {
+ if (unlikely(exp == UINT_MAX))
+ return EOVERFLOW;
+ } while (!atomic_compare_exchange_weak_explicit(&sem->value, &exp, exp + 1,
+ memory_order_release,
+ memory_order_relaxed));
- return ret;
+ vlc_atomic_notify_one(&sem->value);
+ return 0;
}
void vlc_sem_wait (vlc_sem_t *sem)
{
- vlc_mutex_lock (&sem->lock);
- mutex_cleanup_push (&sem->lock);
- while (!sem->value)
- vlc_cond_wait (&sem->wait, &sem->lock);
- sem->value--;
- vlc_cleanup_pop ();
- vlc_mutex_unlock (&sem->lock);
+ unsigned exp = 1;
+
+ while (!atomic_compare_exchange_weak_explicit(&sem->value, &exp, exp - 1,
+ memory_order_acquire,
+ memory_order_relaxed))
+ {
+ if (likely(exp == 0))
+ {
+ vlc_atomic_wait(&sem->value, 0);
+ exp = 1;
+ }
+ }
}
#endif /* LIBVLC_NEED_SEMAPHORE */
More information about the vlc-commits
mailing list