1 /* $Id: nttimer.c,v 1.23 2003/12/30 18:52:05 fireball Exp $
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>
18 #include <internal/ob.h>
20 #include <internal/pool.h>
21 #include <internal/safe.h>
23 #include <internal/debug.h>
26 /* TYPES ********************************************************************/
28 typedef struct _NTTIMER
37 /* GLOBALS ******************************************************************/
39 POBJECT_TYPE ExTimerType
= NULL
;
41 static GENERIC_MAPPING ExpTimerMapping
= {
42 STANDARD_RIGHTS_READ
| TIMER_QUERY_STATE
,
43 STANDARD_RIGHTS_WRITE
| TIMER_MODIFY_STATE
,
44 STANDARD_RIGHTS_EXECUTE
| SYNCHRONIZE
,
48 /* FUNCTIONS *****************************************************************/
51 NtpCreateTimer(PVOID ObjectBody
,
54 POBJECT_ATTRIBUTES ObjectAttributes
)
56 DPRINT("NtpCreateTimer(ObjectBody %x, Parent %x, RemainingPath %S)\n",
57 ObjectBody
, Parent
, RemainingPath
);
59 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+1, '\\') != NULL
)
61 return(STATUS_UNSUCCESSFUL
);
64 return(STATUS_SUCCESS
);
69 NtpDeleteTimer(PVOID ObjectBody
)
72 PNTTIMER Timer
= ObjectBody
;
74 DPRINT("NtpDeleteTimer()\n");
76 OldIrql
= KeRaiseIrqlToDpcLevel();
78 KeCancelTimer(&Timer
->Timer
);
79 KeRemoveQueueDpc(&Timer
->Dpc
);
80 KeRemoveQueueApc(&Timer
->Apc
);
81 Timer
->Running
= FALSE
;
88 NtpTimerDpcRoutine(PKDPC Dpc
,
89 PVOID DeferredContext
,
90 PVOID SystemArgument1
,
91 PVOID SystemArgument2
)
95 DPRINT("NtpTimerDpcRoutine()\n");
97 Timer
= (PNTTIMER
)DeferredContext
;
101 KeInsertQueueApc(&Timer
->Apc
,
110 NtpTimerApcKernelRoutine(PKAPC Apc
,
111 PKNORMAL_ROUTINE
* NormalRoutine
,
112 PVOID
* NormalContext
,
113 PVOID
* SystemArgument1
,
114 PVOID
* SystemArguemnt2
)
116 DPRINT("NtpTimerApcKernelRoutine()\n");
122 NtInitializeTimerImplementation(VOID
)
125 ExTimerType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
127 RtlCreateUnicodeString(&ExTimerType
->TypeName
, L
"Timer");
129 ExTimerType
->Tag
= TAG('T', 'I', 'M', 'T');
130 ExTimerType
->MaxObjects
= ULONG_MAX
;
131 ExTimerType
->MaxHandles
= ULONG_MAX
;
132 ExTimerType
->TotalObjects
= 0;
133 ExTimerType
->TotalHandles
= 0;
134 ExTimerType
->PagedPoolCharge
= 0;
135 ExTimerType
->NonpagedPoolCharge
= sizeof(NTTIMER
);
136 ExTimerType
->Mapping
= &ExpTimerMapping
;
137 ExTimerType
->Dump
= NULL
;
138 ExTimerType
->Open
= NULL
;
139 ExTimerType
->Close
= NULL
;
140 ExTimerType
->Delete
= NtpDeleteTimer
;
141 ExTimerType
->Parse
= NULL
;
142 ExTimerType
->Security
= NULL
;
143 ExTimerType
->QueryName
= NULL
;
144 ExTimerType
->OkayToClose
= NULL
;
145 ExTimerType
->Create
= NtpCreateTimer
;
146 ExTimerType
->DuplicationNotify
= NULL
;
148 ObpCreateTypeObject(ExTimerType
);
153 NtCancelTimer(IN HANDLE TimerHandle
,
154 OUT PBOOLEAN CurrentState OPTIONAL
)
161 DPRINT("NtCancelTimer()\n");
162 Status
= ObReferenceObjectByHandle(TimerHandle
,
168 if (!NT_SUCCESS(Status
))
171 OldIrql
= KeRaiseIrqlToDpcLevel();
173 State
= KeCancelTimer(&Timer
->Timer
);
174 KeRemoveQueueDpc(&Timer
->Dpc
);
175 KeRemoveQueueApc(&Timer
->Apc
);
176 Timer
->Running
= FALSE
;
178 KeLowerIrql(OldIrql
);
179 ObDereferenceObject(Timer
);
181 if (CurrentState
!= NULL
)
183 *CurrentState
= State
;
186 return STATUS_SUCCESS
;
191 NtCreateTimer(OUT PHANDLE TimerHandle
,
192 IN ACCESS_MASK DesiredAccess
,
193 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
194 IN TIMER_TYPE TimerType
)
199 DPRINT("NtCreateTimer()\n");
200 Status
= ObCreateObject(ExGetPreviousMode(),
209 if (!NT_SUCCESS(Status
))
212 KeInitializeTimerEx(&Timer
->Timer
,
215 KeInitializeDpc(&Timer
->Dpc
,
219 Timer
->Running
= FALSE
;
221 Status
= ObInsertObject ((PVOID
)Timer
,
228 ObDereferenceObject(Timer
);
235 NtOpenTimer(OUT PHANDLE TimerHandle
,
236 IN ACCESS_MASK DesiredAccess
,
237 IN POBJECT_ATTRIBUTES ObjectAttributes
)
241 Status
= ObOpenObjectByName(ObjectAttributes
,
253 NtQueryTimer(IN HANDLE TimerHandle
,
254 IN CINT TimerInformationClass
,
255 OUT PVOID UnsafeTimerInformation
,
257 OUT PULONG UnsafeResultLength
)
260 TIMER_BASIC_INFORMATION TimerInformation
;
264 Status
= ObReferenceObjectByHandle(TimerHandle
,
267 (KPROCESSOR_MODE
)KeGetPreviousMode(),
270 if (!NT_SUCCESS(Status
))
275 if (TimerInformationClass
!= TimerBasicInformation
)
277 ObDereferenceObject(Timer
);
278 return(STATUS_INVALID_INFO_CLASS
);
280 if (Length
< sizeof(TIMER_BASIC_INFORMATION
))
282 ObDereferenceObject(Timer
);
283 return(STATUS_INFO_LENGTH_MISMATCH
);
286 memcpy(&TimerInformation
.TimeRemaining
, &Timer
->Timer
.DueTime
,
287 sizeof(LARGE_INTEGER
));
288 TimerInformation
.SignalState
= (BOOLEAN
)Timer
->Timer
.Header
.SignalState
;
289 ResultLength
= sizeof(TIMER_BASIC_INFORMATION
);
291 Status
= MmCopyToCaller(UnsafeTimerInformation
, &TimerInformation
,
292 sizeof(TIMER_BASIC_INFORMATION
));
293 if (!NT_SUCCESS(Status
))
295 ObDereferenceObject(Timer
);
299 if (UnsafeResultLength
!= NULL
)
301 Status
= MmCopyToCaller(UnsafeResultLength
, &ResultLength
,
303 if (!NT_SUCCESS(Status
))
305 ObDereferenceObject(Timer
);
309 ObDereferenceObject(Timer
);
310 return(STATUS_SUCCESS
);
315 NtSetTimer(IN HANDLE TimerHandle
,
316 IN PLARGE_INTEGER DueTime
,
317 IN PTIMERAPCROUTINE TimerApcRoutine
,
318 IN PVOID TimerContext
,
320 IN ULONG Period OPTIONAL
,
321 OUT PBOOLEAN PreviousState OPTIONAL
)
328 DPRINT("NtSetTimer()\n");
330 Status
= ObReferenceObjectByHandle(TimerHandle
,
333 (KPROCESSOR_MODE
)KeGetPreviousMode(),
336 if (!NT_SUCCESS(Status
))
341 State
= KeReadStateTimer(&Timer
->Timer
);
343 if (Timer
->Running
== TRUE
)
345 /* cancel running timer */
346 const KIRQL OldIrql
= KeRaiseIrqlToDpcLevel();
347 KeCancelTimer(&Timer
->Timer
);
348 KeRemoveQueueDpc(&Timer
->Dpc
);
349 KeRemoveQueueApc(&Timer
->Apc
);
350 Timer
->Running
= FALSE
;
351 KeLowerIrql(OldIrql
);
356 KeInitializeApc(&Timer
->Apc
,
357 KeGetCurrentThread(),
358 OriginalApcEnvironment
,
359 &NtpTimerApcKernelRoutine
,
360 (PKRUNDOWN_ROUTINE
)NULL
,
361 (PKNORMAL_ROUTINE
)TimerApcRoutine
,
362 (KPROCESSOR_MODE
)KeGetPreviousMode(),
366 Result
= KeSetTimerEx(&Timer
->Timer
,
369 TimerApcRoutine
? &Timer
->Dpc
: 0 );
372 ObDereferenceObject(Timer
);
373 DPRINT1( "KeSetTimer says the timer was already running, this shouldn't be\n" );
374 return STATUS_UNSUCCESSFUL
;
377 Timer
->Running
= TRUE
;
379 ObDereferenceObject(Timer
);
381 if (PreviousState
!= NULL
)
383 *PreviousState
= State
;
386 return STATUS_SUCCESS
;