[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