[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