ReactOS  r75214
timerobj.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: ntoskrnl/ke/timerobj.c
5  * PURPOSE: Handle Kernel Timers (Kernel-part of Executive Timers)
6  * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS *******************************************************************/
16 
21 
22 /* PRIVATE FUNCTIONS *********************************************************/
23 
24 BOOLEAN
28 {
29  BOOLEAN Inserted = FALSE;
30  ULONG Hand = 0;
31  PKSPIN_LOCK_QUEUE LockQueue;
32  DPRINT("KiInsertTreeTimer(): Timer %p, Interval: %I64d\n", Timer, Interval.QuadPart);
33 
34  /* Setup the timer's due time */
35  if (KiComputeDueTime(Timer, Interval, &Hand))
36  {
37  /* Acquire the lock */
38  LockQueue = KiAcquireTimerLock(Hand);
39 
40  /* Insert the timer */
41  if (KiInsertTimerTable(Timer, Hand))
42  {
43  /* It was already there, remove it */
44  KiRemoveEntryTimer(Timer);
45  Timer->Header.Inserted = FALSE;
46  }
47  else
48  {
49  /* Otherwise, we're now inserted */
50  Inserted = TRUE;
51  }
52 
53  /* Release the lock */
54  KiReleaseTimerLock(LockQueue);
55  }
56 
57  /* Release the lock and return insert status */
58  return Inserted;
59 }
60 
61 BOOLEAN
64  IN ULONG Hand)
65 {
66  LARGE_INTEGER InterruptTime;
67  LONGLONG DueTime = Timer->DueTime.QuadPart;
68  BOOLEAN Expired = FALSE;
69  PLIST_ENTRY ListHead, NextEntry;
70  PKTIMER CurrentTimer;
71  DPRINT("KiInsertTimerTable(): Timer %p, Hand: %lu\n", Timer, Hand);
72 
73  /* Check if the period is zero */
74  if (!Timer->Period) Timer->Header.SignalState = FALSE;
75 
76  /* Sanity check */
77  ASSERT(Hand == KiComputeTimerTableIndex(DueTime));
78 
79  /* Loop the timer list backwards */
80  ListHead = &KiTimerTableListHead[Hand].Entry;
81  NextEntry = ListHead->Blink;
82  while (NextEntry != ListHead)
83  {
84  /* Get the timer */
85  CurrentTimer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
86 
87  /* Now check if we can fit it before */
88  if ((ULONGLONG)DueTime >= CurrentTimer->DueTime.QuadPart) break;
89 
90  /* Keep looping */
91  NextEntry = NextEntry->Blink;
92  }
93 
94  /* Looped all the list, insert it here and get the interrupt time again */
95  InsertHeadList(NextEntry, &Timer->TimerListEntry);
96 
97  /* Check if we didn't find it in the list */
98  if (NextEntry == ListHead)
99  {
100  /* Set the time */
101  KiTimerTableListHead[Hand].Time.QuadPart = DueTime;
102 
103  /* Make sure it hasn't expired already */
104  InterruptTime.QuadPart = KeQueryInterruptTime();
105  if (DueTime <= InterruptTime.QuadPart) Expired = TRUE;
106  }
107 
108  /* Return expired state */
109  return Expired;
110 }
111 
112 BOOLEAN
113 FASTCALL
115 {
116  BOOLEAN RequestInterrupt = FALSE;
117  PKDPC Dpc = Timer->Dpc;
118  ULONG Period = Timer->Period;
119  LARGE_INTEGER Interval, SystemTime;
120  DPRINT("KiSignalTimer(): Timer %p\n", Timer);
121 
122  /* Set default values */
123  Timer->Header.Inserted = FALSE;
124  Timer->Header.SignalState = TRUE;
125 
126  /* Check if the timer has waiters */
127  if (!IsListEmpty(&Timer->Header.WaitListHead))
128  {
129  /* Check the type of event */
130  if (Timer->Header.Type == TimerNotificationObject)
131  {
132  /* Unwait the thread */
133  KxUnwaitThread(&Timer->Header, IO_NO_INCREMENT);
134  }
135  else
136  {
137  /* Otherwise unwait the thread and signal the timer */
139  }
140  }
141 
142  /* Check if we have a period */
143  if (Period)
144  {
145  /* Calculate the interval and insert the timer */
146  Interval.QuadPart = Int32x32To64(Period, -10000);
147  while (!KiInsertTreeTimer(Timer, Interval));
148  }
149 
150  /* Check if we have a DPC */
151  if (Dpc)
152  {
153  /* Insert it in the queue */
154  KeQuerySystemTime(&SystemTime);
155  KeInsertQueueDpc(Dpc,
156  ULongToPtr(SystemTime.LowPart),
157  ULongToPtr(SystemTime.HighPart));
158  RequestInterrupt = TRUE;
159  }
160 
161  /* Return whether we need to request a DPC interrupt or not */
162  return RequestInterrupt;
163 }
164 
165 VOID
166 FASTCALL
168  IN PKSPIN_LOCK_QUEUE LockQueue)
169 {
170  LIST_ENTRY ListHead;
171  BOOLEAN RequestInterrupt = FALSE;
172  DPRINT("KiCompleteTimer(): Timer %p, LockQueue: %p\n", Timer, LockQueue);
173 
174  /* Remove it from the timer list */
175  KiRemoveEntryTimer(Timer);
176 
177  /* Link the timer list to our stack */
178  ListHead.Flink = &Timer->TimerListEntry;
179  ListHead.Blink = &Timer->TimerListEntry;
180  Timer->TimerListEntry.Flink = &ListHead;
181  Timer->TimerListEntry.Blink = &ListHead;
182 
183  /* Release the timer lock */
184  KiReleaseTimerLock(LockQueue);
185 
186  /* Acquire dispatcher lock */
188 
189  /* Signal the timer if it's still on our list */
190  if (!IsListEmpty(&ListHead)) RequestInterrupt = KiSignalTimer(Timer);
191 
192  /* Release the dispatcher lock */
194 
195  /* Request a DPC if needed */
196  if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
197 }
198 
199 /* PUBLIC FUNCTIONS **********************************************************/
200 
201 /*
202  * @implemented
203  */
204 BOOLEAN
205 NTAPI
207 {
208  KIRQL OldIrql;
209  BOOLEAN Inserted;
210  ASSERT_TIMER(Timer);
212  DPRINT("KeCancelTimer(): Timer %p\n", Timer);
213 
214  /* Lock the Database and Raise IRQL */
215  OldIrql = KiAcquireDispatcherLock();
216 
217  /* Check if it's inserted, and remove it if it is */
218  Inserted = Timer->Header.Inserted;
219  if (Inserted) KxRemoveTreeTimer(Timer);
220 
221  /* Release Dispatcher Lock */
222  KiReleaseDispatcherLock(OldIrql);
223 
224  /* Return the old state */
225  return Inserted;
226 }
227 
228 /*
229  * @implemented
230  */
231 VOID
232 NTAPI
234 {
235  /* Call the New Function */
237 }
238 
239 /*
240  * @implemented
241  */
242 VOID
243 NTAPI
246 {
247  DPRINT("KeInitializeTimerEx(): Timer %p, Type %s\n",
248  Timer, (Type == NotificationTimer) ?
249  "NotificationTimer" : "SynchronizationTimer");
250 
251  /* Initialize the Dispatch Header */
252  Timer->Header.Type = TimerNotificationObject + Type;
253  //Timer->Header.TimerControlFlags = 0; // win does not init this field
254  Timer->Header.Hand = sizeof(KTIMER) / sizeof(ULONG);
255  Timer->Header.Inserted = 0; // win7: Timer->Header.TimerMiscFlags = 0;
256  Timer->Header.SignalState = 0;
257  InitializeListHead(&(Timer->Header.WaitListHead));
258 
259  /* Initialize the Other data */
260  Timer->DueTime.QuadPart = 0;
261  Timer->Period = 0;
262 }
263 
264 /*
265  * @implemented
266  */
267 BOOLEAN
268 NTAPI
270 {
271  /* Return the Signal State */
272  ASSERT_TIMER(Timer);
273  return (BOOLEAN)Timer->Header.SignalState;
274 }
275 
276 /*
277  * @implemented
278  */
279 BOOLEAN
280 NTAPI
284 {
285  /* Call the newer function and supply a period of 0 */
286  return KeSetTimerEx(Timer, DueTime, 0, Dpc);
287 }
288 
289 /*
290  * @implemented
291  */
292 BOOLEAN
293 NTAPI
296  IN LONG Period,
298 {
299  KIRQL OldIrql;
300  BOOLEAN Inserted;
301  ULONG Hand = 0;
302  BOOLEAN RequestInterrupt = FALSE;
303  ASSERT_TIMER(Timer);
305  DPRINT("KeSetTimerEx(): Timer %p, DueTime %I64d, Period %d, Dpc %p\n",
306  Timer, DueTime.QuadPart, Period, Dpc);
307 
308  /* Lock the Database and Raise IRQL */
309  OldIrql = KiAcquireDispatcherLock();
310 
311  /* Check if it's inserted, and remove it if it is */
312  Inserted = Timer->Header.Inserted;
313  if (Inserted) KxRemoveTreeTimer(Timer);
314 
315  /* Set Default Timer Data */
316  Timer->Dpc = Dpc;
317  Timer->Period = Period;
318  if (!KiComputeDueTime(Timer, DueTime, &Hand))
319  {
320  /* Signal the timer */
321  RequestInterrupt = KiSignalTimer(Timer);
322 
323  /* Release the dispatcher lock */
325 
326  /* Check if we need to do an interrupt */
327  if (RequestInterrupt) HalRequestSoftwareInterrupt(DISPATCH_LEVEL);
328  }
329  else
330  {
331  /* Insert the timer */
332  Timer->Header.SignalState = FALSE;
333  KxInsertTimer(Timer, Hand);
334  }
335 
336  /* Exit the dispatcher */
337  KiExitDispatcher(OldIrql);
338 
339  /* Return old state */
340  return Inserted;
341 }
342 
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define IN
Definition: typedefs.h:39
#define TRUE
Definition: types.h:120
#define ULongToPtr(ul)
Definition: basetsd.h:91
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
VOID FASTCALL KiCompleteTimer(IN PKTIMER Timer, IN PKSPIN_LOCK_QUEUE LockQueue)
Definition: timerobj.c:167
LARGE_INTEGER KiTimeIncrementReciprocal
Definition: timerobj.c:18
Type
Definition: Type.h:6
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel)?(CompletionRoutine!=NULL):TRUE)
_In_ LARGE_INTEGER DueTime
Definition: kefuncs.h:524
struct _LIST_ENTRY * Blink
Definition: typedefs.h:121
FORCEINLINE VOID InsertHeadList(_Inout_ PLIST_ENTRY ListHead, _Inout_ __drv_aliasesMem PLIST_ENTRY Entry)
Definition: rtlfuncs.h:201
FORCEINLINE BOOLEAN KiComputeDueTime(IN PKTIMER Timer, IN LARGE_INTEGER DueTime, OUT PULONG Hand)
Definition: ke_x.h:943
FORCEINLINE VOID KxUnwaitThreadForEvent(IN PKEVENT Event, IN KPRIORITY Increment)
Definition: ke_x.h:1295
FORCEINLINE PKSPIN_LOCK_QUEUE KiAcquireTimerLock(IN ULONG Hand)
Definition: ke_x.h:280
BOOLEAN NTAPI KeInsertQueueDpc(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: dpc.c:724
BOOLEAN NTAPI KeReadStateTimer(IN PKTIMER Timer)
Definition: timerobj.c:269
FORCEINLINE VOID KxRemoveTreeTimer(IN PKTIMER Timer)
Definition: ke_x.h:995
_In_ LARGE_INTEGER _In_ ULONG Period
Definition: kefuncs.h:1268
struct _KTIMER KTIMER
BOOLEAN NTAPI KeSetTimerEx(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN LONG Period, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:294
BOOLEAN FASTCALL KiInsertTreeTimer(IN PKTIMER Timer, IN LARGE_INTEGER Interval)
Definition: timerobj.c:26
#define FASTCALL
Definition: nt_native.h:50
BOOLEAN KiEnableTimerWatchdog
Definition: timerobj.c:20
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
Definition: ketypes.h:661
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
#define FALSE
Definition: types.h:117
long LONG
Definition: pedump.c:60
#define ASSERT_TIMER(Object)
UCHAR KiTimeIncrementShiftCount
Definition: timerobj.c:19
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
void DPRINT(...)
Definition: polytest.cpp:61
FORCEINLINE VOID KxInsertTimer(IN PKTIMER Timer, IN ULONG Hand)
Definition: ke_x.h:915
VOID FASTCALL KiExitDispatcher(KIRQL OldIrql)
ULARGE_INTEGER Time
Definition: ketypes.h:667
DWORD Interval
Definition: netstat.c:30
int64_t LONGLONG
Definition: typedefs.h:67
struct _LIST_ENTRY * Flink
Definition: typedefs.h:120
unsigned char BOOLEAN
_In_ LARGE_INTEGER _In_opt_ PKDPC Dpc
Definition: kefuncs.h:524
#define TIMER_TABLE_SIZE
Definition: ketypes.h:821
LIST_ENTRY Entry
Definition: ketypes.h:666
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
uint64_t ULONGLONG
Definition: typedefs.h:66
BOOLEAN FASTCALL KiSignalTimer(IN PKTIMER Timer)
Definition: timerobj.c:114
ULARGE_INTEGER DueTime
Definition: ketypes.h:826
enum _TIMER_TYPE TIMER_TYPE
unsigned char UCHAR
Definition: xmlstorage.h:181
BOOLEAN FASTCALL KiInsertTimerTable(IN PKTIMER Timer, IN ULONG Hand)
Definition: timerobj.c:63
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
Definition: ketypes.h:672
ULONG LowPart
Definition: typedefs.h:105
Definition: typedefs.h:118
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:152
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:144
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
FORCEINLINE VOID KiRemoveEntryTimer(IN PKTIMER Timer)
Definition: ke_x.h:884
FORCEINLINE VOID KiReleaseDispatcherLockFromDpcLevel(VOID)
Definition: ke_x.h:168
#define OUT
Definition: typedefs.h:40
unsigned int ULONG
Definition: retypes.h:1
KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]
Definition: timerobj.c:17
#define IO_NO_INCREMENT
Definition: iotypes.h:565
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
FORCEINLINE VOID KxUnwaitThread(IN DISPATCHER_HEADER *Object, IN KPRIORITY Increment)
Definition: ke_x.h:1250
ULONGLONG NTAPI KeQueryInterruptTime(VOID)
Definition: clock.c:203
FORCEINLINE ULONG KiComputeTimerTableIndex(IN ULONGLONG DueTime)
Definition: ke_x.h:873
IN HDEVINFO IN PSP_DEVINFO_DATA DeviceInfoData OPTIONAL
Definition: devinst.c:44
#define Int32x32To64(a, b)
VOID NTAPI KeInitializeTimerEx(OUT PKTIMER Timer, IN TIMER_TYPE Type)
Definition: timerobj.c:244
FORCEINLINE VOID KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
Definition: ke_x.h:291
FORCEINLINE VOID KiAcquireDispatcherLockAtDpcLevel(VOID)
Definition: ke_x.h:160
LONGLONG QuadPart
Definition: typedefs.h:113