ntoskrnl.exe: Reimplement KeSetTimerEx() on top of thread pool.

This is needed to call the DPC callbacks later as SetWaitableTimer()
will call the callback only when the thread is in alertable
wait state.

Signed-off-by: Paul Gofman <pgofman@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Paul Gofman 2020-05-28 12:15:16 +03:00 committed by Alexandre Julliard
parent ba98574207
commit 68a03b6393
1 changed files with 35 additions and 2 deletions

View File

@ -388,6 +388,15 @@ LONG WINAPI KeReleaseMutex( PRKMUTEX mutex, BOOLEAN wait )
return ret;
}
static void CALLBACK ke_timer_complete_proc(PTP_CALLBACK_INSTANCE instance, void *timer_, PTP_TIMER tp_timer)
{
KTIMER *timer = timer_;
TRACE("instance %p, timer %p, tp_timer %p.\n", instance, timer, tp_timer);
SetEvent(timer->Header.WaitListHead.Blink);
}
/***********************************************************************
* KeInitializeTimerEx (NTOSKRNL.EXE.@)
*/
@ -431,9 +440,18 @@ BOOLEAN WINAPI KeSetTimerEx( KTIMER *timer, LARGE_INTEGER duetime, LONG period,
ret = timer->Header.Inserted;
timer->Header.Inserted = TRUE;
timer->Header.WaitListHead.Blink = CreateWaitableTimerW( NULL, timer->Header.Type == TYPE_MANUAL_TIMER, NULL );
SetWaitableTimer( timer->Header.WaitListHead.Blink, &duetime, period, NULL, NULL, FALSE );
timer->Header.WaitListHead.Blink = CreateEventW( NULL, timer->Header.Type == TYPE_MANUAL_TIMER, FALSE, NULL );
if (!timer->TimerListEntry.Blink)
timer->TimerListEntry.Blink = (void *)CreateThreadpoolTimer(ke_timer_complete_proc, timer, NULL);
if (!timer->TimerListEntry.Blink)
ERR("Could not create thread pool timer.\n");
timer->DueTime.QuadPart = duetime.QuadPart;
timer->Period = period;
SetThreadpoolTimer((TP_TIMER *)timer->TimerListEntry.Blink, (FILETIME *)&duetime, period, 0);
LeaveCriticalSection( &sync_cs );
return ret;
@ -446,6 +464,21 @@ BOOLEAN WINAPI KeCancelTimer( KTIMER *timer )
TRACE("timer %p.\n", timer);
EnterCriticalSection( &sync_cs );
if (timer->TimerListEntry.Blink)
{
SetThreadpoolTimer((TP_TIMER *)timer->TimerListEntry.Blink, NULL, 0, 0);
LeaveCriticalSection( &sync_cs );
WaitForThreadpoolTimerCallbacks((TP_TIMER *)timer->TimerListEntry.Blink, TRUE);
EnterCriticalSection( &sync_cs );
if (timer->TimerListEntry.Blink)
{
CloseThreadpoolTimer((TP_TIMER *)timer->TimerListEntry.Blink);
timer->TimerListEntry.Blink = NULL;
}
}
ret = timer->Header.Inserted;
timer->Header.Inserted = FALSE;
CloseHandle(timer->Header.WaitListHead.Blink);