[PATCH v2 0/3] MR10095: mf: Implement IMFTimer using a periodic callback.
In preparation for adding the `IMFPresentationTimeSource` interface to SAR, this MR adds tests for `IMFPresentationClock` using a custom `IMFPresentationTimeSource`. These tests highlighted a couple of issues in wine: 1. Clock events are sent to a clock sink twice if it is also the presentation time source; and 2. The `IMFTimer::SetTimer` calls do not work correctly. This MR also addresses both of these issues. -- v2: mf: Implement IMFTimer using a periodic callback. mf: Don't async notify a sink that is also the time source. mf/tests: Test presentation clock with custom time source. https://gitlab.winehq.org/wine/wine/-/merge_requests/10095
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/tests/mf.c | 230 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index df1362381b2..ef4a71f8055 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -3876,6 +3876,192 @@ static const IMFClockStateSinkVtbl test_clock_sink_vtbl = test_clock_sink_OnClockSetRate, }; +struct test_time_source +{ + IMFPresentationTimeSource IMFPresentationTimeSource_iface; + IMFClockStateSink IMFClockStateSink_iface; + LONG refcount; + LONGLONG time; +}; + +static struct test_time_source *test_time_source_from_IMFPresentationTimeSource(IMFPresentationTimeSource *iface) +{ + return CONTAINING_RECORD(iface, struct test_time_source, IMFPresentationTimeSource_iface); +} + +static HRESULT WINAPI test_time_source_QueryInterface(IMFPresentationTimeSource *iface, REFIID riid, void **obj) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFPresentationTimeSource(iface); + + if (IsEqualGUID(riid, &IID_IMFPresentationTimeSource) || + IsEqualGUID(riid, &IID_IMFClock) || + IsEqualGUID(riid, &IID_IUnknown)) + { + *obj = iface; + } + else if (IsEqualGUID(riid, &IID_IMFClockStateSink)) + { + *obj = &test_time_source->IMFClockStateSink_iface; + } + else + { + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*obj); + return S_OK; +} + +static ULONG WINAPI test_time_source_AddRef(IMFPresentationTimeSource *iface) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFPresentationTimeSource(iface); + ULONG refcount = InterlockedIncrement(&test_time_source->refcount); + return refcount; +} + +static ULONG WINAPI test_time_source_Release(IMFPresentationTimeSource *iface) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFPresentationTimeSource(iface); + ULONG refcount = InterlockedDecrement(&test_time_source->refcount); + + if (!refcount) + free(test_time_source); + + return refcount; +} + +static HRESULT WINAPI test_time_source_GetClockCharacteristics(IMFPresentationTimeSource *iface, DWORD *flags) +{ + *flags = MFCLOCK_CHARACTERISTICS_FLAG_FREQUENCY_10MHZ; + + return S_OK; +} + +static HRESULT WINAPI test_time_source_GetCorrelatedTime(IMFPresentationTimeSource *iface, DWORD reserved, + LONGLONG *clock_time, MFTIME *system_time) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFPresentationTimeSource(iface); + + *clock_time = test_time_source->time; + *system_time = MFGetSystemTime(); + + return S_OK; +} + +static HRESULT WINAPI test_time_source_GetContinuityKey(IMFPresentationTimeSource *iface, DWORD *key) +{ + return E_NOTIMPL; +} + + +static HRESULT WINAPI test_time_source_GetState(IMFPresentationTimeSource *iface, DWORD reserved, + MFCLOCK_STATE *state) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_GetProperties(IMFPresentationTimeSource *iface, MFCLOCK_PROPERTIES *props) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_GetUnderlyingClock(IMFPresentationTimeSource *iface, IMFClock **clock) +{ + return MF_E_NO_CLOCK; +} + +DEFINE_EXPECT(test_time_source_sink_OnClockStart); + +static IMFPresentationTimeSourceVtbl test_time_source_vtbl = +{ + test_time_source_QueryInterface, + test_time_source_AddRef, + test_time_source_Release, + test_time_source_GetClockCharacteristics, + test_time_source_GetCorrelatedTime, + test_time_source_GetContinuityKey, + test_time_source_GetState, + test_time_source_GetProperties, + test_time_source_GetUnderlyingClock, +}; + +static struct test_time_source *test_time_source_from_IMFClockStateSink(IMFClockStateSink *iface) +{ + return CONTAINING_RECORD(iface, struct test_time_source, IMFClockStateSink_iface); +} + +static HRESULT WINAPI test_time_source_sink_QueryInterface(IMFClockStateSink *iface, REFIID riid, void **obj) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFClockStateSink(iface); + return IMFPresentationTimeSource_QueryInterface(&test_time_source->IMFPresentationTimeSource_iface, riid, obj); +} + +static ULONG WINAPI test_time_source_sink_AddRef(IMFClockStateSink *iface) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFClockStateSink(iface); + return IMFPresentationTimeSource_AddRef(&test_time_source->IMFPresentationTimeSource_iface); +} + +static ULONG WINAPI test_time_source_sink_Release(IMFClockStateSink *iface) +{ + struct test_time_source *test_time_source = test_time_source_from_IMFClockStateSink(iface); + return IMFPresentationTimeSource_Release(&test_time_source->IMFPresentationTimeSource_iface); +} + +static HRESULT WINAPI test_time_source_sink_OnClockStart(IMFClockStateSink *iface, MFTIME system_time, LONGLONG offset) +{ + HRESULT hr; + + hr = (expect_test_time_source_sink_OnClockStart) ? S_OK : E_NOTIMPL; + todo_wine_if(!expect_test_time_source_sink_OnClockStart) + CHECK_EXPECT(test_time_source_sink_OnClockStart); + return hr; +} + +static HRESULT WINAPI test_time_source_sink_OnClockStop(IMFClockStateSink *iface, MFTIME system_time) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_sink_OnClockPause(IMFClockStateSink *iface, MFTIME system_time) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_sink_OnClockRestart(IMFClockStateSink *iface, MFTIME system_time) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI test_time_source_sink_OnClockSetRate(IMFClockStateSink *iface, MFTIME system_time, float rate) +{ + return E_NOTIMPL; +} + +static IMFClockStateSinkVtbl test_time_source_sink_vtbl = +{ + test_time_source_sink_QueryInterface, + test_time_source_sink_AddRef, + test_time_source_sink_Release, + test_time_source_sink_OnClockStart, + test_time_source_sink_OnClockStop, + test_time_source_sink_OnClockPause, + test_time_source_sink_OnClockRestart, + test_time_source_sink_OnClockSetRate, +}; + +struct test_time_source *create_test_time_source(void) +{ + struct test_time_source *test_time_source; + test_time_source = calloc(1, sizeof(*test_time_source)); + test_time_source->IMFPresentationTimeSource_iface.lpVtbl = &test_time_source_vtbl; + test_time_source->IMFClockStateSink_iface.lpVtbl = &test_time_source_sink_vtbl; + test_time_source->refcount = 1; + + return test_time_source; +} + static void test_presentation_clock(void) { static const struct clock_state_test @@ -3904,6 +4090,7 @@ static void test_presentation_clock(void) { CLOCK_START, MFCLOCK_STATE_RUNNING, MFCLOCK_STATE_RUNNING }, }; IMFClockStateSink test_sink = { &test_clock_sink_vtbl }; + struct test_time_source *test_time_source; IMFPresentationTimeSource *time_source; struct test_callback *timer_callback; MFCLOCK_PROPERTIES props, props2; @@ -4207,6 +4394,49 @@ static void test_presentation_clock(void) IMFPresentationClock_Release(clock); + /* Test with a custom presentation time source */ + hr = MFCreatePresentationClock(&clock); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + test_time_source = create_test_time_source(); + time_source = &test_time_source->IMFPresentationTimeSource_iface; + + hr = IMFPresentationClock_SetTimeSource(clock, time_source); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IMFPresentationClock_AddClockStateSink(clock, &test_time_source->IMFClockStateSink_iface); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + SET_EXPECT(test_time_source_sink_OnClockStart); + hr = IMFPresentationClock_Start(clock, 0); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(test_time_source_sink_OnClockStart); + + hr = IMFPresentationClock_QueryInterface(clock, &IID_IMFTimer, (void **)&timer); + ok(hr == S_OK, "got hr %#lx.\n", hr); + + callback = create_test_callback(FALSE); + timer_callback = impl_from_IMFAsyncCallback(callback); + hr = IMFTimer_SetTimer(timer, 0, 1000000, callback, NULL, &timer_cancel_key); + ok(hr == S_OK, "got hr %#lx.\n", hr); + todo_wine + ok(WaitForSingleObject(timer_callback->event, 4000) == WAIT_TIMEOUT, "WaitForSingleObject should timeout.\n"); + + /* the timer will only trigger when the time of the time source is within 5ms of the target time */ + test_time_source->time = 1000000-50001; + ok(WaitForSingleObject(timer_callback->event, 4000) == WAIT_TIMEOUT, "WaitForSingleObject should timeout.\n"); + + test_time_source->time = 1000000-50000; + todo_wine + ok(WaitForSingleObject(timer_callback->event, 4000) == WAIT_OBJECT_0, "WaitForSingleObject failed.\n"); + + IUnknown_Release(timer_cancel_key); + IMFTimer_Release(timer); + IMFAsyncCallback_Release(callback); + + IMFPresentationTimeSource_Release(time_source); + IMFPresentationClock_Release(clock); + hr = MFShutdown(); ok(hr == S_OK, "Failed to shut down, hr %#lx.\n", hr); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10095
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/clock.c | 4 +++- dlls/mf/tests/mf.c | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/dlls/mf/clock.c b/dlls/mf/clock.c index 997994fc5f9..364d5a69c01 100644 --- a/dlls/mf/clock.c +++ b/dlls/mf/clock.c @@ -640,7 +640,9 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c LIST_FOR_EACH_ENTRY(sink, &clock->sinks, struct clock_sink, entry) { - clock_notify_async_sink(clock, system_time, param, notification, sink->state_sink); + /* Don't notify a sink that is also the time source */ + if (clock->time_source_sink != sink->state_sink) + clock_notify_async_sink(clock, system_time, param, notification, sink->state_sink); } return S_OK; diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index ef4a71f8055..77386d8ec32 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4014,7 +4014,6 @@ static HRESULT WINAPI test_time_source_sink_OnClockStart(IMFClockStateSink *ifac HRESULT hr; hr = (expect_test_time_source_sink_OnClockStart) ? S_OK : E_NOTIMPL; - todo_wine_if(!expect_test_time_source_sink_OnClockStart) CHECK_EXPECT(test_time_source_sink_OnClockStart); return hr; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10095
From: Brendan McGrath <bmcgrath@codeweavers.com> --- dlls/mf/clock.c | 161 ++++++++++++++------------------------------- dlls/mf/tests/mf.c | 2 - 2 files changed, 48 insertions(+), 115 deletions(-) diff --git a/dlls/mf/clock.c b/dlls/mf/clock.c index 364d5a69c01..b13faaf44c9 100644 --- a/dlls/mf/clock.c +++ b/dlls/mf/clock.c @@ -72,9 +72,8 @@ struct clock_timer { IUnknown IUnknown_iface; LONG refcount; + LONGLONG time; IMFAsyncResult *result; - IMFAsyncCallback *callback; - MFWORKITEM_KEY key; struct list entry; }; @@ -85,7 +84,6 @@ struct presentation_clock IMFTimer IMFTimer_iface; IMFShutdown IMFShutdown_iface; IMFAsyncCallback sink_callback; - IMFAsyncCallback timer_callback; LONG refcount; IMFPresentationTimeSource *time_source; IMFClockStateSink *time_source_sink; @@ -97,6 +95,7 @@ struct presentation_clock LONGLONG frequency; CRITICAL_SECTION cs; BOOL is_shut_down; + DWORD key; }; static struct presentation_clock *impl_from_IMFPresentationClock(IMFPresentationClock *iface) @@ -124,11 +123,6 @@ static struct presentation_clock *impl_from_sink_callback_IMFAsyncCallback(IMFAs return CONTAINING_RECORD(iface, struct presentation_clock, sink_callback); } -static struct presentation_clock *impl_from_timer_callback_IMFAsyncCallback(IMFAsyncCallback *iface) -{ - return CONTAINING_RECORD(iface, struct presentation_clock, timer_callback); -} - static struct clock_timer *impl_clock_timer_from_IUnknown(IUnknown *iface) { return CONTAINING_RECORD(iface, struct clock_timer, IUnknown_iface); @@ -555,6 +549,39 @@ static HRESULT clock_call_state_change(MFTIME system_time, struct clock_state_ch return hr; } +static struct clock_timer *presentation_clock_next_timer(struct presentation_clock *clock, LONGLONG time) +{ + struct clock_timer *timer; + + LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry) + { + if (timer->time <= time + 50000) + return timer; + } + + return NULL; +} + +static void CALLBACK presentation_clock_timer_callback(IUnknown *context) +{ + struct presentation_clock *clock = impl_from_IMFPresentationClock((IMFPresentationClock*)context); + struct clock_timer *timer; + LONGLONG time, systime; + + EnterCriticalSection(&clock->cs); + if (clock->time_source && + SUCCEEDED(IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, &time, &systime))) + { + while ( (timer = presentation_clock_next_timer(clock, time)) ) + { + list_remove(&timer->entry); + MFInvokeCallback(timer->result); + IUnknown_Release(&timer->IUnknown_iface); + } + } + LeaveCriticalSection(&clock->cs); +} + static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_command command, struct clock_state_change_param param) { @@ -574,7 +601,6 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c enum clock_notification notification; struct clock_sink *sink; MFCLOCK_STATE old_state; - IMFAsyncResult *result; MFTIME system_time; HRESULT hr; @@ -609,31 +635,17 @@ static HRESULT clock_change_state(struct presentation_clock *clock, enum clock_c transitioning from running state. */ if ((clock->state == MFCLOCK_STATE_RUNNING) ^ (old_state == MFCLOCK_STATE_RUNNING)) { - struct clock_timer *timer, *timer2; - if (clock->state == MFCLOCK_STATE_RUNNING) { - LIST_FOR_EACH_ENTRY_SAFE(timer, timer2, &clock->timers, struct clock_timer, entry) - { - list_remove(&timer->entry); - hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result); - IUnknown_Release(&timer->IUnknown_iface); - if (SUCCEEDED(hr)) - { - MFPutWorkItemEx(MFASYNC_CALLBACK_QUEUE_TIMER, result); - IMFAsyncResult_Release(result); - } - } + if (FAILED(hr = MFAddPeriodicCallback(presentation_clock_timer_callback, (IUnknown*)&clock->IMFPresentationClock_iface, &clock->key))) + ERR("Failed to start periodic callback %#lx\n", hr); } else { - LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry) + if (clock->key) { - if (timer->key) - { - MFCancelWorkItem(timer->key); - timer->key = 0; - } + MFRemovePeriodicCallback(clock->key); + clock->key = 0; } } } @@ -799,39 +811,24 @@ static ULONG WINAPI present_clock_timer_Release(IMFTimer *iface) } static HRESULT present_clock_schedule_timer(struct presentation_clock *clock, DWORD flags, LONGLONG time, - struct clock_timer *timer) + IMFAsyncCallback *callback, IUnknown *state, struct clock_timer *timer) { - IMFAsyncResult *result; MFTIME systime, clocktime; - LONGLONG frequency; HRESULT hr; - if (!(flags & MFTIMER_RELATIVE)) + timer->time = time; + + if (flags & MFTIMER_RELATIVE) { if (FAILED(hr = IMFPresentationTimeSource_GetCorrelatedTime(clock->time_source, 0, &clocktime, &systime))) { WARN("Failed to get clock time, hr %#lx.\n", hr); return hr; } - if (time > clocktime) - time -= clocktime; - else - time = 0; + timer->time += clocktime; } - frequency = clock->frequency / 1000; - time /= frequency; - - /* Scheduled item is using clock instance callback, with timer instance as an object. Clock callback will - call user callback and cleanup timer list. */ - - if (FAILED(hr = MFCreateAsyncResult(&timer->IUnknown_iface, &clock->timer_callback, NULL, &result))) - return hr; - - hr = MFScheduleWorkItemEx(result, -time, &timer->key); - IMFAsyncResult_Release(result); - - return hr; + return MFCreateAsyncResult(NULL, callback, state, &timer->result); } static HRESULT WINAPI clock_timer_QueryInterface(IUnknown *iface, REFIID riid, void **obj) @@ -861,7 +858,6 @@ static ULONG WINAPI clock_timer_Release(IUnknown *iface) if (!refcount) { IMFAsyncResult_Release(timer->result); - IMFAsyncCallback_Release(timer->callback); free(timer); } @@ -887,7 +883,7 @@ static HRESULT WINAPI present_clock_timer_SetTimer(IMFTimer *iface, DWORD flags, if (!(clock_timer = calloc(1, sizeof(*clock_timer)))) return E_OUTOFMEMORY; - if (FAILED(hr = MFCreateAsyncResult(NULL, NULL, state, &clock_timer->result))) + if (FAILED(hr = present_clock_schedule_timer(clock, flags, time, callback, state, clock_timer))) { free(clock_timer); return hr; @@ -895,14 +891,10 @@ static HRESULT WINAPI present_clock_timer_SetTimer(IMFTimer *iface, DWORD flags, clock_timer->IUnknown_iface.lpVtbl = &clock_timer_vtbl; clock_timer->refcount = 1; - clock_timer->callback = callback; - IMFAsyncCallback_AddRef(clock_timer->callback); EnterCriticalSection(&clock->cs); - if (clock->state == MFCLOCK_STATE_RUNNING) - hr = present_clock_schedule_timer(clock, flags, time, clock_timer); - else if (clock->state == MFCLOCK_STATE_STOPPED) + if (clock->state == MFCLOCK_STATE_STOPPED) hr = MF_S_CLOCK_STOPPED; if (SUCCEEDED(hr)) @@ -937,11 +929,6 @@ static HRESULT WINAPI present_clock_timer_CancelTimer(IMFTimer *iface, IUnknown if (&timer->IUnknown_iface == cancel_key) { list_remove(&timer->entry); - if (timer->key) - { - MFCancelWorkItem(timer->key); - timer->key = 0; - } IUnknown_Release(&timer->IUnknown_iface); break; } @@ -1080,57 +1067,6 @@ static const IMFAsyncCallbackVtbl presentclocksinkcallbackvtbl = present_clock_sink_callback_Invoke, }; -static ULONG WINAPI present_clock_timer_callback_AddRef(IMFAsyncCallback *iface) -{ - struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface); - return IMFPresentationClock_AddRef(&clock->IMFPresentationClock_iface); -} - -static ULONG WINAPI present_clock_timer_callback_Release(IMFAsyncCallback *iface) -{ - struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface); - return IMFPresentationClock_Release(&clock->IMFPresentationClock_iface); -} - -static HRESULT WINAPI present_clock_timer_callback_Invoke(IMFAsyncCallback *iface, IMFAsyncResult *result) -{ - struct presentation_clock *clock = impl_from_timer_callback_IMFAsyncCallback(iface); - struct clock_timer *timer; - IUnknown *object; - HRESULT hr; - - if (FAILED(hr = IMFAsyncResult_GetObject(result, &object))) - return hr; - - EnterCriticalSection(&clock->cs); - LIST_FOR_EACH_ENTRY(timer, &clock->timers, struct clock_timer, entry) - { - if (&timer->IUnknown_iface == object) - { - list_remove(&timer->entry); - IUnknown_Release(&timer->IUnknown_iface); - break; - } - } - LeaveCriticalSection(&clock->cs); - - timer = impl_clock_timer_from_IUnknown(object); - IMFAsyncCallback_Invoke(timer->callback, timer->result); - - IUnknown_Release(object); - - return S_OK; -} - -static const IMFAsyncCallbackVtbl presentclocktimercallbackvtbl = -{ - present_clock_callback_QueryInterface, - present_clock_timer_callback_AddRef, - present_clock_timer_callback_Release, - present_clock_callback_GetParameters, - present_clock_timer_callback_Invoke, -}; - /*********************************************************************** * MFCreatePresentationClock (mf.@) */ @@ -1148,7 +1084,6 @@ HRESULT WINAPI MFCreatePresentationClock(IMFPresentationClock **clock) object->IMFTimer_iface.lpVtbl = &presentclocktimervtbl; object->IMFShutdown_iface.lpVtbl = &presentclockshutdownvtbl; object->sink_callback.lpVtbl = &presentclocksinkcallbackvtbl; - object->timer_callback.lpVtbl = &presentclocktimercallbackvtbl; object->refcount = 1; list_init(&object->sinks); list_init(&object->timers); diff --git a/dlls/mf/tests/mf.c b/dlls/mf/tests/mf.c index 77386d8ec32..8bc3f83019c 100644 --- a/dlls/mf/tests/mf.c +++ b/dlls/mf/tests/mf.c @@ -4418,7 +4418,6 @@ static void test_presentation_clock(void) timer_callback = impl_from_IMFAsyncCallback(callback); hr = IMFTimer_SetTimer(timer, 0, 1000000, callback, NULL, &timer_cancel_key); ok(hr == S_OK, "got hr %#lx.\n", hr); - todo_wine ok(WaitForSingleObject(timer_callback->event, 4000) == WAIT_TIMEOUT, "WaitForSingleObject should timeout.\n"); /* the timer will only trigger when the time of the time source is within 5ms of the target time */ @@ -4426,7 +4425,6 @@ static void test_presentation_clock(void) ok(WaitForSingleObject(timer_callback->event, 4000) == WAIT_TIMEOUT, "WaitForSingleObject should timeout.\n"); test_time_source->time = 1000000-50000; - todo_wine ok(WaitForSingleObject(timer_callback->event, 4000) == WAIT_OBJECT_0, "WaitForSingleObject failed.\n"); IUnknown_Release(timer_cancel_key); -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10095
v2: - update comment to read "Don't notify..."; - move critical section in `presentation_clock_timer_callback` to include check and use of `clock->time_source` - rebase to master -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10095#note_130298
On Tue Feb 24 00:14:10 2026 +0000, Nikolay Sivov wrote:
This should read "Don't notify...", otherwise it sounds optional. Good point. That is done.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10095#note_130299
On Tue Feb 24 00:14:47 2026 +0000, Nikolay Sivov wrote:
This does not look safe, in terms of "time_source". Good catch. I've moved the critical section to include the check and use of `time_source`.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10095#note_130302
On Mon Feb 23 21:10:35 2026 +0000, Nikolay Sivov wrote:
Why 50000? This matches Windows behaviour. The periodic timer is 10ms, so I guess the idea is (in an ideal situation) it triggers the timer between 5ms early to 5ms late. Rather than never early and up to 10ms late.
That is what I am testing for here: https://gitlab.winehq.org/wine/wine/-/merge_requests/10095/diffs#38af2002cda... -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10095#note_130303
On Tue Feb 24 00:20:35 2026 +0000, Nikolay Sivov wrote:
Could you explain why periodic callback is the right choice? This seems to match Windows behaviour. I of course can't be sure it's using that, but it seems to trigger every 10ms (which is what the periodic callback does). I guess it allows for arbitrary time sources that may not advance in a uniform manner.
-- https://gitlab.winehq.org/wine/wine/-/merge_requests/10095#note_130304
This merge request was approved by Nikolay Sivov. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10095
participants (3)
-
Brendan McGrath -
Brendan McGrath (@redmcg) -
Nikolay Sivov (@nsivov)