[vlc-devel] [PATCH] win32: use the ThreadPoolTimer API to handle timers

Steve Lhomme robux4 at ycbcr.xyz
Fri Jun 12 07:31:30 CEST 2020


On 2020-06-11 17:25, Rémi Denis-Courmont wrote:
> 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.

I would never add an abort in the core (or in modules for that matter). 
If you mean asserting, maybe. But do have a return value here that 
callers should handle (and they do) so I don't see why we would want to 
add extra checks.

I don't see how this is a bug in our code if the OS cannot create a 
timer pool at that moment. The documentation doesn't say in which case 
it can happen, but it can.

>> +    }
>>       *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/
> 
> 
> 
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel
> 


More information about the vlc-devel mailing list