]> git.sesse.net Git - vlc/blobdiff - src/misc/threads.c
decoder: remove unnecessary special case
[vlc] / src / misc / threads.c
index e3f2cb21b2eb1374915f71ee307ed0c775fcb3aa..01e1d976d0cedbe13e9de81e1d840d6bbd093429 100644 (file)
@@ -1,14 +1,7 @@
 /*****************************************************************************
- * threads.c : threads implementation for the VideoLAN client
+ * threads.c: LibVLC generic thread support
  *****************************************************************************
- * Copyright (C) 1999-2008 VLC authors and VideoLAN
- * $Id$
- *
- * Authors: Jean-Marc Dressler <polux@via.ecp.fr>
- *          Samuel Hocevar <sam@zoy.org>
- *          Gildas Bazin <gbazin@netcourrier.com>
- *          Clément Sténac
- *          Rémi Denis-Courmont
+ * Copyright (C) 2009-2012 Rémi Denis-Courmont
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
 # include "config.h"
 #endif
 
-#include <vlc_common.h>
 #include <assert.h>
 
+#include <vlc_common.h>
+
 /*** Global locks ***/
 
 void vlc_global_mutex (unsigned n, bool acquire)
@@ -42,6 +36,7 @@ void vlc_global_mutex (unsigned n, bool acquire)
         VLC_STATIC_MUTEX,
         VLC_STATIC_MUTEX,
         VLC_STATIC_MUTEX,
+        VLC_STATIC_MUTEX,
     };
     static_assert (VLC_MAX_MUTEX == (sizeof (locks) / sizeof (locks[0])),
                    "Wrong number of global mutexes");
@@ -53,3 +48,128 @@ void vlc_global_mutex (unsigned n, bool acquire)
     else
         vlc_mutex_unlock (lock);
 }
+
+#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.
+ *  - The other bits code the number of times the lock is held for reading.
+ * Consequently:
+ *  - The value is negative if and only if the lock is held for writing.
+ *  - The value is zero if and only if the lock is not held at all.
+ */
+#define READER_MASK LONG_MAX
+#define WRITER_BIT  LONG_MIN
+
+void vlc_rwlock_init (vlc_rwlock_t *lock)
+{
+    vlc_mutex_init (&lock->mutex);
+    vlc_cond_init (&lock->wait);
+    lock->state = 0;
+}
+
+void vlc_rwlock_destroy (vlc_rwlock_t *lock)
+{
+    vlc_cond_destroy (&lock->wait);
+    vlc_mutex_destroy (&lock->mutex);
+}
+
+void vlc_rwlock_rdlock (vlc_rwlock_t *lock)
+{
+    vlc_mutex_lock (&lock->mutex);
+    /* Recursive read-locking is allowed.
+     * Ensure that there is no active writer. */
+    while (lock->state < 0)
+    {
+        assert (lock->state == WRITER_BIT);
+        mutex_cleanup_push (&lock->mutex);
+        vlc_cond_wait (&lock->wait, &lock->mutex);
+        vlc_cleanup_pop ();
+    }
+    if (unlikely(lock->state >= READER_MASK))
+        abort (); /* An overflow is certainly a recursion bug. */
+    lock->state++;
+    vlc_mutex_unlock (&lock->mutex);
+}
+
+void vlc_rwlock_wrlock (vlc_rwlock_t *lock)
+{
+    vlc_mutex_lock (&lock->mutex);
+    /* Wait until nobody owns the lock in any way. */
+    while (lock->state != 0)
+    {
+        mutex_cleanup_push (&lock->mutex);
+        vlc_cond_wait (&lock->wait, &lock->mutex);
+        vlc_cleanup_pop ();
+    }
+    lock->state = WRITER_BIT;
+    vlc_mutex_unlock (&lock->mutex);
+}
+
+void vlc_rwlock_unlock (vlc_rwlock_t *lock)
+{
+    vlc_mutex_lock (&lock->mutex);
+    if (lock->state < 0)
+    {   /* Write unlock */
+        assert (lock->state == WRITER_BIT);
+        /* Let reader and writer compete. OS scheduler decides who wins. */
+        lock->state = 0;
+        vlc_cond_broadcast (&lock->wait);
+    }
+    else
+    {   /* Read unlock */
+        assert (lock->state > 0);
+        /* If there are no readers left, wake up one pending writer. */
+        if (--lock->state == 0)
+            vlc_cond_signal (&lock->wait);
+    }
+    vlc_mutex_unlock (&lock->mutex);
+}
+#endif /* LIBVLC_NEED_RWLOCK */
+
+#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;
+}
+
+void vlc_sem_destroy (vlc_sem_t *sem)
+{
+    vlc_cond_destroy (&sem->wait);
+    vlc_mutex_destroy (&sem->lock);
+}
+
+int vlc_sem_post (vlc_sem_t *sem)
+{
+    int ret = 0;
+
+    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);
+
+    return ret;
+}
+
+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_run ();
+}
+#endif /* LIBVLC_NEED_SEMAPHORE */