Skip to content
Snippets Groups Projects
Commit 9fdd9fb1 authored by Thomas Guillem's avatar Thomas Guillem
Browse files

win32: timer: use threadpoolapiset.h

New API: https://docs.microsoft.com/en-us/windows/win32/procthread/thread-pool-api

This avoid one allocation (that can fail) in vlc_timer_schedule() (that
was handled with a call to abort()).

One remark from the documentation: "If the due time specified by
pftDueTime is relative, the time that the system spends in sleep or
hibernation does not count toward the expiration of the timer. The timer
is signaled when the cumulative amount of elapsed time the system spends
in the waking state equals the timer's relative due time or period. If
the due time specified by pftDueTime is absolute, the time that the
system spends in sleep or hibernation does count toward the expiration
of the timer. If the timer expires while the system is sleeping, the
timer is signaled immediately when the system wakes."

For that reason, the vlc_timer API always use a absolute FILETIME in
SetThreadpoolTimer(). vlc_timer absolute ticks are substracted with
vlc_tick_now() and added to the absolute FILETIME.
parent e1278328
No related branches found
No related tags found
1 merge request!2190win32: timer: use threadpoolapiset.h
Pipeline #241037 passed with stage
in 17 minutes and 17 seconds
......@@ -29,17 +29,19 @@
struct vlc_timer
{
HANDLE handle;
PTP_TIMER t;
void (*func) (void *);
void *data;
};
static void CALLBACK vlc_timer_do (void *val, BOOLEAN timeout)
static VOID CALLBACK timer_callback(PTP_CALLBACK_INSTANCE instance,
PVOID context, PTP_TIMER t)
{
struct vlc_timer *timer = val;
(void) instance;
(void) t; assert(t);
struct vlc_timer *timer = context;
assert (timeout);
timer->func (timer->data);
timer->func(timer->data);
}
int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
......@@ -48,48 +50,79 @@ int vlc_timer_create (vlc_timer_t *id, void (*func) (void *), void *data)
if (timer == NULL)
return ENOMEM;
timer->t = CreateThreadpoolTimer(timer_callback, timer, NULL);
if (timer->t == NULL)
{
free(timer);
return ENOMEM;
}
assert(func);
timer->func = func;
timer->data = data;
timer->handle = INVALID_HANDLE_VALUE;
*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);
free (timer);
SetThreadpoolTimer(timer->t, NULL, 0, 0);
WaitForThreadpoolTimerCallbacks(timer->t, TRUE);
CloseThreadpoolTimer(timer->t);
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)
if (value == VLC_TIMER_DISARM)
{
DeleteTimerQueueTimer (NULL, timer->handle, INVALID_HANDLE_VALUE);
timer->handle = INVALID_HANDLE_VALUE;
SetThreadpoolTimer(timer->t, NULL, 0, 0);
/* Cancel any pending callbacks */
WaitForThreadpoolTimerCallbacks(timer->t, TRUE);
return;
}
if (value == VLC_TIMER_DISARM)
return; /* Disarm */
/* Always use absolute FILETIME (positive) since "the time that the system
* spends in sleep or hibernation does count toward the expiration of the
* timer. */
/* Convert the tick value to a relative tick. */
if (absolute)
value -= vlc_tick_now();
if (value < 0)
value = 0;
/* Get the system FILETIME */
FILETIME time;
#if (_WIN32_WINNT >= _WIN32_WINNT_WIN8) && (!defined(VLC_WINSTORE_APP) || _WIN32_WINNT >= 0x0A00)
GetSystemTimePreciseAsFileTime(&time);
#else
GetSystemTimeAsFileTime(&time);
#endif
/* Convert it to ULARGE_INTEGER to allow calculation (addition here) */
ULARGE_INTEGER time_ul = {
.LowPart = time.dwLowDateTime,
.HighPart = time.dwHighDateTime,
};
/* Add the relative tick to the absolute time */
time_ul.QuadPart += MSFTIME_FROM_VLC_TICK(value);
/* Convert it back to a FILETIME*/
time.dwLowDateTime = time_ul.u.LowPart;
time.dwHighDateTime = time_ul.u.HighPart;
DWORD intervaldw;
if (interval == VLC_TIMER_FIRE_ONCE)
intervaldw = 0;
else
{
value -= vlc_tick_now ();
if (value < 0)
value = 0;
uint64_t intervalms = MS_FROM_VLC_TICK(interval);
intervaldw = unlikely(intervalms > UINT32_MAX) ? UINT32_MAX : intervalms;
}
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 ();
SetThreadpoolTimer(timer->t, &time, intervaldw, 0);
}
unsigned vlc_timer_getoverrun (vlc_timer_t timer)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment