[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