Implement thread semaphores
[vlc.git] / src / misc / pthread.c
index 58b2c8f..ce604f4 100644 (file)
@@ -35,6 +35,7 @@
 #include <assert.h>
 #include <unistd.h> /* fsync() */
 #include <signal.h>
+#include <errno.h>
 
 #include <sched.h>
 #ifdef __linux__
@@ -141,9 +142,11 @@ void vlc_mutex_init( vlc_mutex_t *p_mutex )
 
     if( pthread_mutexattr_init( &attr ) )
         abort();
-#ifndef NDEBUG
+#ifdef NDEBUG
+    pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_NORMAL );
+#else
     /* Create error-checking mutex to detect problems more easily. */
-# if defined (__GLIBC__) && (__GLIBC_MINOR__ < 6)
+# if defined (__GLIBC__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ < 6)
     pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_ERRORCHECK_NP );
 # else
     pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_ERRORCHECK );
@@ -162,7 +165,7 @@ void vlc_mutex_init_recursive( vlc_mutex_t *p_mutex )
     pthread_mutexattr_t attr;
 
     pthread_mutexattr_init( &attr );
-#if defined (__GLIBC__) && (__GLIBC_MINOR__ < 6)
+#if defined (__GLIBC__) && (__GLIBC__ == 2) && (__GLIBC_MINOR__ < 6)
     pthread_mutexattr_setkind_np( &attr, PTHREAD_MUTEX_RECURSIVE_NP );
 #else
     pthread_mutexattr_settype( &attr, PTHREAD_MUTEX_RECURSIVE );
@@ -375,6 +378,48 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
     return val;
 }
 
+/**
+ * Initializes a semaphore.
+ */
+void vlc_sem_init (vlc_sem_t *sem, unsigned value)
+{
+    if (sem_init (sem, 0, value))
+        abort ();
+}
+
+/**
+ * Destroys a semaphore.
+ */
+void vlc_sem_destroy (vlc_sem_t *sem)
+{
+    int val = sem_destroy (sem);
+    VLC_THREAD_ASSERT ("destroying semaphore");
+}
+
+/**
+ * Increments the value of a semaphore.
+ */
+int vlc_sem_post (vlc_sem_t *sem)
+{
+    int val = sem_post (sem);
+    if (val != EOVERFLOW)
+        VLC_THREAD_ASSERT ("unlocking semaphore");
+    return val;
+}
+
+/**
+ * Atomically wait for the semaphore to become non-zero (if needed),
+ * then decrements it.
+ */
+void vlc_sem_wait (vlc_sem_t *sem)
+{
+    int val;
+    do
+        val = sem_wait (sem);
+    while (val == EINTR);
+    VLC_THREAD_ASSERT ("locking semaphore");
+}
+
 /**
  * Initializes a read/write lock.
  */
@@ -775,13 +820,11 @@ int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
  * @warning This function <b>must</b> be called before the timer data can be
  * freed and before the timer callback function can be unloaded.
  *
- * @param timer to destroy
+ * @param timer timer to destroy
  */
-void vlc_timer_destroy (vlc_timer_t *id)
+void vlc_timer_destroy (vlc_timer_t timer)
 {
-    struct vlc_timer *timer = *id;
-
-    vlc_timer_schedule (id, false, 0, 0);
+    vlc_timer_schedule (timer, false, 0, 0);
     vlc_mutex_lock (&timer->lock);
     while (timer->users != 0)
         vlc_cond_wait (&timer->wait, &timer->lock);
@@ -801,7 +844,7 @@ void vlc_timer_destroy (vlc_timer_t *id)
  * the system is busy or suspended, or because a previous iteration of the
  * timer is still running. See also vlc_timer_getoverrun().
  *
- * @param id initialized timer pointer
+ * @param timer initialized timer
  * @param absolute the timer value origin is the same as mdate() if true,
  *                 the timer value is relative to now if false.
  * @param value zero to disarm the timer, otherwise the initial time to wait
@@ -809,16 +852,19 @@ void vlc_timer_destroy (vlc_timer_t *id)
  * @param interval zero to fire the timer just once, otherwise the timer
  *                 repetition interval.
  */
-void vlc_timer_schedule (vlc_timer_t *id, bool absolute,
+void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
                          mtime_t value, mtime_t interval)
 {
-    struct vlc_timer *timer = *id;
+    static vlc_mutex_t lock = VLC_STATIC_MUTEX;
 
+    vlc_mutex_lock (&lock);
     vlc_mutex_lock (&timer->lock);
     if (timer->value)
     {
+        vlc_mutex_unlock (&timer->lock);
         vlc_cancel (timer->thread);
         vlc_join (timer->thread, NULL);
+        vlc_mutex_lock (&timer->lock);
         timer->value = 0;
     }
     if ((value != 0)
@@ -829,18 +875,18 @@ void vlc_timer_schedule (vlc_timer_t *id, bool absolute,
         timer->interval = interval;
     }
     vlc_mutex_unlock (&timer->lock);
+    vlc_mutex_unlock (&lock);
 }
 
 /**
  * Fetch and reset the overrun counter for a timer.
- * @param id initialized timer pointer
+ * @param timer initialized timer
  * @return the timer overrun counter, i.e. the number of times that the timer
  * should have run but did not since the last actual run. If all is well, this
  * is zero.
  */
-unsigned vlc_timer_getoverrun (const vlc_timer_t *id)
+unsigned vlc_timer_getoverrun (vlc_timer_t timer)
 {
-    struct vlc_timer *timer = *id;
     unsigned ret;
 
     vlc_mutex_lock (&timer->lock);