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(&parameters);
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         //                   &parameters);
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