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
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
14 #include <internal/debug.h>
17 /* TYPES ********************************************************************/
19 typedef struct _NTTIMER
28 /* GLOBALS ******************************************************************/
30 POBJECT_TYPE ExTimerType
= NULL
;
32 static GENERIC_MAPPING ExpTimerMapping
= {
33 STANDARD_RIGHTS_READ
| TIMER_QUERY_STATE
,
34 STANDARD_RIGHTS_WRITE
| TIMER_MODIFY_STATE
,
35 STANDARD_RIGHTS_EXECUTE
| SYNCHRONIZE
,
38 static const INFORMATION_CLASS_INFO ExTimerInfoClass
[] =
40 ICI_SQ_SAME( sizeof(TIMER_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
), /* TimerBasicInformation */
43 /* FUNCTIONS *****************************************************************/
46 ExpCreateTimer(PVOID ObjectBody
,
49 POBJECT_ATTRIBUTES ObjectAttributes
)
51 DPRINT("ExpCreateTimer(ObjectBody %x, Parent %x, RemainingPath %S)\n",
52 ObjectBody
, Parent
, RemainingPath
);
54 if (RemainingPath
!= NULL
&& wcschr(RemainingPath
+1, '\\') != NULL
)
56 return(STATUS_UNSUCCESSFUL
);
59 return(STATUS_SUCCESS
);
64 ExpDeleteTimer(PVOID ObjectBody
)
67 PNTTIMER Timer
= ObjectBody
;
69 DPRINT("ExpDeleteTimer()\n");
71 OldIrql
= KeRaiseIrqlToDpcLevel();
73 KeCancelTimer(&Timer
->Timer
);
74 KeRemoveQueueDpc(&Timer
->Dpc
);
75 KeRemoveQueueApc(&Timer
->Apc
);
76 Timer
->Running
= FALSE
;
83 ExpTimerDpcRoutine(PKDPC Dpc
,
84 PVOID DeferredContext
,
85 PVOID SystemArgument1
,
86 PVOID SystemArgument2
)
90 DPRINT("ExpTimerDpcRoutine()\n");
92 Timer
= (PNTTIMER
)DeferredContext
;
96 KeInsertQueueApc(&Timer
->Apc
,
105 ExpTimerApcKernelRoutine(PKAPC Apc
,
106 PKNORMAL_ROUTINE
* NormalRoutine
,
107 PVOID
* NormalContext
,
108 PVOID
* SystemArgument1
,
109 PVOID
* SystemArguemnt2
)
111 DPRINT("ExpTimerApcKernelRoutine()\n");
117 ExpInitializeTimerImplementation(VOID
)
120 ExTimerType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
122 RtlCreateUnicodeString(&ExTimerType
->TypeName
, L
"Timer");
124 ExTimerType
->Tag
= TAG('T', 'I', 'M', 'T');
125 ExTimerType
->PeakObjects
= 0;
126 ExTimerType
->PeakHandles
= 0;
127 ExTimerType
->TotalObjects
= 0;
128 ExTimerType
->TotalHandles
= 0;
129 ExTimerType
->PagedPoolCharge
= 0;
130 ExTimerType
->NonpagedPoolCharge
= sizeof(NTTIMER
);
131 ExTimerType
->Mapping
= &ExpTimerMapping
;
132 ExTimerType
->Dump
= NULL
;
133 ExTimerType
->Open
= NULL
;
134 ExTimerType
->Close
= NULL
;
135 ExTimerType
->Delete
= ExpDeleteTimer
;
136 ExTimerType
->Parse
= NULL
;
137 ExTimerType
->Security
= NULL
;
138 ExTimerType
->QueryName
= NULL
;
139 ExTimerType
->OkayToClose
= NULL
;
140 ExTimerType
->Create
= ExpCreateTimer
;
141 ExTimerType
->DuplicationNotify
= NULL
;
143 ObpCreateTypeObject(ExTimerType
);
148 NtCancelTimer(IN HANDLE TimerHandle
,
149 OUT PBOOLEAN CurrentState OPTIONAL
)
152 KPROCESSOR_MODE PreviousMode
;
153 NTSTATUS Status
= STATUS_SUCCESS
;
155 PreviousMode
= ExGetPreviousMode();
157 DPRINT("NtCancelTimer(0x%x, 0x%x)\n", TimerHandle
, CurrentState
);
159 if(CurrentState
!= NULL
&& PreviousMode
!= KernelMode
)
163 ProbeForWrite(CurrentState
,
169 Status
= _SEH_GetExceptionCode();
173 if(!NT_SUCCESS(Status
))
179 Status
= ObReferenceObjectByHandle(TimerHandle
,
185 if(NT_SUCCESS(Status
))
188 KIRQL OldIrql
= KeRaiseIrqlToDpcLevel();
190 State
= KeCancelTimer(&Timer
->Timer
);
191 KeRemoveQueueDpc(&Timer
->Dpc
);
192 KeRemoveQueueApc(&Timer
->Apc
);
193 Timer
->Running
= FALSE
;
195 KeLowerIrql(OldIrql
);
196 ObDereferenceObject(Timer
);
198 if(CurrentState
!= NULL
)
202 *CurrentState
= State
;
206 Status
= _SEH_GetExceptionCode();
217 NtCreateTimer(OUT PHANDLE TimerHandle
,
218 IN ACCESS_MASK DesiredAccess
,
219 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
220 IN TIMER_TYPE TimerType
)
224 KPROCESSOR_MODE PreviousMode
;
225 NTSTATUS Status
= STATUS_SUCCESS
;
227 DPRINT("NtCreateTimer()\n");
229 PreviousMode
= ExGetPreviousMode();
231 if(PreviousMode
!= KernelMode
)
235 ProbeForWrite(TimerHandle
,
241 Status
= _SEH_GetExceptionCode();
245 if(!NT_SUCCESS(Status
))
251 Status
= ObCreateObject(PreviousMode
,
260 if(NT_SUCCESS(Status
))
262 KeInitializeTimerEx(&Timer
->Timer
,
265 KeInitializeDpc(&Timer
->Dpc
,
269 Timer
->Running
= FALSE
;
271 Status
= ObInsertObject ((PVOID
)Timer
,
277 ObDereferenceObject(Timer
);
279 if(NT_SUCCESS(Status
))
283 *TimerHandle
= hTimer
;
287 Status
= _SEH_GetExceptionCode();
298 NtOpenTimer(OUT PHANDLE TimerHandle
,
299 IN ACCESS_MASK DesiredAccess
,
300 IN POBJECT_ATTRIBUTES ObjectAttributes
)
303 KPROCESSOR_MODE PreviousMode
;
304 NTSTATUS Status
= STATUS_SUCCESS
;
306 DPRINT("NtOpenTimer()\n");
308 PreviousMode
= ExGetPreviousMode();
310 if(PreviousMode
!= KernelMode
)
314 ProbeForWrite(TimerHandle
,
320 Status
= _SEH_GetExceptionCode();
324 if(!NT_SUCCESS(Status
))
330 Status
= ObOpenObjectByName(ObjectAttributes
,
337 if(NT_SUCCESS(Status
))
341 *TimerHandle
= hTimer
;
345 Status
= _SEH_GetExceptionCode();
355 NtQueryTimer(IN HANDLE TimerHandle
,
356 IN TIMER_INFORMATION_CLASS TimerInformationClass
,
357 OUT PVOID TimerInformation
,
358 IN ULONG TimerInformationLength
,
359 OUT PULONG ReturnLength OPTIONAL
)
362 KPROCESSOR_MODE PreviousMode
;
363 NTSTATUS Status
= STATUS_SUCCESS
;
365 PreviousMode
= ExGetPreviousMode();
367 DefaultQueryInfoBufferCheck(TimerInformationClass
,
370 TimerInformationLength
,
374 if(!NT_SUCCESS(Status
))
376 DPRINT1("NtQueryTimer() failed, Status: 0x%x\n", Status
);
380 Status
= ObReferenceObjectByHandle(TimerHandle
,
386 if(NT_SUCCESS(Status
))
388 switch(TimerInformationClass
)
390 case TimerBasicInformation
:
392 PTIMER_BASIC_INFORMATION BasicInfo
= (PTIMER_BASIC_INFORMATION
)TimerInformation
;
396 /* FIXME - interrupt correction */
397 BasicInfo
->TimeRemaining
.QuadPart
= Timer
->Timer
.DueTime
.QuadPart
;
398 BasicInfo
->SignalState
= (BOOLEAN
)Timer
->Timer
.Header
.SignalState
;
400 if(ReturnLength
!= NULL
)
402 *ReturnLength
= sizeof(TIMER_BASIC_INFORMATION
);
407 Status
= _SEH_GetExceptionCode();
414 Status
= STATUS_NOT_IMPLEMENTED
;
418 ObDereferenceObject(Timer
);
426 NtSetTimer(IN HANDLE TimerHandle
,
427 IN PLARGE_INTEGER DueTime
,
428 IN PTIMER_APC_ROUTINE TimerApcRoutine OPTIONAL
,
429 IN PVOID TimerContext OPTIONAL
,
430 IN BOOLEAN ResumeTimer
,
431 IN LONG Period OPTIONAL
,
432 OUT PBOOLEAN PreviousState OPTIONAL
)
437 LARGE_INTEGER TimerDueTime
;
438 KPROCESSOR_MODE PreviousMode
;
439 NTSTATUS Status
= STATUS_SUCCESS
;
441 DPRINT("NtSetTimer()\n");
443 PreviousMode
= ExGetPreviousMode();
445 if(PreviousMode
!= KernelMode
)
449 ProbeForRead(DueTime
,
450 sizeof(LARGE_INTEGER
),
452 TimerDueTime
= *DueTime
;
454 if(PreviousState
!= NULL
)
456 ProbeForWrite(PreviousState
,
463 Status
= _SEH_GetExceptionCode();
467 if(!NT_SUCCESS(Status
))
473 Status
= ObReferenceObjectByHandle(TimerHandle
,
479 if (!NT_SUCCESS(Status
))
484 State
= KeReadStateTimer(&Timer
->Timer
);
486 if (Timer
->Running
== TRUE
)
488 /* cancel running timer */
489 const KIRQL OldIrql
= KeRaiseIrqlToDpcLevel();
490 KeCancelTimer(&Timer
->Timer
);
491 KeRemoveQueueDpc(&Timer
->Dpc
);
492 KeRemoveQueueApc(&Timer
->Apc
);
493 Timer
->Running
= FALSE
;
494 KeLowerIrql(OldIrql
);
499 KeInitializeApc(&Timer
->Apc
,
500 KeGetCurrentThread(),
501 OriginalApcEnvironment
,
502 &ExpTimerApcKernelRoutine
,
503 (PKRUNDOWN_ROUTINE
)NULL
,
504 (PKNORMAL_ROUTINE
)TimerApcRoutine
,
509 Result
= KeSetTimerEx(&Timer
->Timer
,
512 TimerApcRoutine
? &Timer
->Dpc
: 0 );
515 ObDereferenceObject(Timer
);
516 DPRINT1( "KeSetTimer says the timer was already running, this shouldn't be\n" );
517 return STATUS_UNSUCCESSFUL
;
520 Timer
->Running
= TRUE
;
522 ObDereferenceObject(Timer
);
524 if (PreviousState
!= NULL
)
528 *PreviousState
= State
;
532 Status
= _SEH_GetExceptionCode();