1 /* $Id: nttimer.c 12779 2005-01-04 04:45:00Z gdalsnes $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ex/timer.c
6 * PURPOSE: User-mode timers
7 * PROGRAMMER: David Welch (welch@mcmail.com)
12 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
18 /* TYPES ********************************************************************/
20 typedef struct _NTTIMER
29 /* GLOBALS ******************************************************************/
31 POBJECT_TYPE ExTimerType
= NULL
;
33 static GENERIC_MAPPING ExpTimerMapping
= {
34 STANDARD_RIGHTS_READ
| TIMER_QUERY_STATE
,
35 STANDARD_RIGHTS_WRITE
| TIMER_MODIFY_STATE
,
36 STANDARD_RIGHTS_EXECUTE
| SYNCHRONIZE
,
40 /* FUNCTIONS *****************************************************************/
43 ExpCreateTimer(PVOID ObjectBody
,
46 POBJECT_ATTRIBUTES ObjectAttributes
)
48 DPRINT("ExpCreateTimer(ObjectBody %x, Parent %x, RemainingPath %S)\n",
49 ObjectBody
, Parent
, RemainingPath
);
51 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+1, '\\') != NULL
)
53 return(STATUS_UNSUCCESSFUL
);
56 return(STATUS_SUCCESS
);
61 ExpDeleteTimer(PVOID ObjectBody
)
64 PNTTIMER Timer
= ObjectBody
;
66 DPRINT("ExpDeleteTimer()\n");
68 OldIrql
= KeRaiseIrqlToDpcLevel();
70 KeCancelTimer(&Timer
->Timer
);
71 KeRemoveQueueDpc(&Timer
->Dpc
);
72 KeRemoveQueueApc(&Timer
->Apc
);
73 Timer
->Running
= FALSE
;
80 ExpTimerDpcRoutine(PKDPC Dpc
,
81 PVOID DeferredContext
,
82 PVOID SystemArgument1
,
83 PVOID SystemArgument2
)
87 DPRINT("ExpTimerDpcRoutine()\n");
89 Timer
= (PNTTIMER
)DeferredContext
;
93 KeInsertQueueApc(&Timer
->Apc
,
102 ExpTimerApcKernelRoutine(PKAPC Apc
,
103 PKNORMAL_ROUTINE
* NormalRoutine
,
104 PVOID
* NormalContext
,
105 PVOID
* SystemArgument1
,
106 PVOID
* SystemArguemnt2
)
108 DPRINT("ExpTimerApcKernelRoutine()\n");
114 ExpInitializeTimerImplementation(VOID
)
117 ExTimerType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
119 RtlCreateUnicodeString(&ExTimerType
->TypeName
, L
"Timer");
121 ExTimerType
->Tag
= TAG('T', 'I', 'M', 'T');
122 ExTimerType
->PeakObjects
= 0;
123 ExTimerType
->PeakHandles
= 0;
124 ExTimerType
->TotalObjects
= 0;
125 ExTimerType
->TotalHandles
= 0;
126 ExTimerType
->PagedPoolCharge
= 0;
127 ExTimerType
->NonpagedPoolCharge
= sizeof(NTTIMER
);
128 ExTimerType
->Mapping
= &ExpTimerMapping
;
129 ExTimerType
->Dump
= NULL
;
130 ExTimerType
->Open
= NULL
;
131 ExTimerType
->Close
= NULL
;
132 ExTimerType
->Delete
= ExpDeleteTimer
;
133 ExTimerType
->Parse
= NULL
;
134 ExTimerType
->Security
= NULL
;
135 ExTimerType
->QueryName
= NULL
;
136 ExTimerType
->OkayToClose
= NULL
;
137 ExTimerType
->Create
= ExpCreateTimer
;
138 ExTimerType
->DuplicationNotify
= NULL
;
140 ObpCreateTypeObject(ExTimerType
);
145 NtCancelTimer(IN HANDLE TimerHandle
,
146 OUT PBOOLEAN CurrentState OPTIONAL
)
153 DPRINT("NtCancelTimer()\n");
154 Status
= ObReferenceObjectByHandle(TimerHandle
,
160 if (!NT_SUCCESS(Status
))
163 OldIrql
= KeRaiseIrqlToDpcLevel();
165 State
= KeCancelTimer(&Timer
->Timer
);
166 KeRemoveQueueDpc(&Timer
->Dpc
);
167 KeRemoveQueueApc(&Timer
->Apc
);
168 Timer
->Running
= FALSE
;
170 KeLowerIrql(OldIrql
);
171 ObDereferenceObject(Timer
);
173 if (CurrentState
!= NULL
)
175 *CurrentState
= State
;
178 return STATUS_SUCCESS
;
183 NtCreateTimer(OUT PHANDLE TimerHandle
,
184 IN ACCESS_MASK DesiredAccess
,
185 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
186 IN TIMER_TYPE TimerType
)
191 DPRINT("NtCreateTimer()\n");
192 Status
= ObCreateObject(ExGetPreviousMode(),
201 if (!NT_SUCCESS(Status
))
204 KeInitializeTimerEx(&Timer
->Timer
,
207 KeInitializeDpc(&Timer
->Dpc
,
211 Timer
->Running
= FALSE
;
213 Status
= ObInsertObject ((PVOID
)Timer
,
220 ObDereferenceObject(Timer
);
227 NtOpenTimer(OUT PHANDLE TimerHandle
,
228 IN ACCESS_MASK DesiredAccess
,
229 IN POBJECT_ATTRIBUTES ObjectAttributes
)
233 Status
= ObOpenObjectByName(ObjectAttributes
,
245 NtQueryTimer(IN HANDLE TimerHandle
,
246 IN TIMER_INFORMATION_CLASS TimerInformationClass
,
247 OUT PVOID TimerInformation
,
248 IN ULONG TimerInformationLength
,
249 OUT PULONG ReturnLength OPTIONAL
)
252 TIMER_BASIC_INFORMATION SafeTimerInformation
;
256 Status
= ObReferenceObjectByHandle(TimerHandle
,
259 (KPROCESSOR_MODE
)KeGetPreviousMode(),
262 if (!NT_SUCCESS(Status
))
267 if (TimerInformationClass
!= TimerBasicInformation
)
269 ObDereferenceObject(Timer
);
270 return(STATUS_INVALID_INFO_CLASS
);
272 if (TimerInformationLength
< sizeof(TIMER_BASIC_INFORMATION
))
274 ObDereferenceObject(Timer
);
275 return(STATUS_INFO_LENGTH_MISMATCH
);
278 memcpy(&SafeTimerInformation
.TimeRemaining
, &Timer
->Timer
.DueTime
,
279 sizeof(LARGE_INTEGER
));
280 SafeTimerInformation
.SignalState
= (BOOLEAN
)Timer
->Timer
.Header
.SignalState
;
281 ResultLength
= sizeof(TIMER_BASIC_INFORMATION
);
283 Status
= MmCopyToCaller(TimerInformation
, &SafeTimerInformation
,
284 sizeof(TIMER_BASIC_INFORMATION
));
285 if (!NT_SUCCESS(Status
))
287 ObDereferenceObject(Timer
);
291 if (ReturnLength
!= NULL
)
293 Status
= MmCopyToCaller(ReturnLength
, &ResultLength
,
295 if (!NT_SUCCESS(Status
))
297 ObDereferenceObject(Timer
);
301 ObDereferenceObject(Timer
);
302 return(STATUS_SUCCESS
);
307 NtSetTimer(IN HANDLE TimerHandle
,
308 IN PLARGE_INTEGER DueTime
,
309 IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL
,
310 IN PVOID TimerContext OPTIONAL
,
311 IN BOOLEAN ResumeTimer
,
312 IN LONG Period OPTIONAL
,
313 OUT PBOOLEAN PreviousState OPTIONAL
)
320 DPRINT("NtSetTimer()\n");
322 Status
= ObReferenceObjectByHandle(TimerHandle
,
325 (KPROCESSOR_MODE
)KeGetPreviousMode(),
328 if (!NT_SUCCESS(Status
))
333 State
= KeReadStateTimer(&Timer
->Timer
);
335 if (Timer
->Running
== TRUE
)
337 /* cancel running timer */
338 const KIRQL OldIrql
= KeRaiseIrqlToDpcLevel();
339 KeCancelTimer(&Timer
->Timer
);
340 KeRemoveQueueDpc(&Timer
->Dpc
);
341 KeRemoveQueueApc(&Timer
->Apc
);
342 Timer
->Running
= FALSE
;
343 KeLowerIrql(OldIrql
);
348 KeInitializeApc(&Timer
->Apc
,
349 KeGetCurrentThread(),
350 OriginalApcEnvironment
,
351 &ExpTimerApcKernelRoutine
,
352 (PKRUNDOWN_ROUTINE
)NULL
,
353 (PKNORMAL_ROUTINE
)TimerApcRoutine
,
354 (KPROCESSOR_MODE
)KeGetPreviousMode(),
358 Result
= KeSetTimerEx(&Timer
->Timer
,
361 TimerApcRoutine
? &Timer
->Dpc
: 0 );
364 ObDereferenceObject(Timer
);
365 DPRINT1( "KeSetTimer says the timer was already running, this shouldn't be\n" );
366 return STATUS_UNSUCCESSFUL
;
369 Timer
->Running
= TRUE
;
371 ObDereferenceObject(Timer
);
373 if (PreviousState
!= NULL
)
375 *PreviousState
= State
;
378 return STATUS_SUCCESS
;