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 #include <ddk/ntddk.h>
15 #include <ntos/synch.h>
16 #include <internal/ke.h>
18 #include <internal/pool.h>
19 #include <internal/safe.h>
21 #include <internal/debug.h>
24 /* TYPES ********************************************************************/
26 typedef struct _NTTIMER
35 /* GLOBALS ******************************************************************/
37 POBJECT_TYPE ExTimerType = NULL;
39 static GENERIC_MAPPING ExpTimerMapping = {
40 STANDARD_RIGHTS_READ | TIMER_QUERY_STATE,
41 STANDARD_RIGHTS_WRITE | TIMER_MODIFY_STATE,
42 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
46 /* FUNCTIONS *****************************************************************/
49 NtpCreateTimer(PVOID ObjectBody,
52 POBJECT_ATTRIBUTES ObjectAttributes)
54 DPRINT("NtpCreateTimer(ObjectBody %x, Parent %x, RemainingPath %S)\n",
55 ObjectBody, Parent, RemainingPath);
57 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
59 return(STATUS_UNSUCCESSFUL);
62 return(STATUS_SUCCESS);
67 NtpDeleteTimer(PVOID ObjectBody)
70 PNTTIMER Timer = ObjectBody;
72 DPRINT("NtpDeleteTimer()\n");
74 OldIrql = KeRaiseIrqlToDpcLevel();
76 KeCancelTimer(&Timer->Timer);
77 KeRemoveQueueDpc(&Timer->Dpc);
78 KeRemoveQueueApc(&Timer->Apc);
79 Timer->Running = FALSE;
86 NtpTimerDpcRoutine(PKDPC Dpc,
87 PVOID DeferredContext,
88 PVOID SystemArgument1,
89 PVOID SystemArgument2)
93 DPRINT("NtpTimerDpcRoutine()\n");
95 Timer = (PNTTIMER)DeferredContext;
99 KeInsertQueueApc(&Timer->Apc,
108 NtpTimerApcKernelRoutine(PKAPC Apc,
109 PKNORMAL_ROUTINE* NormalRoutine,
110 PVOID* NormalContext,
111 PVOID* SystemArgument1,
112 PVOID* SystemArguemnt2)
114 DPRINT("NtpTimerApcKernelRoutine()\n");
119 VOID NtInitializeTimerImplementation(VOID)
121 ExTimerType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
123 RtlCreateUnicodeString(&ExTimerType->TypeName, L"Timer");
125 ExTimerType->Tag = TAG('T', 'I', 'M', 'T');
126 ExTimerType->MaxObjects = ULONG_MAX;
127 ExTimerType->MaxHandles = ULONG_MAX;
128 ExTimerType->TotalObjects = 0;
129 ExTimerType->TotalHandles = 0;
130 ExTimerType->PagedPoolCharge = 0;
131 ExTimerType->NonpagedPoolCharge = sizeof(NTTIMER);
132 ExTimerType->Mapping = &ExpTimerMapping;
133 ExTimerType->Dump = NULL;
134 ExTimerType->Open = NULL;
135 ExTimerType->Close = NULL;
136 ExTimerType->Delete = NtpDeleteTimer;
137 ExTimerType->Parse = NULL;
138 ExTimerType->Security = NULL;
139 ExTimerType->QueryName = NULL;
140 ExTimerType->OkayToClose = NULL;
141 ExTimerType->Create = NtpCreateTimer;
142 ExTimerType->DuplicationNotify = NULL;
147 NtCancelTimer(IN HANDLE TimerHandle,
148 OUT PBOOLEAN CurrentState OPTIONAL)
155 DPRINT("NtCancelTimer()\n");
156 Status = ObReferenceObjectByHandle(TimerHandle,
162 if (!NT_SUCCESS(Status))
165 OldIrql = KeRaiseIrqlToDpcLevel();
167 State = KeCancelTimer(&Timer->Timer);
168 KeRemoveQueueDpc(&Timer->Dpc);
169 KeRemoveQueueApc(&Timer->Apc);
170 Timer->Running = FALSE;
172 KeLowerIrql(OldIrql);
173 ObDereferenceObject(Timer);
175 if (CurrentState != NULL)
177 *CurrentState = State;
180 return STATUS_SUCCESS;
185 NtCreateTimer(OUT PHANDLE TimerHandle,
186 IN ACCESS_MASK DesiredAccess,
187 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
188 IN TIMER_TYPE TimerType)
193 DPRINT("NtCreateTimer()\n");
194 Status = ObCreateObject(TimerHandle,
199 if (!NT_SUCCESS(Status))
202 KeInitializeTimerEx(&Timer->Timer,
205 KeInitializeDpc (&Timer->Dpc,
206 (PKDEFERRED_ROUTINE)NtpTimerDpcRoutine,
209 Timer->Running = FALSE;
211 ObDereferenceObject(Timer);
213 return(STATUS_SUCCESS);
218 NtOpenTimer(OUT PHANDLE TimerHandle,
219 IN ACCESS_MASK DesiredAccess,
220 IN POBJECT_ATTRIBUTES ObjectAttributes)
224 Status = ObOpenObjectByName(ObjectAttributes,
236 NtQueryTimer(IN HANDLE TimerHandle,
237 IN CINT TimerInformationClass,
238 OUT PVOID UnsafeTimerInformation,
240 OUT PULONG UnsafeResultLength)
243 TIMER_BASIC_INFORMATION TimerInformation;
247 Status = ObReferenceObjectByHandle(TimerHandle,
253 if (!NT_SUCCESS(Status))
258 if (TimerInformationClass != TimerBasicInformation)
260 ObDereferenceObject(Timer);
261 return(STATUS_INVALID_INFO_CLASS);
263 if (Length < sizeof(TIMER_BASIC_INFORMATION))
265 ObDereferenceObject(Timer);
266 return(STATUS_INFO_LENGTH_MISMATCH);
269 memcpy(&TimerInformation.TimeRemaining, &Timer->Timer.DueTime,
270 sizeof(LARGE_INTEGER));
271 TimerInformation.SignalState = Timer->Timer.Header.SignalState;
272 ResultLength = sizeof(TIMER_BASIC_INFORMATION);
274 Status = MmCopyToCaller(UnsafeTimerInformation, &TimerInformation,
275 sizeof(TIMER_BASIC_INFORMATION));
276 if (!NT_SUCCESS(Status))
278 ObDereferenceObject(Timer);
282 if (UnsafeResultLength != NULL)
284 Status = MmCopyToCaller(UnsafeResultLength, &ResultLength,
286 if (!NT_SUCCESS(Status))
288 ObDereferenceObject(Timer);
292 ObDereferenceObject(Timer);
293 return(STATUS_SUCCESS);
298 NtSetTimer(IN HANDLE TimerHandle,
299 IN PLARGE_INTEGER DueTime,
300 IN PTIMERAPCROUTINE TimerApcRoutine,
301 IN PVOID TimerContext,
303 IN ULONG Period OPTIONAL,
304 OUT PBOOLEAN PreviousState OPTIONAL)
312 DPRINT("NtSetTimer()\n");
314 Status = ObReferenceObjectByHandle(TimerHandle,
320 if (!NT_SUCCESS(Status))
323 State = KeReadStateTimer(&Timer->Timer);
325 if (Timer->Running == TRUE)
327 /* cancel running timer */
328 OldIrql = KeRaiseIrqlToDpcLevel();
329 KeCancelTimer(&Timer->Timer);
330 KeRemoveQueueDpc(&Timer->Dpc);
331 KeRemoveQueueApc(&Timer->Apc);
332 Timer->Running = FALSE;
333 KeLowerIrql(OldIrql);
335 if( TimerApcRoutine )
336 KeInitializeApc(&Timer->Apc,
337 KeGetCurrentThread(),
339 (PKKERNEL_ROUTINE)NtpTimerApcKernelRoutine,
340 (PKRUNDOWN_ROUTINE)NULL,
341 (PKNORMAL_ROUTINE)TimerApcRoutine,
345 Result = KeSetTimerEx (&Timer->Timer,
348 TimerApcRoutine ? &Timer->Dpc : 0 );
351 ObDereferenceObject(Timer);
352 DPRINT1( "KeSetTimer says the timer was already running, this shouldn't be\n" );
353 return STATUS_UNSUCCESSFUL;
356 Timer->Running = TRUE;
358 ObDereferenceObject(Timer);
360 if (PreviousState != NULL)
362 *PreviousState = State;
365 return STATUS_SUCCESS;