1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 ModuleName: 6 7 MxTimerKm.h 8 9 Abstract: 10 11 Kernel mode implementation of timer defined in 12 MxTimer.h 13 14 Author: 15 16 17 Revision History: 18 19 20 21 --*/ 22 23 #pragma once 24 25 #define TolerableDelayUnlimited ((ULONG)-1) 26 27 typedef 28 BOOLEAN 29 (STDCALL *PFN_KE_SET_COALESCABLE_TIMER) ( 30 __inout PKTIMER Timer, 31 __in LARGE_INTEGER DueTime, 32 __in ULONG Period, 33 __in ULONG TolerableDelay, 34 __in_opt PKDPC Dpc 35 ); 36 37 typedef struct _MdTimer { 38 39 40 // 41 // The timer period 42 // 43 LONG m_Period; 44 45 // 46 // Tracks whether the ex timer is being used 47 // 48 BOOLEAN m_IsExtTimer; 49 50 // #pragma warning(push) 51 // #pragma warning( disable: 4201 ) // nonstandard extension used : nameless struct/union 52 53 union { 54 struct { 55 // 56 // Callback function to be invoked upon timer expiration 57 // 58 MdDeferredRoutine m_TimerCallback; 59 KTIMER KernelTimer; 60 KDPC TimerDpc; 61 }; 62 63 struct { 64 // 65 // Callback function to be invoked upon timer expiration 66 // 67 MdExtCallback m_ExTimerCallback; 68 PEX_TIMER m_KernelExTimer; 69 }; 70 }; 71 72 // #pragma warning(pop) 73 74 // 75 // Context to be passed in to the callback function 76 // 77 PVOID m_TimerContext; 78 79 } MdTimer; 80 81 #include "mxtimer.h" 82 83 MxTimer::MxTimer( 84 VOID 85 ) 86 { 87 m_Timer.m_TimerContext = NULL; 88 m_Timer.m_TimerCallback = NULL; 89 m_Timer.m_Period = 0; 90 m_Timer.m_KernelExTimer = NULL; 91 } 92 93 MxTimer::~MxTimer( 94 VOID 95 ) 96 { 97 // __REACTOS__ Ex timers are not supported 98 // BOOLEAN wasCancelled; 99 100 // if (m_Timer.m_IsExtTimer && 101 // m_Timer.m_KernelExTimer) { 102 // wasCancelled = ExDeleteTimer(m_Timer.m_KernelExTimer, 103 // TRUE, // Cancel if pending. We don't expect 104 // // it to be pending though 105 // FALSE,// Wait 106 // NULL); 107 // // 108 // // Timer should not have been pending 109 // // 110 // ASSERT(wasCancelled == FALSE); 111 // m_Timer.m_KernelExTimer = NULL; 112 // } 113 } 114 115 NTSTATUS 116 #ifdef _MSC_VER 117 #pragma prefast(suppress:__WARNING_UNMATCHED_DECL_ANNO, "_Must_inspect_result_ not needed in kernel mode as the function always succeeds"); 118 #endif 119 MxTimer::Initialize( 120 __in_opt PVOID TimerContext, 121 __in MdDeferredRoutine TimerCallback, 122 __in LONG Period 123 ) 124 { 125 m_Timer.m_TimerContext = TimerContext; 126 m_Timer.m_TimerCallback = TimerCallback; 127 m_Timer.m_Period = Period; 128 129 KeInitializeTimerEx(&(m_Timer.KernelTimer), NotificationTimer); 130 KeInitializeDpc(&(m_Timer.TimerDpc), // Timer DPC 131 m_Timer.m_TimerCallback, // DeferredRoutine 132 m_Timer.m_TimerContext); // DeferredContext 133 134 m_Timer.m_IsExtTimer = FALSE; 135 136 return STATUS_SUCCESS; 137 } 138 139 _Must_inspect_result_ 140 NTSTATUS 141 MxTimer::InitializeEx( 142 __in_opt PVOID TimerContext, 143 __in MdExtCallback TimerCallback, 144 __in LONG Period, 145 __in ULONG TolerableDelay, 146 __in BOOLEAN UseHighResolutionTimer 147 ) 148 /*++ 149 150 Routine Description: 151 152 Initializes an Ex timer. By invoking this routine instead of 153 Initialize, the client is implicitly declaring that it wants 154 to use the new timers 155 156 Arguments: 157 158 TimerContext - Context to be passed back with the cllback 159 TimerCallback - Callback to be invoked when the timer fires 160 Period - Period in ms 161 TolerableDelay - Tolerable delay in ms 162 UseHighResolutionTimer- Indicates whether to use the high 163 resolution timers 164 165 Returns: 166 167 Status 168 169 --*/ 170 171 { 172 // NTSTATUS status; 173 // ULONG attributes = 0; 174 175 // m_Timer.m_TimerContext = TimerContext; 176 // m_Timer.m_ExTimerCallback = TimerCallback; 177 // m_Timer.m_Period = Period; 178 179 // if (TolerableDelay != 0) { 180 181 // attributes |= EX_TIMER_NO_WAKE; 182 183 // } else if (UseHighResolutionTimer) { 184 185 // attributes |= EX_TIMER_HIGH_RESOLUTION; 186 // } 187 188 // m_Timer.m_KernelExTimer = ExAllocateTimer(m_Timer.m_ExTimerCallback, 189 // TimerContext, 190 // attributes); 191 // if (m_Timer.m_KernelExTimer) { 192 193 // status = STATUS_SUCCESS; 194 195 // } else { 196 197 // status = STATUS_INSUFFICIENT_RESOURCES; 198 // } 199 200 // m_Timer.m_IsExtTimer = TRUE; 201 202 // return status; 203 return STATUS_NOT_IMPLEMENTED; // __REACTOS__ Ex timers are not supported 204 } 205 206 207 __inline 208 BOOLEAN 209 MxTimer::StartWithReturn( 210 __in LARGE_INTEGER DueTime, 211 __in ULONG TolerableDelay 212 ) 213 { 214 if (m_Timer.m_IsExtTimer) { 215 // __REACTOS__ Ex timers are not supported 216 // EXT_SET_PARAMETERS parameters; 217 218 // ExInitializeSetTimerParameters(¶meters); 219 220 // // 221 // // We get the delay in ms but the underlying API needs it in 100 ns 222 // // units. Convert tolerable delay from ms to 100 ns. However, 223 // // MAXULONG (TolerableDelayUnlimited) has a special meaning that the 224 // // system should never be woken up, so we assign the corresponding 225 // // special value for Ex timers 226 // // 227 // if (TolerableDelay == TolerableDelayUnlimited) { 228 // parameters.NoWakeTolerance = EX_TIMER_UNLIMITED_TOLERANCE; 229 // } else { 230 // parameters.NoWakeTolerance = ((LONGLONG) TolerableDelay) * 10 * 1000; 231 // } 232 233 // return ExSetTimer(m_Timer.m_KernelExTimer, 234 // DueTime.QuadPart, 235 // (((LONGLONG) m_Timer.m_Period) * 10 * 1000), 236 // ¶meters); 237 return FALSE; 238 } else { 239 240 return KeSetCoalescableTimer(&(m_Timer.KernelTimer), 241 DueTime, 242 m_Timer.m_Period, 243 TolerableDelay, 244 &(m_Timer.TimerDpc)); 245 } 246 247 } 248 249 250 VOID 251 MxTimer::Start( 252 __in LARGE_INTEGER DueTime, 253 __in ULONG TolerableDelay 254 ) 255 { 256 if (m_Timer.m_IsExtTimer) { 257 258 StartWithReturn(DueTime,TolerableDelay); 259 260 } else { 261 KeSetCoalescableTimer(&(m_Timer.KernelTimer), 262 DueTime, 263 m_Timer.m_Period, 264 TolerableDelay, 265 &(m_Timer.TimerDpc)); 266 } 267 268 return; 269 } 270 271 _Must_inspect_result_ 272 BOOLEAN 273 MxTimer::Stop( 274 VOID 275 ) 276 { 277 BOOLEAN bRetVal; 278 279 if (m_Timer.m_IsExtTimer) { 280 bRetVal = FALSE; 281 // bRetVal = ExCancelTimer(m_Timer.m_KernelExTimer, NULL); // __REACTOS__ Ex timers are not supported 282 283 } else { 284 bRetVal = KeCancelTimer(&(m_Timer.KernelTimer)); 285 } 286 287 return bRetVal; 288 } 289 290 VOID 291 MxTimer::FlushQueuedDpcs( 292 VOID 293 ) 294 { 295 Mx::MxFlushQueuedDpcs(); 296 } 297