Remove /nt directory
[reactos.git] / reactos / ntoskrnl / ex / timer.c
1 /* $Id: nttimer.c 12779 2005-01-04 04:45:00Z gdalsnes $
2 *
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)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <ntoskrnl.h>
15 #include <internal/debug.h>
16
17
18 /* TYPES ********************************************************************/
19
20 typedef struct _NTTIMER
21 {
22 KTIMER Timer;
23 KDPC Dpc;
24 KAPC Apc;
25 BOOLEAN Running;
26 } NTTIMER, *PNTTIMER;
27
28
29 /* GLOBALS ******************************************************************/
30
31 POBJECT_TYPE ExTimerType = NULL;
32
33 static GENERIC_MAPPING ExpTimerMapping = {
34 STANDARD_RIGHTS_READ | TIMER_QUERY_STATE,
35 STANDARD_RIGHTS_WRITE | TIMER_MODIFY_STATE,
36 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE,
37 TIMER_ALL_ACCESS};
38
39
40 /* FUNCTIONS *****************************************************************/
41
42 NTSTATUS STDCALL
43 ExpCreateTimer(PVOID ObjectBody,
44 PVOID Parent,
45 PWSTR RemainingPath,
46 POBJECT_ATTRIBUTES ObjectAttributes)
47 {
48 DPRINT("ExpCreateTimer(ObjectBody %x, Parent %x, RemainingPath %S)\n",
49 ObjectBody, Parent, RemainingPath);
50
51 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
52 {
53 return(STATUS_UNSUCCESSFUL);
54 }
55
56 return(STATUS_SUCCESS);
57 }
58
59
60 VOID STDCALL
61 ExpDeleteTimer(PVOID ObjectBody)
62 {
63 KIRQL OldIrql;
64 PNTTIMER Timer = ObjectBody;
65
66 DPRINT("ExpDeleteTimer()\n");
67
68 OldIrql = KeRaiseIrqlToDpcLevel();
69
70 KeCancelTimer(&Timer->Timer);
71 KeRemoveQueueDpc(&Timer->Dpc);
72 KeRemoveQueueApc(&Timer->Apc);
73 Timer->Running = FALSE;
74
75 KeLowerIrql(OldIrql);
76 }
77
78
79 VOID STDCALL
80 ExpTimerDpcRoutine(PKDPC Dpc,
81 PVOID DeferredContext,
82 PVOID SystemArgument1,
83 PVOID SystemArgument2)
84 {
85 PNTTIMER Timer;
86
87 DPRINT("ExpTimerDpcRoutine()\n");
88
89 Timer = (PNTTIMER)DeferredContext;
90
91 if ( Timer->Running )
92 {
93 KeInsertQueueApc(&Timer->Apc,
94 SystemArgument1,
95 SystemArgument2,
96 IO_NO_INCREMENT);
97 }
98 }
99
100
101 VOID STDCALL
102 ExpTimerApcKernelRoutine(PKAPC Apc,
103 PKNORMAL_ROUTINE* NormalRoutine,
104 PVOID* NormalContext,
105 PVOID* SystemArgument1,
106 PVOID* SystemArguemnt2)
107 {
108 DPRINT("ExpTimerApcKernelRoutine()\n");
109
110 }
111
112
113 VOID INIT_FUNCTION
114 ExpInitializeTimerImplementation(VOID)
115 {
116 ASSERT(!ExTimerType)
117 ExTimerType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
118
119 RtlCreateUnicodeString(&ExTimerType->TypeName, L"Timer");
120
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;
139
140 ObpCreateTypeObject(ExTimerType);
141 }
142
143
144 NTSTATUS STDCALL
145 NtCancelTimer(IN HANDLE TimerHandle,
146 OUT PBOOLEAN CurrentState OPTIONAL)
147 {
148 PNTTIMER Timer;
149 NTSTATUS Status;
150 BOOLEAN State;
151 KIRQL OldIrql;
152
153 DPRINT("NtCancelTimer()\n");
154 Status = ObReferenceObjectByHandle(TimerHandle,
155 TIMER_ALL_ACCESS,
156 ExTimerType,
157 UserMode,
158 (PVOID*)&Timer,
159 NULL);
160 if (!NT_SUCCESS(Status))
161 return Status;
162
163 OldIrql = KeRaiseIrqlToDpcLevel();
164
165 State = KeCancelTimer(&Timer->Timer);
166 KeRemoveQueueDpc(&Timer->Dpc);
167 KeRemoveQueueApc(&Timer->Apc);
168 Timer->Running = FALSE;
169
170 KeLowerIrql(OldIrql);
171 ObDereferenceObject(Timer);
172
173 if (CurrentState != NULL)
174 {
175 *CurrentState = State;
176 }
177
178 return STATUS_SUCCESS;
179 }
180
181
182 NTSTATUS STDCALL
183 NtCreateTimer(OUT PHANDLE TimerHandle,
184 IN ACCESS_MASK DesiredAccess,
185 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
186 IN TIMER_TYPE TimerType)
187 {
188 PNTTIMER Timer;
189 NTSTATUS Status;
190
191 DPRINT("NtCreateTimer()\n");
192 Status = ObCreateObject(ExGetPreviousMode(),
193 ExTimerType,
194 ObjectAttributes,
195 ExGetPreviousMode(),
196 NULL,
197 sizeof(NTTIMER),
198 0,
199 0,
200 (PVOID*)&Timer);
201 if (!NT_SUCCESS(Status))
202 return Status;
203
204 KeInitializeTimerEx(&Timer->Timer,
205 TimerType);
206
207 KeInitializeDpc(&Timer->Dpc,
208 &ExpTimerDpcRoutine,
209 Timer);
210
211 Timer->Running = FALSE;
212
213 Status = ObInsertObject ((PVOID)Timer,
214 NULL,
215 DesiredAccess,
216 0,
217 NULL,
218 TimerHandle);
219
220 ObDereferenceObject(Timer);
221
222 return Status;
223 }
224
225
226 NTSTATUS STDCALL
227 NtOpenTimer(OUT PHANDLE TimerHandle,
228 IN ACCESS_MASK DesiredAccess,
229 IN POBJECT_ATTRIBUTES ObjectAttributes)
230 {
231 NTSTATUS Status;
232
233 Status = ObOpenObjectByName(ObjectAttributes,
234 ExTimerType,
235 NULL,
236 UserMode,
237 DesiredAccess,
238 NULL,
239 TimerHandle);
240 return Status;
241 }
242
243
244 NTSTATUS STDCALL
245 NtQueryTimer(IN HANDLE TimerHandle,
246 IN TIMER_INFORMATION_CLASS TimerInformationClass,
247 OUT PVOID TimerInformation,
248 IN ULONG TimerInformationLength,
249 OUT PULONG ReturnLength OPTIONAL)
250 {
251 PNTTIMER Timer;
252 TIMER_BASIC_INFORMATION SafeTimerInformation;
253 ULONG ResultLength;
254 NTSTATUS Status;
255
256 Status = ObReferenceObjectByHandle(TimerHandle,
257 TIMER_QUERY_STATE,
258 ExTimerType,
259 (KPROCESSOR_MODE)KeGetPreviousMode(),
260 (PVOID*)&Timer,
261 NULL);
262 if (!NT_SUCCESS(Status))
263 {
264 return(Status);
265 }
266
267 if (TimerInformationClass != TimerBasicInformation)
268 {
269 ObDereferenceObject(Timer);
270 return(STATUS_INVALID_INFO_CLASS);
271 }
272 if (TimerInformationLength < sizeof(TIMER_BASIC_INFORMATION))
273 {
274 ObDereferenceObject(Timer);
275 return(STATUS_INFO_LENGTH_MISMATCH);
276 }
277
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);
282
283 Status = MmCopyToCaller(TimerInformation, &SafeTimerInformation,
284 sizeof(TIMER_BASIC_INFORMATION));
285 if (!NT_SUCCESS(Status))
286 {
287 ObDereferenceObject(Timer);
288 return(Status);
289 }
290
291 if (ReturnLength != NULL)
292 {
293 Status = MmCopyToCaller(ReturnLength, &ResultLength,
294 sizeof(ULONG));
295 if (!NT_SUCCESS(Status))
296 {
297 ObDereferenceObject(Timer);
298 return(Status);
299 }
300 }
301 ObDereferenceObject(Timer);
302 return(STATUS_SUCCESS);
303 }
304
305
306 NTSTATUS STDCALL
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)
314 {
315 PNTTIMER Timer;
316 NTSTATUS Status;
317 BOOLEAN Result;
318 BOOLEAN State;
319
320 DPRINT("NtSetTimer()\n");
321
322 Status = ObReferenceObjectByHandle(TimerHandle,
323 TIMER_ALL_ACCESS,
324 ExTimerType,
325 (KPROCESSOR_MODE)KeGetPreviousMode(),
326 (PVOID*)&Timer,
327 NULL);
328 if (!NT_SUCCESS(Status))
329 {
330 return Status;
331 }
332
333 State = KeReadStateTimer(&Timer->Timer);
334
335 if (Timer->Running == TRUE)
336 {
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);
344 }
345
346 if (TimerApcRoutine)
347 {
348 KeInitializeApc(&Timer->Apc,
349 KeGetCurrentThread(),
350 OriginalApcEnvironment,
351 &ExpTimerApcKernelRoutine,
352 (PKRUNDOWN_ROUTINE)NULL,
353 (PKNORMAL_ROUTINE)TimerApcRoutine,
354 (KPROCESSOR_MODE)KeGetPreviousMode(),
355 TimerContext);
356 }
357
358 Result = KeSetTimerEx(&Timer->Timer,
359 *DueTime,
360 Period,
361 TimerApcRoutine ? &Timer->Dpc : 0 );
362 if (Result == TRUE)
363 {
364 ObDereferenceObject(Timer);
365 DPRINT1( "KeSetTimer says the timer was already running, this shouldn't be\n" );
366 return STATUS_UNSUCCESSFUL;
367 }
368
369 Timer->Running = TRUE;
370
371 ObDereferenceObject(Timer);
372
373 if (PreviousState != NULL)
374 {
375 *PreviousState = State;
376 }
377
378 return STATUS_SUCCESS;
379 }
380
381 /* EOF */