ReactOS 0.4.16-dev-338-g34e76ad
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
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 */
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
64 IN ULONG Hand)
65{
66 ULONGLONG InterruptTime;
67 ULONGLONG 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 */
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 */
102
103 /* Make sure it hasn't expired already */
104 InterruptTime = KeQueryInterruptTime();
105 if (DueTime <= InterruptTime) Expired = TRUE;
106 }
107
108 /* Return expired state */
109 return Expired;
110}
111
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 */
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);
148 }
149
150 /* Check if we have a DPC */
151 if (Dpc)
152 {
153 /* Insert it in the queue */
154 KeQuerySystemTime(&SystemTime);
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
165VOID
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 */
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 */
205NTAPI
207{
209 BOOLEAN Inserted;
212 DPRINT("KeCancelTimer(): Timer %p\n", Timer);
213
214 /* Lock the Database and Raise IRQL */
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 */
223
224 /* Return the old state */
225 return Inserted;
226}
227
228/*
229 * @implemented
230 */
231VOID
232NTAPI
234{
235 /* Call the New Function */
237}
238
239/*
240 * @implemented
241 */
242VOID
243NTAPI
246{
247 DPRINT("KeInitializeTimerEx(): Timer %p, Type %s\n",
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 */
268NTAPI
270{
271 /* Return the Signal State */
273 return (BOOLEAN)Timer->Header.SignalState;
274}
275
276/*
277 * @implemented
278 */
280NTAPI
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 */
293NTAPI
296 IN LONG Period,
298{
300 BOOLEAN Inserted;
301 ULONG Hand = 0;
302 BOOLEAN RequestInterrupt = FALSE;
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 */
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 */
338
339 /* Return old state */
340 return Inserted;
341}
342
unsigned char BOOLEAN
Type
Definition: Type.h:7
#define ULongToPtr(ul)
Definition: basetsd.h:92
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
BOOLEAN NTAPI KeInsertQueueDpc(IN PKDPC Dpc, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
Definition: dpc.c:725
#define InsertHeadList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
UCHAR KIRQL
Definition: env_spec_w32.h:591
#define KeQuerySystemTime(t)
Definition: env_spec_w32.h:570
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
FORCEINLINE BOOLEAN KiComputeDueTime(IN PKTIMER Timer, IN LARGE_INTEGER DueTime, OUT PULONG Hand)
Definition: ke_x.h:952
FORCEINLINE VOID KiReleaseDispatcherLock(IN KIRQL OldIrql)
Definition: ke_x.h:157
FORCEINLINE VOID KxRemoveTreeTimer(IN PKTIMER Timer)
Definition: ke_x.h:1004
FORCEINLINE VOID KiRemoveEntryTimer(IN PKTIMER Timer)
Definition: ke_x.h:892
FORCEINLINE VOID KiReleaseTimerLock(IN PKSPIN_LOCK_QUEUE LockQueue)
Definition: ke_x.h:297
FORCEINLINE ULONG KiComputeTimerTableIndex(IN ULONGLONG DueTime)
Definition: ke_x.h:881
FORCEINLINE VOID KxUnwaitThread(IN DISPATCHER_HEADER *Object, IN KPRIORITY Increment)
Definition: ke_x.h:1259
FORCEINLINE PKSPIN_LOCK_QUEUE KiAcquireTimerLock(IN ULONG Hand)
Definition: ke_x.h:286
FORCEINLINE VOID KiReleaseDispatcherLockFromSynchLevel(VOID)
Definition: ke_x.h:174
FORCEINLINE VOID KiAcquireDispatcherLockAtSynchLevel(VOID)
Definition: ke_x.h:165
FORCEINLINE KIRQL KiAcquireDispatcherLock(VOID)
Definition: ke_x.h:149
FORCEINLINE VOID KxInsertTimer(IN PKTIMER Timer, IN ULONG Hand)
Definition: ke_x.h:923
FORCEINLINE VOID KxUnwaitThreadForEvent(IN PKEVENT Event, IN KPRIORITY Increment)
Definition: ke_x.h:1304
#define ASSERT(a)
Definition: mode.c:44
@ TimerNotificationObject
Definition: ketypes.h:414
DWORD Interval
Definition: netstat.c:30
#define FASTCALL
Definition: nt_native.h:50
#define Int32x32To64(a, b)
enum _TIMER_TYPE TIMER_TYPE
@ NotificationTimer
VOID FASTCALL KiExitDispatcher(KIRQL OldIrql)
long LONG
Definition: pedump.c:60
#define KeQueryInterruptTime()
Definition: ke.h:37
#define DPRINT
Definition: sndvol32.h:73
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
Definition: ketypes.h:699
Definition: ketypes.h:774
ULARGE_INTEGER Time
Definition: ketypes.h:779
LIST_ENTRY Entry
Definition: ketypes.h:778
ULARGE_INTEGER DueTime
Definition: ketypes.h:853
Definition: typedefs.h:120
struct _LIST_ENTRY * Blink
Definition: typedefs.h:122
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]
Definition: timerobj.c:17
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
LARGE_INTEGER KiTimeIncrementReciprocal
Definition: timerobj.c:18
BOOLEAN FASTCALL KiSignalTimer(IN PKTIMER Timer)
Definition: timerobj.c:114
VOID FASTCALL KiCompleteTimer(IN PKTIMER Timer, IN PKSPIN_LOCK_QUEUE LockQueue)
Definition: timerobj.c:167
BOOLEAN KiEnableTimerWatchdog
Definition: timerobj.c:20
BOOLEAN NTAPI KeReadStateTimer(IN PKTIMER Timer)
Definition: timerobj.c:269
UCHAR KiTimeIncrementShiftCount
Definition: timerobj.c:19
BOOLEAN FASTCALL KiInsertTimerTable(IN PKTIMER Timer, IN ULONG Hand)
Definition: timerobj.c:63
BOOLEAN NTAPI KeSetTimerEx(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN LONG Period, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:294
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
BOOLEAN FASTCALL KiInsertTreeTimer(IN PKTIMER Timer, IN LARGE_INTEGER Interval)
Definition: timerobj.c:26
VOID NTAPI KeInitializeTimerEx(OUT PKTIMER Timer, IN TIMER_TYPE Type)
Definition: timerobj.c:244
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
#define NTAPI
Definition: typedefs.h:36
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
ULONG LowPart
Definition: typedefs.h:106
_Must_inspect_result_ _In_ PWDF_DPC_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFDPC * Dpc
Definition: wdfdpc.h:112
_In_ WDFTIMER _In_ LONGLONG DueTime
Definition: wdftimer.h:190
#define IO_NO_INCREMENT
Definition: iotypes.h:598
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
_In_ LARGE_INTEGER _In_ ULONG Period
Definition: kefuncs.h:1313
#define ASSERT_TIMER(Object)
#define TIMER_TABLE_SIZE
Definition: ketypes.h:848
struct _KTIMER KTIMER
unsigned char UCHAR
Definition: xmlstorage.h:181