[vlc-devel] [PATCH 2/7] thread: rewrite semaphores with an atomic variable

RĂ©mi Denis-Courmont remi at remlab.net
Sun Feb 16 18:50:41 CET 2020


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.
---
 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 */
-- 
2.25.0



More information about the vlc-devel mailing list