[vlc-devel] commit: Asynchronous timer API ( Rémi Denis-Courmont )

Derk-Jan Hartman hartman at videolan.org
Wed Jun 3 12:12:26 CEST 2009


On 3 jun 2009, at 06:59, Pierre d'Herbemont wrote:
> That does not work on Mac OS X, which has not Posix Timer API.
>
> We'll need a fallback.


W00t Apple :(
Incredible annoying. Anyways, what are our options ? Are there any  
mach timer's or something that have roughly the same behaviour ? I  
suspect setitimer() is not a good alternative ?

DJ


> 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
>>
> _______________________________________________
> 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