[PATCH 3/7] ntoskrnl.exe: Reimplement KeSetTimerEx() on top of thread pool.

Paul Gofman pgofman at codeweavers.com
Thu May 28 04:15:16 CDT 2020


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 at codeweavers.com>
---
 dlls/ntoskrnl.exe/sync.c | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c
index d5a635efad7..1954b8befb7 100644
--- a/dlls/ntoskrnl.exe/sync.c
+++ b/dlls/ntoskrnl.exe/sync.c
@@ -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);
-- 
2.26.2




More information about the wine-devel mailing list