]> git.sesse.net Git - vlc/blobdiff - src/misc/pthread.c
Fixed filter_chain_MouseFilter when multiple video filters are used.
[vlc] / src / misc / pthread.c
index 264d1bf713bde7b0c9e3d70e60562ba1d07a7b1d..ae002679f0145a9b0417e323b0db2ee15b416992 100644 (file)
@@ -29,6 +29,7 @@
 #endif
 
 #include <vlc_common.h>
+#include <vlc_atomic.h>
 
 #include "libvlc.h"
 #include <stdarg.h>
@@ -380,22 +381,28 @@ int vlc_cond_timedwait (vlc_cond_t *p_condvar, vlc_mutex_t *p_mutex,
                         mtime_t deadline)
 {
 #if defined(__APPLE__) && !defined(__powerpc__) && !defined( __ppc__ ) && !defined( __ppc64__ )
-    /* mdate() is mac_absolute_time on OSX, which we must convert to do
-     * the same base than gettimeofday() which pthread_cond_timedwait
-     * relies on. */
-    mtime_t oldbase = mdate();
-    struct timeval tv;
-    gettimeofday(&tv, NULL);
-    mtime_t newbase = (mtime_t)tv.tv_sec * 1000000 + (mtime_t) tv.tv_usec;
-    deadline = deadline - oldbase + newbase;
-#endif
+    /* mdate() is the monotonic clock, timedwait origin is gettimeofday() which
+     * isn't monotonic. Use imedwait_relative_np() instead
+    */
+    mtime_t base = mdate();
+    deadline -= base;
+    if (deadline < 0)
+        deadline = 0;
     lldiv_t d = lldiv( deadline, CLOCK_FREQ );
     struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) };
 
+    int val = pthread_cond_timedwait_relative_np(p_condvar, p_mutex, &ts);
+    if (val != ETIMEDOUT)
+        VLC_THREAD_ASSERT ("timed-waiting on condition");
+    return val;
+#else
+    lldiv_t d = lldiv( deadline, CLOCK_FREQ );
+    struct timespec ts = { d.quot, d.rem * (1000000000 / CLOCK_FREQ) };
     int val = pthread_cond_timedwait (p_condvar, p_mutex, &ts);
     if (val != ETIMEDOUT)
         VLC_THREAD_ASSERT ("timed-waiting on condition");
     return val;
+#endif
 }
 
 /**
@@ -688,6 +695,9 @@ int vlc_clone (vlc_thread_t *p_handle, void * (*entry) (void *), void *data,
 void vlc_cancel (vlc_thread_t thread_id)
 {
     pthread_cancel (thread_id);
+#ifdef HAVE_MAEMO
+    pthread_kill (thread_id, SIGRTMIN);
+#endif
 }
 
 /**
@@ -791,28 +801,13 @@ struct vlc_timer
 {
     vlc_thread_t thread;
     vlc_mutex_t  lock;
-    vlc_cond_t   wait;
     void       (*func) (void *);
     void        *data;
     mtime_t      value, interval;
     unsigned     users;
-    unsigned     overruns;
+    vlc_atomic_t overruns;
 };
 
-static void *vlc_timer_do (void *data)
-{
-    struct vlc_timer *timer = data;
-
-    timer->func (timer->data);
-
-    vlc_mutex_lock (&timer->lock);
-    assert (timer->users > 0);
-    if (--timer->users == 0)
-        vlc_cond_signal (&timer->wait);
-    vlc_mutex_unlock (&timer->lock);
-    return NULL;
-}
-
 static void *vlc_timer_thread (void *data)
 {
     struct vlc_timer *timer = data;
@@ -825,23 +820,26 @@ static void *vlc_timer_thread (void *data)
 
     for (;;)
     {
-         vlc_thread_t th;
-
          mwait (value);
 
-         vlc_mutex_lock (&timer->lock);
-         if (vlc_clone (&th, vlc_timer_do, timer, VLC_THREAD_PRIORITY_INPUT))
-             timer->overruns++;
-         else
-         {
-             vlc_detach (th);
-             timer->users++;
-         }
-         vlc_mutex_unlock (&timer->lock);
+         int canc = vlc_savecancel ();
+         timer->func (timer->data);
+         vlc_restorecancel (canc);
 
          if (interval == 0)
              return NULL;
 
+         mtime_t now = mdate ();
+         unsigned misses = (now - value) / interval;
+         /* Try to compensate for one miss (mwait() will return immediately)
+          * but no more. Otherwise, we might busy loop, after extended periods
+          * without scheduling (suspend, SIGSTOP, RT preemption, ...). */
+         if (misses > 1)
+         {
+             misses--;
+             vlc_atomic_add (&timer->overruns, misses);
+             value += misses * interval;
+         }
          value += interval;
     }
 }
