3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/nt/nttimer.c
6 * PURPOSE: User-mode timers
7 * PROGRAMMER: David Welch (welch@mcmail.com)
12 /* INCLUDES *****************************************************************/
14 #define NTOS_MODE_KERNEL
16 #include <ntos/synch.h>
17 #include <internal/ke.h>
19 #include <internal/pool.h>
20 #include <internal/safe.h>
22 #include <internal/debug.h>
25 /* TYPES ********************************************************************/
27 typedef struct _NTTIMER
36 /* GLOBALS ******************************************************************/
38 POBJECT_TYPE ExTimerType = NULL;
40 static GENERIC_MAPPING ExpTimerMapping = {
41 STANDARD_RIGHTS_READ | TIMER_QUERY_STATE,
42 STANDARD_RIGHTS_WRITE | TIMER_MODIFY_STATE,
43 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
47 /* FUNCTIONS *****************************************************************/
50 NtpCreateTimer(PVOID ObjectBody,
53 POBJECT_ATTRIBUTES ObjectAttributes)
55 DPRINT("NtpCreateTimer(ObjectBody %x, Parent %x, RemainingPath %S)\n",
56 ObjectBody, Parent, RemainingPath);
58 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
60 return(STATUS_UNSUCCESSFUL);
63 return(STATUS_SUCCESS);
68 NtpDeleteTimer(PVOID ObjectBody)
71 PNTTIMER Timer = ObjectBody;
73 DPRINT("NtpDeleteTimer()\n");
75 OldIrql = KeRaiseIrqlToDpcLevel();
77 KeCancelTimer(&Timer->Timer);
78 KeRemoveQueueDpc(&Timer->Dpc);
79 KeRemoveQueueApc(&Timer->Apc);
80 Timer->Running = FALSE;
87 NtpTimerDpcRoutine(PKDPC Dpc,
88 PVOID DeferredContext,
89 PVOID SystemArgument1,
90 PVOID SystemArgument2)
94 DPRINT("NtpTimerDpcRoutine()\n");
96 Timer = (PNTTIMER)DeferredContext;
100 KeInsertQueueApc(&Timer->Apc,
109 NtpTimerApcKernelRoutine(PKAPC Apc,
110 PKNORMAL_ROUTINE* NormalRoutine,
111 PVOID* NormalContext,
112 PVOID* SystemArgument1,
113 PVOID* SystemArguemnt2)
115 DPRINT("NtpTimerApcKernelRoutine()\n");
120 VOID NtInitializeTimerImplementation(VOID)
122 ExTimerType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
124 RtlCreateUnicodeString(&ExTimerType->TypeName, L"Timer");
126 ExTimerType->Tag = TAG('T', 'I', 'M', 'T');
127 ExTimerType->MaxObjects = ULONG_MAX;
128 ExTimerType->MaxHandles = ULONG_MAX;
129 ExTimerType->TotalObjects = 0;
130 ExTimerType->TotalHandles = 0;
131 ExTimerType->PagedPoolCharge = 0;
132 ExTimerType->NonpagedPoolCharge = sizeof(NTTIMER);
133 ExTimerType->Mapping = &ExpTimerMapping;
134 ExTimerType->Dump = NULL;
135 ExTimerType->Open = NULL;
136 ExTimerType->Close = NULL;
137 ExTimerType->Delete = NtpDeleteTimer;
138 ExTimerType->Parse = NULL;
139 ExTimerType->Security = NULL;
140 ExTimerType->QueryName = NULL;
141 ExTimerType->OkayToClose = NULL;
142 ExTimerType->Create = NtpCreateTimer;
143 ExTimerType->DuplicationNotify = NULL;
148 NtCancelTimer(IN HANDLE TimerHandle,
149 OUT PBOOLEAN CurrentState OPTIONAL)
156 DPRINT("NtCancelTimer()\n");
157 Status = ObReferenceObjectByHandle(TimerHandle,
163 if (!NT_SUCCESS(Status))
166 OldIrql = KeRaiseIrqlToDpcLevel();
168 State = KeCancelTimer(&Timer->Timer);
169 KeRemoveQueueDpc(&Timer->Dpc);
170 KeRemoveQueueApc(&Timer->Apc);
171 Timer->Running = FALSE;
173 KeLowerIrql(OldIrql);
174 ObDereferenceObject(Timer);
176 if (CurrentState != NULL)
178 *CurrentState = State;
181 return STATUS_SUCCESS;
186 NtCreateTimer(OUT PHANDLE TimerHandle,
187 IN ACCESS_MASK DesiredAccess,
188 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
189 IN TIMER_TYPE TimerType)
194 DPRINT("NtCreateTimer()\n");
195 Status = ObRosCreateObject(TimerHandle,
200 if (!NT_SUCCESS(Status))
203 KeInitializeTimerEx(&Timer->Timer,
206 KeInitializeDpc (&Timer->Dpc,
207 (PKDEFERRED_ROUTINE)NtpTimerDpcRoutine,
210 Timer->Running = FALSE;
212 ObDereferenceObject(Timer);
214 return(STATUS_SUCCESS);
219 NtOpenTimer(OUT PHANDLE TimerHandle,
220 IN ACCESS_MASK DesiredAccess,
221 IN POBJECT_ATTRIBUTES ObjectAttributes)
225 Status = ObOpenObjectByName(ObjectAttributes,
237 NtQueryTimer(IN HANDLE TimerHandle,
238 IN CINT TimerInformationClass,
239 OUT PVOID UnsafeTimerInformation,
241 OUT PULONG UnsafeResultLength)
244 TIMER_BASIC_INFORMATION TimerInformation;
248 Status = ObReferenceObjectByHandle(TimerHandle,
254 if (!NT_SUCCESS(Status))
259 if (TimerInformationClass != TimerBasicInformation)
261 ObDereferenceObject(Timer);
262 return(STATUS_INVALID_INFO_CLASS);
264 if (Length < sizeof(TIMER_BASIC_INFORMATION))
266 ObDereferenceObject(Timer);
267 return(STATUS_INFO_LENGTH_MISMATCH);
270 memcpy(&TimerInformation.TimeRemaining, &Timer->Timer.DueTime,
271 sizeof(LARGE_INTEGER));
272 TimerInformation.SignalState = Timer->Timer.Header.SignalState;
273 ResultLength = sizeof(TIMER_BASIC_INFORMATION);
275 Status = MmCopyToCaller(UnsafeTimerInformation, &TimerInformation,
276 sizeof(TIMER_BASIC_INFORMATION));
277 if (!NT_SUCCESS(Status))
279 ObDereferenceObject(Timer);
283 if (UnsafeResultLength != NULL)
285 Status = MmCopyToCaller(UnsafeResultLength, &ResultLength,
287 if (!NT_SUCCESS(Status))
289 ObDereferenceObject(Timer);
293 ObDereferenceObject(Timer);
294 return(STATUS_SUCCESS);
299 NtSetTimer(IN HANDLE TimerHandle,
300 IN PLARGE_INTEGER DueTime,
301 IN PTIMERAPCROUTINE TimerApcRoutine,
302 IN PVOID TimerContext,
304 IN ULONG Period OPTIONAL,
305 OUT PBOOLEAN PreviousState OPTIONAL)
313 DPRINT("NtSetTimer()\n");
315 Status = ObReferenceObjectByHandle(TimerHandle,
321 if (!NT_SUCCESS(Status))
324 State = KeReadStateTimer(&Timer->Timer);
326 if (Timer->Running == TRUE)
328 /* cancel running timer */
329 OldIrql = KeRaiseIrqlToDpcLevel();
330 KeCancelTimer(&Timer->Timer);
331 KeRemoveQueueDpc(&Timer->Dpc);
332 KeRemoveQueueApc(&Timer->Apc);
333 Timer->Running = FALSE;
334 KeLowerIrql(OldIrql);
336 if( TimerApcRoutine )
337 KeInitializeApc(&Timer->Apc,
338 KeGetCurrentThread(),
339 OriginalApcEnvironment,
340 (PKKERNEL_ROUTINE)NtpTimerApcKernelRoutine,
341 (PKRUNDOWN_ROUTINE)NULL,
342 (PKNORMAL_ROUTINE)TimerApcRoutine,
346 Result = KeSetTimerEx (&Timer->Timer,
349 TimerApcRoutine ? &Timer->Dpc : 0 );
352 ObDereferenceObject(Timer);
353 DPRINT1( "KeSetTimer says the timer was already running, this shouldn't be\n" );
354 return STATUS_UNSUCCESSFUL;
357 Timer->Running = TRUE;
359 ObDereferenceObject(Timer);
361 if (PreviousState != NULL)
363 *PreviousState = State;
366 return STATUS_SUCCESS;