#endif
#include <vlc_common.h>
+#include <vlc_atomic.h>
#include "libvlc.h"
#include <stdarg.h>
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
}
/**
void vlc_cancel (vlc_thread_t thread_id)
{
pthread_cancel (thread_id);
+#ifdef HAVE_MAEMO
+ pthread_kill (thread_id, SIGRTMIN);
+#endif
}
/**
{
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;
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;
}
}
/**
* 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
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;
}
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);
}
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,
timer->interval = interval;
}
vlc_mutex_unlock (&timer->lock);
- vlc_mutex_unlock (&lock);
}
/**
*/
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);
}