@@ -849,7 +847,8 @@ static void *vlc_timer_thread (void *data)
 /**
  * Initializes an asynchronous timer.
  * @warning Asynchronous timers are processed from an unspecified thread.
- * Also, multiple occurences of an interval timer can run concurrently.
+ * Multiple occurences of a single interval timer are serialized; they cannot
+ * run concurrently.
  *
  * @param id pointer to timer to be initialized
  * @param func function that the timer will call
@@ -863,14 +862,13 @@ int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
     if (unlikely(timer == NULL))
         return ENOMEM;
     vlc_mutex_init (&timer->lock);
-    vlc_cond_init (&timer->wait);
     assert (func);
     timer->func = func;
     timer->data = data;
     timer->value = 0;
     timer->interval = 0;
     timer->users = 0;
-    timer->overruns = 0;
+    vlc_atomic_set(&timer->overruns, 0);
     *id = timer;
     return 0;
 }
@@ -887,12 +885,6 @@ int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
 void vlc_timer_destroy (vlc_timer_t timer)
 {
     vlc_timer_schedule (timer, false, 0, 0);
-    vlc_mutex_lock (&timer->lock);
-    while (timer->users != 0)
-        vlc_cond_wait (&timer->wait, &timer->lock);
-    vlc_mutex_unlock (&timer->lock);
-
-    vlc_cond_destroy (&timer->wait);
     vlc_mutex_destroy (&timer->lock);
     free (timer);
 }
@@ -917,17 +909,17 @@ void vlc_timer_destroy (vlc_timer_t timer)
 void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
                          mtime_t value, mtime_t interval)
 {
-    static vlc_mutex_t lock = VLC_STATIC_MUTEX;
-
-    vlc_mutex_lock (&lock);
     vlc_mutex_lock (&timer->lock);
-    if (timer->value)
+    while (timer->value)
     {
+        vlc_thread_t thread = timer->thread;
+
+        timer->value = 0;
         vlc_mutex_unlock (&timer->lock);
-        vlc_cancel (timer->thread);
-        vlc_join (timer->thread, NULL);
+        vlc_cancel (thread);
+        /* cannot keep the lock during vlc_join X( */
+        vlc_join (thread, NULL);
         vlc_mutex_lock (&timer->lock);
-        timer->value = 0;
     }
     if ((value != 0)
      && (vlc_clone (&timer->thread, vlc_timer_thread, timer,
@@ -937,7 +929,6 @@ void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
         timer->interval = interval;
     }
     vlc_mutex_unlock (&timer->lock);
-    vlc_mutex_unlock (&lock);
 }
 
 /**
@@ -949,11 +940,5 @@ void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
  */
 unsigned vlc_timer_getoverrun (vlc_timer_t timer)
 {
-    unsigned ret;
-
-    vlc_mutex_lock (&timer->lock);
-    ret = timer->overruns;
-    timer->overruns = 0;
-    vlc_mutex_unlock (&timer->lock);
-    return ret;
+    return vlc_atomic_swap (&timer->overruns, 0);
 }