[vlc-commits] threads: generic futex-based semaphores

Rémi Denis-Courmont git at videolan.org
Wed Jun 1 21:57:09 CEST 2016


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Wed Jun  1 21:18:14 2016 +0300| [4d29bafd6d762ecbc99d7ae075e73cf1fc458c4a] | committer: Rémi Denis-Courmont

threads: generic futex-based semaphores

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

 include/vlc_threads.h |    4 +--
 src/misc/threads.c    |   86 ++++++++++++++++++++++++++++++++++++++++---------
 2 files changed, 72 insertions(+), 18 deletions(-)

diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 33f2a8a..d3ea0ac 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -334,9 +334,7 @@ typedef struct
 #ifdef LIBVLC_NEED_SEMAPHORE
 typedef struct vlc_sem
 {
-    vlc_mutex_t lock;
-    vlc_cond_t  wait;
-    unsigned    value;
+    unsigned value;
 } vlc_sem_t;
 #endif
 
diff --git a/src/misc/threads.c b/src/misc/threads.c
index 8bdcb1f..6451274 100644
--- a/src/misc/threads.c
+++ b/src/misc/threads.c
@@ -24,6 +24,7 @@
 
 #include <assert.h>
 #include <errno.h>
+#include <limits.h>
 
 #include <vlc_common.h>
 
@@ -215,8 +216,6 @@ int vlc_cond_timedwait_daytime(vlc_cond_t *cond, vlc_mutex_t *mutex,
 
 #ifdef LIBVLC_NEED_RWLOCK
 /*** Generic read/write locks ***/
-#include <stdlib.h>
-#include <limits.h>
 /* NOTE:
  * lock->state is a signed long integer:
  *  - The sign bit is set when the lock is held for writing.
@@ -296,45 +295,102 @@ void vlc_rwlock_unlock (vlc_rwlock_t *lock)
 
 #ifdef LIBVLC_NEED_SEMAPHORE
 /*** Generic semaphores ***/
-#include <limits.h>
-#include <errno.h>
+# ifdef LIBVLC_NEED_CONDVAR
+static inline atomic_uint *vlc_sem_value(vlc_sem_t *sem)
+{
+    /* XXX: ugly but avoids including vlc_atomic.h in vlc_threads.h */
+    static_assert (sizeof (sem->value) <= sizeof (atomic_uint),
+                   "Size mismatch!");
+    static_assert ((alignof (sem->value) % alignof (atomic_uint)) == 0,
+                   "Alignment mismatch");
+    return (atomic_uint *)&sem->value;
+}
+
+void vlc_sem_init(vlc_sem_t *sem, unsigned value)
+{
+    atomic_init(vlc_sem_value(sem), value);
+}
+
+void vlc_sem_destroy(vlc_sem_t *sem)
+{
+    (void) sem;
+}
+
+int vlc_sem_post(vlc_sem_t *sem)
+{
+    unsigned count = 0;
+
+    while (!atomic_compare_exchange_weak(vlc_sem_value(sem), &count,
+                                         count + 1))
+    {
+        if (unlikely(count == UINT_MAX))
+            return EOVERFLOW;
+    }
+
+    vlc_addr_signal(&sem->value);
+    return 0;
+}
+
+void vlc_sem_wait(vlc_sem_t *sem)
+{
+    unsigned count = 1;
+
+    vlc_testcancel();
+
+    while (!atomic_compare_exchange_weak(vlc_sem_value(sem), &count,
+                                         count - 1))
+    {
+        if (count == 0)
+        {
+            vlc_cancel_addr_prepare(&sem->value);
+            vlc_addr_wait(&sem->value, 0);
+            vlc_cancel_addr_finish(&sem->value);
+        }
+    }
+}
+# else
+static struct
+{
+    vlc_mutex_t lock;
+    vlc_cond_t  wait;
+} semaphores = { VLC_STATIC_MUTEX, VLC_STATIC_COND };
 
 void vlc_sem_init (vlc_sem_t *sem, unsigned value)
 {
-    vlc_mutex_init (&sem->lock);
-    vlc_cond_init (&sem->wait);
+    union { unsigned u; signed s; } u = { .u = value };
+
     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;
 
-    vlc_mutex_lock (&sem->lock);
+    vlc_mutex_lock(&semaphores.lock);
     if (likely(sem->value != UINT_MAX))
         sem->value++;
     else
         ret = EOVERFLOW;
-    vlc_mutex_unlock (&sem->lock);
-    vlc_cond_signal (&sem->wait);
+    vlc_mutex_unlock(&semaphores.lock);
+    vlc_cond_broadcast(&semaphores.wait);
 
     return ret;
 }
 
 void vlc_sem_wait (vlc_sem_t *sem)
 {
-    vlc_mutex_lock (&sem->lock);
-    mutex_cleanup_push (&sem->lock);
+    vlc_mutex_lock(&semaphores.lock);
+    mutex_cleanup_push(&semaphores.lock);
     while (!sem->value)
-        vlc_cond_wait (&sem->wait, &sem->lock);
+        vlc_cond_wait(&semaphores.wait, &semaphores.lock);
     sem->value--;
     vlc_cleanup_pop ();
-    vlc_mutex_unlock (&sem->lock);
+    vlc_mutex_unlock(&semaphores.lock);
 }
+# endif
 #endif /* LIBVLC_NEED_SEMAPHORE */



More information about the vlc-commits mailing list