[vlc-devel] commit: Asynchronous timer API ( Rémi Denis-Courmont )
Pierre d'Herbemont
pdherbemont at free.fr
Wed Jun 3 06:59:19 CEST 2009
That does not work on Mac OS X, which has not Posix Timer API.
We'll need a fallback.
On Tue, Jun 2, 2009 at 11:32 AM, git version control <git at videolan.org> wrote:
> vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Tue Jun 2 20:19:19 2009 +0300| [35e2425f9a49e674683479fde78fd7972b389a71] | committer: Rémi Denis-Courmont
>
> Asynchronous timer API
>
>> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=35e2425f9a49e674683479fde78fd7972b389a71
> ---
>
> include/vlc_threads.h | 22 ++++++++++
> src/libvlccore.sym | 4 ++
> src/misc/pthread.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++
> src/misc/w32thread.c | 60 +++++++++++++++++++++++++++
> 4 files changed, 193 insertions(+), 0 deletions(-)
>
> diff --git a/include/vlc_threads.h b/include/vlc_threads.h
> index 7ccafbb..d653595 100644
> --- a/include/vlc_threads.h
> +++ b/include/vlc_threads.h
> @@ -108,6 +108,13 @@ typedef pthread_mutex_t vlc_mutex_t;
> #define VLC_STATIC_MUTEX PTHREAD_MUTEX_INITIALIZER
> typedef pthread_cond_t vlc_cond_t;
> typedef pthread_key_t vlc_threadvar_t;
> +typedef struct vlc_timer_t vlc_timer_t;
> +struct vlc_timer_t
> +{
> + timer_t handle;
> + void (*func) (vlc_timer_t *, void *);
> + void *data;
> +};
>
> #elif defined( WIN32 )
> typedef struct
> @@ -129,6 +136,16 @@ typedef struct
>
> typedef HANDLE vlc_cond_t;
> typedef DWORD vlc_threadvar_t;
> +typedef struct vlc_timer_t vlc_timer_t;
> +struct vlc_timer_t
> +{
> + HANDLE handle;
> + void (*func) (vlc_timer_t *, void *);
> + void *data;
> + unsigned overrun;
> + CRITICAL_SECTION serializer;
> + LONG volatile counter;
> +};
>
> #endif
>
> @@ -164,6 +181,11 @@ VLC_EXPORT( void, vlc_cancel, (vlc_thread_t) );
> VLC_EXPORT( void, vlc_join, (vlc_thread_t, void **) );
> VLC_EXPORT (void, vlc_control_cancel, (int cmd, ...));
>
> +VLC_EXPORT( int, vlc_timer_create, (vlc_timer_t *, void (*) (vlc_timer_t *, void *), void *) LIBVLC_USED );
> +VLC_EXPORT( void, vlc_timer_destroy, (vlc_timer_t *) );
> +VLC_EXPORT( void, vlc_timer_schedule, (vlc_timer_t *, bool, mtime_t, mtime_t) );
> +VLC_EXPORT( unsigned, vlc_timer_getoverrun, (const vlc_timer_t *) );
> +
> #ifndef LIBVLC_USE_PTHREAD_CANCEL
> enum {
> VLC_DO_CANCEL,
> diff --git a/src/libvlccore.sym b/src/libvlccore.sym
> index 239ff76..bd116a8 100644
> --- a/src/libvlccore.sym
> +++ b/src/libvlccore.sym
> @@ -522,6 +522,10 @@ vlc_threadvar_create
> vlc_threadvar_delete
> vlc_threadvar_get
> vlc_threadvar_set
> +vlc_timer_create
> +vlc_timer_destroy
> +vlc_timer_getoverrun
> +vlc_timer_schedule
> vlc_ureduce
> VLC_Version
> vlc_wclosedir
> diff --git a/src/misc/pthread.c b/src/misc/pthread.c
> index 757df9a..f3127f3 100644
> --- a/src/misc/pthread.c
> +++ b/src/misc/pthread.c
> @@ -583,3 +583,110 @@ void vlc_control_cancel (int cmd, ...)
> (void) cmd;
> assert (0);
> }
> +
> +
> +static void vlc_timer_do (union sigval val)
> +{
> + vlc_timer_t *id = val.sival_ptr;
> + id->func (id, id->data);
> +}
> +
> +/**
> + * Initializes an asynchronous timer.
> + * @warning Asynchronous timers are processed from an unspecified thread, and
> + * a timer is only serialized against itself.
> + *
> + * @param id pointer to timer to be initialized
> + * @param func function that the timer will call
> + * @param data parameter for the timer function
> + * @return 0 on success, a system error code otherwise.
> + */
> +int vlc_timer_create (vlc_timer_t *id, void (*func) (vlc_timer_t *, void *),
> + void *data)
> +{
> + struct sigevent ev;
> +
> + memset (&ev, 0, sizeof (ev));
> + ev.sigev_notify = SIGEV_THREAD;
> + ev.sigev_value.sival_ptr = id;
> + ev.sigev_notify_function = vlc_timer_do;
> + ev.sigev_notify_attributes = NULL;
> + id->func = func;
> + id->data = data;
> +
> + if (timer_create (CLOCK_MONOTONIC, &ev, &id->handle))
> + return errno;
> + return 0;
> +}
> +
> +/**
> + * Destroys an initialized timer. If needed, the timer is first disarmed.
> + * This function is undefined if the specified timer is not initialized.
> + *
> + * @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
> + */
> +void vlc_timer_destroy (vlc_timer_t *id)
> +{
> + int val = timer_delete (id->handle);
> + VLC_THREAD_ASSERT ("deleting timer");
> +}
> +
> +/**
> + * Arm or disarm an initialized timer.
> + * This functions overrides any previous call to itself.
> + *
> + * @note A timer can fire later than requested due to system scheduling
> + * limitations. An interval timer can fail to trigger sometimes, either because
> + * 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 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
> + * before firing the timer.
> + * @param interval zero to fire the timer just once, otherwise the timer
> + * repetition interval.
> + */
> +void vlc_timer_schedule (vlc_timer_t *id, bool absolute,
> + mtime_t value, mtime_t interval)
> +{
> + lldiv_t vad = lldiv (value, CLOCK_FREQ);
> + lldiv_t itd = lldiv (interval, CLOCK_FREQ);
> + struct itimerspec it = {
> + .it_interval = {
> + .tv_sec = itd.quot,
> + .tv_nsec = (1000000000 / CLOCK_FREQ) * itd.rem,
> + },
> + .it_value = {
> + .tv_sec = vad.quot,
> + .tv_nsec = (1000000000 / CLOCK_FREQ) * vad.rem,
> + },
> + };
> + int flags = absolute ? TIMER_ABSTIME : 0;
> +
> + int val = timer_settime (id->handle, flags, &it, NULL);
> + VLC_THREAD_ASSERT ("scheduling timer");
> +}
> +
> +/**
> + * @param id initialized timer pointer
> + * @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)
> +{
> + int val = timer_getoverrun (id->handle);
> +#ifndef NDEBUG
> + if (val == -1)
> + {
> + val = errno;
> + VLC_THREAD_ASSERT ("fetching timer overrun counter");
> + }
> +#endif
> + return val;
> +}
> diff --git a/src/misc/w32thread.c b/src/misc/w32thread.c
> index 5e187ca..60f72c7 100644
> --- a/src/misc/w32thread.c
> +++ b/src/misc/w32thread.c
> @@ -510,3 +510,63 @@ void vlc_control_cancel (int cmd, ...)
> }
> va_end (ap);
> }
> +
> +
> +/*** Timers ***/
> +static void CALLBACK vlc_timer_do (void *val, BOOLEAN timeout)
> +{
> + vlc_timer_t *id = val;
> +
> + assert (timeout);
> + if (TryEnterCriticalSection (&id->serializer))
> + {
> + id->overrun = InterlockedExchange (&id->counter, 0);
> + id->func (id, id->data);
> + LeaveCriticalSection (&id->serializer);
> + }
> + else /* Overrun */
> + InterlockedIncrement (&id->counter);
> +}
> +
> +int vlc_timer_create (vlc_timer_t *id, void (*func) (vlc_timer_t *, void *),
> + void *data)
> +{
> + id->func = func;
> + id->data = data;
> + id->overrun = 0;
> + id->handle = INVALID_HANDLE_VALUE;
> + InitializeCriticalSection (&id->serializer);
> + return 0;
> +}
> +
> +void vlc_timer_destroy (vlc_timer_t *id)
> +{
> + if (id->handle != INVALID_HANDLE_VALUE)
> + DeleteTimerQueueTimer (NULL, id->handle, NULL);
> + DeleteCriticalSection (&id->serializer);
> +}
> +
> +void vlc_timer_schedule (vlc_timer_t *id, bool absolute,
> + mtime_t value, mtime_t interval)
> +{
> + if (id->handle != INVALID_HANDLE_VALUE)
> + {
> + DeleteTimerQueueTimer (NULL, id->handle, NULL);
> + id->handle = INVALID_HANDLE_VALUE;
> + }
> + if (value == 0)
> + return; /* Disarm */
> +
> + if (absolute)
> + value -= mdate ();
> + value = (value + 999) / 1000;
> + interval = (interval + 999) / 1000;
> + if (!CreateTimerQueueTimer (&id->handle, NULL, vlc_timer_do, id, value,
> + interval, WT_EXECUTEDEFAULT))
> + abort ();
> +}
> +
> +unsigned vlc_timer_getoverrun (const vlc_timer_t *id)
> +{
> + return id->overrun;
> +}
>
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> http://mailman.videolan.org/listinfo/vlc-devel
>
More information about the vlc-devel
mailing list