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 NtpTimerDpcRoutine(PKDPC Dpc,
68 PVOID DeferredContext,
69 PVOID SystemArgument1,
70 PVOID SystemArgument2)
74 DPRINT("NtpTimerDpcRoutine()\n");
76 Timer = (PNTTIMER)DeferredContext;
80 KeInsertQueueApc(&Timer->Apc,
89 NtpTimerApcKernelRoutine(PKAPC Apc,
90 PKNORMAL_ROUTINE* NormalRoutine,
92 PVOID* SystemArgument1,
93 PVOID* SystemArguemnt2)
95 DPRINT("NtpTimerApcKernelRoutine()\n");
100 VOID NtInitializeTimerImplementation(VOID)
102 ExTimerType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
104 RtlCreateUnicodeString(&ExTimerType->TypeName, L"Timer");
106 ExTimerType->Tag = TAG('T', 'I', 'M', 'T');
107 ExTimerType->MaxObjects = ULONG_MAX;
108 ExTimerType->MaxHandles = ULONG_MAX;
109 ExTimerType->TotalObjects = 0;
110 ExTimerType->TotalHandles = 0;
111 ExTimerType->PagedPoolCharge = 0;
112 ExTimerType->NonpagedPoolCharge = sizeof(NTTIMER);
113 ExTimerType->Mapping = &ExpTimerMapping;
114 ExTimerType->Dump = NULL;
115 ExTimerType->Open = NULL;
116 ExTimerType->Close = NULL;
117 ExTimerType->Delete = NULL;
118 ExTimerType->Parse = NULL;
119 ExTimerType->Security = NULL;
120 ExTimerType->QueryName = NULL;
121 ExTimerType->OkayToClose = NULL;
122 ExTimerType->Create = NtpCreateTimer;
123 ExTimerType->DuplicationNotify = NULL;
128 NtCancelTimer(IN HANDLE TimerHandle,
129 OUT PBOOLEAN CurrentState OPTIONAL)
136 DPRINT("NtCancelTimer()\n");
137 Status = ObReferenceObjectByHandle(TimerHandle,
143 if (!NT_SUCCESS(Status))
146 OldIrql = KeRaiseIrqlToDpcLevel();
148 State = KeCancelTimer(&Timer->Timer);
149 KeRemoveQueueDpc(&Timer->Dpc);
150 KeRemoveQueueApc(&Timer->Apc);
151 Timer->Running = FALSE;
153 KeLowerIrql(OldIrql);
154 ObDereferenceObject(Timer);
156 if (CurrentState != NULL)
158 *CurrentState = State;
161 return STATUS_SUCCESS;
166 NtCreateTimer(OUT PHANDLE TimerHandle,
167 IN ACCESS_MASK DesiredAccess,
168 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
169 IN TIMER_TYPE TimerType)
174 DPRINT("NtCreateTimer()\n");
175 Status = ObCreateObject(TimerHandle,
180 if (!NT_SUCCESS(Status))
183 KeInitializeTimerEx(&Timer->Timer,
186 KeInitializeDpc (&Timer->Dpc,
187 (PKDEFERRED_ROUTINE)NtpTimerDpcRoutine,
190 Timer->Running = FALSE;
192 ObDereferenceObject(Timer);
194 return(STATUS_SUCCESS);
199 NtOpenTimer(OUT PHANDLE TimerHandle,
200 IN ACCESS_MASK DesiredAccess,
201 IN POBJECT_ATTRIBUTES ObjectAttributes)
205 Status = ObOpenObjectByName(ObjectAttributes,
217 NtQueryTimer(IN HANDLE TimerHandle,
218 IN CINT TimerInformationClass,
219 OUT PVOID UnsafeTimerInformation,
221 OUT PULONG UnsafeResultLength)
224 TIMER_BASIC_INFORMATION TimerInformation;
228 Status = ObReferenceObjectByHandle(TimerHandle,
234 if (!NT_SUCCESS(Status))
239 if (TimerInformationClass != TimerBasicInformation)
241 ObDereferenceObject(Timer);
242 return(STATUS_INVALID_INFO_CLASS);
244 if (Length < sizeof(TIMER_BASIC_INFORMATION))
246 ObDereferenceObject(Timer);
247 return(STATUS_INFO_LENGTH_MISMATCH);
250 memcpy(&TimerInformation.TimeRemaining, &Timer->Timer.DueTime,
251 sizeof(LARGE_INTEGER));
252 TimerInformation.SignalState = Timer->Timer.Header.SignalState;
253 ResultLength = sizeof(TIMER_BASIC_INFORMATION);
255 Status = MmCopyToCaller(UnsafeTimerInformation, &TimerInformation,
256 sizeof(TIMER_BASIC_INFORMATION));
257 if (!NT_SUCCESS(Status))
259 ObDereferenceObject(Timer);
263 if (UnsafeResultLength != NULL)
265 Status = MmCopyToCaller(UnsafeResultLength, &ResultLength,
267 if (!NT_SUCCESS(Status))
269 ObDereferenceObject(Timer);
273 ObDereferenceObject(Timer);
274 return(STATUS_SUCCESS);
279 NtSetTimer(IN HANDLE TimerHandle,
280 IN PLARGE_INTEGER DueTime,
281 IN PTIMERAPCROUTINE TimerApcRoutine,
282 IN PVOID TimerContext,
284 IN ULONG Period OPTIONAL,
285 OUT PBOOLEAN PreviousState OPTIONAL)
293 DPRINT("NtSetTimer()\n");
295 Status = ObReferenceObjectByHandle(TimerHandle,
301 if (!NT_SUCCESS(Status))
304 State = KeReadStateTimer(&Timer->Timer);
306 if (Timer->Running == TRUE)
308 /* cancel running timer */
309 OldIrql = KeRaiseIrqlToDpcLevel();
310 KeCancelTimer(&Timer->Timer);
311 KeRemoveQueueDpc(&Timer->Dpc);
312 KeRemoveQueueApc(&Timer->Apc);
313 Timer->Running = FALSE;
314 KeLowerIrql(OldIrql);
316 if( TimerApcRoutine )
317 KeInitializeApc(&Timer->Apc,
318 KeGetCurrentThread(),
320 (PKKERNEL_ROUTINE)NtpTimerApcKernelRoutine,
321 (PKRUNDOWN_ROUTINE)NULL,
322 (PKNORMAL_ROUTINE)TimerApcRoutine,
326 Result = KeSetTimerEx (&Timer->Timer,
329 TimerApcRoutine ? &Timer->Dpc : 0 );
332 ObDereferenceObject(Timer);
333 DPRINT1( "KeSetTimer says the timer was already running, this shouldn't be\n" );
334 return STATUS_UNSUCCESSFUL;
337 Timer->Running = TRUE;
339 ObDereferenceObject(Timer);
341 if (PreviousState != NULL)
343 *PreviousState = State;
346 return STATUS_SUCCESS;