1 /* $Id: nttimer.c,v 1.22 2003/10/12 17:05:48 hbirr 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
)
124 ExTimerType
= ExAllocatePool(NonPagedPool
, sizeof(OBJECT_TYPE
));
126 RtlCreateUnicodeString(&ExTimerType
->TypeName
, L
"Timer");
128 ExTimerType
->Tag
= TAG('T', 'I', 'M', 'T');
129 ExTimerType
->MaxObjects
= ULONG_MAX
;
130 ExTimerType
->MaxHandles
= ULONG_MAX
;
131 ExTimerType
->TotalObjects
= 0;
132 ExTimerType
->TotalHandles
= 0;
133 ExTimerType
->PagedPoolCharge
= 0;
134 ExTimerType
->NonpagedPoolCharge
= sizeof(NTTIMER
);
135 ExTimerType
->Mapping
= &ExpTimerMapping
;
136 ExTimerType
->Dump
= NULL
;
137 ExTimerType
->Open
= NULL
;
138 ExTimerType
->Close
= NULL
;
139 ExTimerType
->Delete
= NtpDeleteTimer
;
140 ExTimerType
->Parse
= NULL
;
141 ExTimerType
->Security
= NULL
;
142 ExTimerType
->QueryName
= NULL
;
143 ExTimerType
->OkayToClose
= NULL
;
144 ExTimerType
->Create
= NtpCreateTimer
;
145 ExTimerType
->DuplicationNotify
= NULL
;
147 ObpCreateTypeObject(ExTimerType
);
152 NtCancelTimer(IN HANDLE TimerHandle
,
153 OUT PBOOLEAN CurrentState OPTIONAL
)
160 DPRINT("NtCancelTimer()\n");
161 Status
= ObReferenceObjectByHandle(TimerHandle
,
167 if (!NT_SUCCESS(Status
))
170 OldIrql
= KeRaiseIrqlToDpcLevel();
172 State
= KeCancelTimer(&Timer
->Timer
);
173 KeRemoveQueueDpc(&Timer
->Dpc
);
174 KeRemoveQueueApc(&Timer
->Apc
);
175 Timer
->Running
= FALSE
;
177 KeLowerIrql(OldIrql
);
178 ObDereferenceObject(Timer
);
180 if (CurrentState
!= NULL
)
182 *CurrentState
= State
;
185 return STATUS_SUCCESS
;
190 NtCreateTimer(OUT PHANDLE TimerHandle
,
191 IN ACCESS_MASK DesiredAccess
,
192 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
193 IN TIMER_TYPE TimerType
)
198 DPRINT("NtCreateTimer()\n");
199 Status
= ObCreateObject(ExGetPreviousMode(),
208 if (!NT_SUCCESS(Status
))
211 KeInitializeTimerEx(&Timer
->Timer
,
214 KeInitializeDpc (&Timer
->Dpc
,
215 (PKDEFERRED_ROUTINE
)NtpTimerDpcRoutine
,
218 Timer
->Running
= FALSE
;
220 Status
= ObInsertObject ((PVOID
)Timer
,
227 ObDereferenceObject(Timer
);
234 NtOpenTimer(OUT PHANDLE TimerHandle
,
235 IN ACCESS_MASK DesiredAccess
,
236 IN POBJECT_ATTRIBUTES ObjectAttributes
)
240 Status
= ObOpenObjectByName(ObjectAttributes
,
252 NtQueryTimer(IN HANDLE TimerHandle
,
253 IN CINT TimerInformationClass
,
254 OUT PVOID UnsafeTimerInformation
,
256 OUT PULONG UnsafeResultLength
)
259 TIMER_BASIC_INFORMATION TimerInformation
;
263 Status
= ObReferenceObjectByHandle(TimerHandle
,
269 if (!NT_SUCCESS(Status
))
274 if (TimerInformationClass
!= TimerBasicInformation
)
276 ObDereferenceObject(Timer
);
277 return(STATUS_INVALID_INFO_CLASS
);
279 if (Length
< sizeof(TIMER_BASIC_INFORMATION
))
281 ObDereferenceObject(Timer
);
282 return(STATUS_INFO_LENGTH_MISMATCH
);
285 memcpy(&TimerInformation
.TimeRemaining
, &Timer
->Timer
.DueTime
,
286 sizeof(LARGE_INTEGER
));
287 TimerInformation
.SignalState
= Timer
->Timer
.Header
.SignalState
;
288 ResultLength
= sizeof(TIMER_BASIC_INFORMATION
);
290 Status
= MmCopyToCaller(UnsafeTimerInformation
, &TimerInformation
,
291 sizeof(TIMER_BASIC_INFORMATION
));
292 if (!NT_SUCCESS(Status
))
294 ObDereferenceObject(Timer
);
298 if (UnsafeResultLength
!= NULL
)
300 Status
= MmCopyToCaller(UnsafeResultLength
, &ResultLength
,
302 if (!NT_SUCCESS(Status
))
304 ObDereferenceObject(Timer
);
308 ObDereferenceObject(Timer
);
309 return(STATUS_SUCCESS
);
314 NtSetTimer(IN HANDLE TimerHandle
,
315 IN PLARGE_INTEGER DueTime
,
316 IN PTIMERAPCROUTINE TimerApcRoutine
,
317 IN PVOID TimerContext
,
319 IN ULONG Period OPTIONAL
,
320 OUT PBOOLEAN PreviousState OPTIONAL
)
328 DPRINT("NtSetTimer()\n");
330 Status
= ObReferenceObjectByHandle(TimerHandle
,
336 if (!NT_SUCCESS(Status
))
339 State
= KeReadStateTimer(&Timer
->Timer
);
341 if (Timer
->Running
== TRUE
)
343 /* cancel running timer */
344 OldIrql
= KeRaiseIrqlToDpcLevel();
345 KeCancelTimer(&Timer
->Timer
);
346 KeRemoveQueueDpc(&Timer
->Dpc
);
347 KeRemoveQueueApc(&Timer
->Apc
);
348 Timer
->Running
= FALSE
;
349 KeLowerIrql(OldIrql
);
351 if( TimerApcRoutine
)
352 KeInitializeApc(&Timer
->Apc
,
353 KeGetCurrentThread(),
354 OriginalApcEnvironment
,
355 (PKKERNEL_ROUTINE
)NtpTimerApcKernelRoutine
,
356 (PKRUNDOWN_ROUTINE
)NULL
,
357 (PKNORMAL_ROUTINE
)TimerApcRoutine
,
361 Result
= KeSetTimerEx (&Timer
->Timer
,
364 TimerApcRoutine
? &Timer
->Dpc
: 0 );
367 ObDereferenceObject(Timer
);
368 DPRINT1( "KeSetTimer says the timer was already running, this shouldn't be\n" );
369 return STATUS_UNSUCCESSFUL
;
372 Timer
->Running
= TRUE
;
374 ObDereferenceObject(Timer
);
376 if (PreviousState
!= NULL
)
378 *PreviousState
= State
;
381 return STATUS_SUCCESS
;