[vlc-devel] [PATCH] win32: use the ThreadPoolTimer API to handle timers
Rémi Denis-Courmont
remi at remlab.net
Thu Jun 11 17:25:03 CEST 2020
Le keskiviikkona 10. kesäkuuta 2020, 15.00.57 EEST Steve Lhomme a écrit :
> This is available since Windows 7 and is allowed in Winstore apps. So we
> only maintain one code for all Windows versions.
>
> It should handle timers with an absolute time better as they had to be
> turned into relative times but the system sleep was delaying the timer. [1]
>
> [1]
> https://docs.microsoft.com/en-us/windows/win32/api/threadpoollegacyapiset/n
> f-threadpoollegacyapiset-createtimerqueuetimer "The time that the system
> spends in sleep or hibernation does not count toward the expiration of the
> timer."
> ---
> src/Makefile.am | 5 +++--
> src/win32/timer.c | 46 ++++++++++++++++++++++++----------------------
> 2 files changed, 27 insertions(+), 24 deletions(-)
>
> diff --git a/src/Makefile.am b/src/Makefile.am
> index 9e088c1fd9e6..dc75776d7af7 100644
> --- a/src/Makefile.am
> +++ b/src/Makefile.am
> @@ -406,11 +406,12 @@ libvlccore_la_SOURCES += \
> win32/rand.c \
> win32/specific.c \
> win32/thread.c \
> + win32/timer.c \
> win32/winsock.c
> if HAVE_WINSTORE
> -libvlccore_la_SOURCES += posix/timer.c win32/dirs-uap.c
> +libvlccore_la_SOURCES += win32/dirs-uap.c
> else
> -libvlccore_la_SOURCES += win32/timer.c win32/dirs.c
> +libvlccore_la_SOURCES += win32/dirs.c
> endif
> endif
>
> diff --git a/src/win32/timer.c b/src/win32/timer.c
> index 4fe3d2b067cb..4a2d68f996fb 100644
> --- a/src/win32/timer.c
> +++ b/src/win32/timer.c
> @@ -29,16 +29,16 @@
>
> struct vlc_timer
> {
> - HANDLE handle;
> + PTP_TIMER ptimer;
> void (*func) (void *);
> void *data;
> };
>
> -static void CALLBACK vlc_timer_do (void *val, BOOLEAN timeout)
> +static void CALLBACK vlc_timer_do(PTP_CALLBACK_INSTANCE instance, void
> *val, PTP_TIMER ptimer) {
> + (void) instance; (void) ptimer;
> struct vlc_timer *timer = val;
>
> - assert (timeout);
> timer->func (timer->data);
> }
>
> @@ -50,50 +50,52 @@ int vlc_timer_create (vlc_timer_t *id, void (*func)
> (void *), void *data) return ENOMEM;
> timer->func = func;
> timer->data = data;
> - timer->handle = INVALID_HANDLE_VALUE;
> + timer->ptimer = CreateThreadpoolTimer(vlc_timer_do, timer, NULL);
> + if (unlikely(timer->ptimer == NULL))
> + {
> + free(timer);
> + return EFAULT;
Is EFAULT really the intended error scenario? IMO, it's better to abort than
return EFAULT, because it can only mean the calling code is buggy.
> + }
> *id = timer;
> return 0;
> }
>
> void vlc_timer_destroy (vlc_timer_t timer)
> {
> - if (timer->handle != INVALID_HANDLE_VALUE)
> - DeleteTimerQueueTimer (NULL, timer->handle, INVALID_HANDLE_VALUE);
> + SetThreadpoolTimer(timer->ptimer, NULL, 0, 0);
> + WaitForThreadpoolTimerCallbacks(timer->ptimer, TRUE);
> + CloseThreadpoolTimer(timer->ptimer);
> free (timer);
> }
>
> void vlc_timer_schedule (vlc_timer_t timer, bool absolute,
> vlc_tick_t value, vlc_tick_t interval)
> {
> - if (timer->handle != INVALID_HANDLE_VALUE)
> - {
> - DeleteTimerQueueTimer (NULL, timer->handle, INVALID_HANDLE_VALUE);
> - timer->handle = INVALID_HANDLE_VALUE;
> - }
> + SetThreadpoolTimer(timer->ptimer, NULL, 0, 0);
> + WaitForThreadpoolTimerCallbacks(timer->ptimer, TRUE);
> if (value == VLC_TIMER_DISARM)
> return; /* Disarm */
>
> + ULARGE_INTEGER s;
> if (absolute)
> - {
> - value -= vlc_tick_now ();
> - if (value < 0)
> - value = 0;
> - }
> + s.QuadPart = MSFTIME_FROM_VLC_TICK(value);
> + else
> + s.QuadPart = -MSFTIME_FROM_VLC_TICK(value);
> + FILETIME ts;
> + ts.dwLowDateTime = s.LowPart;
> + ts.dwHighDateTime = s.HighPart;
>
> - DWORD val = MS_FROM_VLC_TICK(value);
> DWORD interv = MS_FROM_VLC_TICK(interval);
> - if (val == 0 && value != 0)
> - val = 1; /* rounding error */
> if (interv == 0 && interval != 0)
> interv = 1; /* rounding error */
>
> - if (!CreateTimerQueueTimer(&timer->handle, NULL, vlc_timer_do, timer,
> - val, interv, WT_EXECUTEDEFAULT))
> - abort ();
> + WaitForThreadpoolTimerCallbacks(timer->ptimer, FALSE);
> + SetThreadpoolTimer(timer->ptimer, &ts, interv, 0 );
> }
>
> unsigned vlc_timer_getoverrun (vlc_timer_t timer)
> {
> + // TODO return the amount of missed timers if any
> (void)timer;
> return 0;
> }
--
Rémi Denis-Courmont
http://www.remlab.net/
More information about the vlc-devel
mailing list