Use upper-case ASSERT macros.
[reactos.git] / reactos / ntoskrnl / ke / timer.c
1 /* $Id: timer.c,v 1.82 2004/10/22 20:30:48 ekohl Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/timer.c
6 * PURPOSE: Handle timers
7 * PROGRAMMER: David Welch (welch@mcmail.com)
8 * UPDATE HISTORY:
9 * 28/05/98: Created
10 * 12/3/99: Phillip Susi: enabled the timers, fixed spin lock
11 */
12
13 /* NOTES ******************************************************************/
14 /*
15 * System time units are 100-nanosecond intervals
16 */
17
18 /* INCLUDES ***************************************************************/
19
20 #include <ntoskrnl.h>
21 #define NDEBUG
22 #include <internal/debug.h>
23
24
25 /* GLOBALS ****************************************************************/
26
27 /*
28 * Current time
29 */
30 #if defined(__GNUC__)
31 LARGE_INTEGER SystemBootTime = (LARGE_INTEGER)0LL;
32 #else
33 LARGE_INTEGER SystemBootTime = { 0 };
34 #endif
35
36 CHAR KiTimerSystemAuditing = 0;
37
38 /*
39 * Number of timer interrupts since initialisation
40 */
41 volatile ULONGLONG KeTickCount = 0;
42 volatile ULONG KiRawTicks = 0;
43
44 /*
45 * The increment in the system clock every timer tick (in system time units)
46 *
47 * = (1/18.2)*10^9
48 *
49 * RJJ was 54945055
50 */
51 #define CLOCK_INCREMENT (100000)
52
53 #ifdef __GNUC__
54 ULONG EXPORTED KeMaximumIncrement = 100000;
55 ULONG EXPORTED KeMinimumIncrement = 100000;
56 #else
57 /* Microsoft-style declarations */
58 EXPORTED ULONG KeMaximumIncrement = 100000;
59 EXPORTED ULONG KeMinimumIncrement = 100000;
60 #endif
61
62
63
64 /*
65 * PURPOSE: List of timers
66 */
67 static LIST_ENTRY AbsoluteTimerListHead;
68 static LIST_ENTRY RelativeTimerListHead;
69 static KSPIN_LOCK TimerListLock;
70 static KSPIN_LOCK TimerValueLock;
71 static KDPC ExpireTimerDpc;
72
73 /* must raise IRQL to PROFILE_LEVEL and grab spin lock there, to sync with ISR */
74
75 extern HANDLE PsIdleThreadHandle;
76
77 #define MICROSECONDS_PER_TICK (10000)
78 #define TICKS_TO_CALIBRATE (1)
79 #define CALIBRATE_PERIOD (MICROSECONDS_PER_TICK * TICKS_TO_CALIBRATE)
80 #define SYSTEM_TIME_UNITS_PER_MSEC (10000)
81
82 static BOOLEAN TimerInitDone = FALSE;
83
84 /* FUNCTIONS **************************************************************/
85
86
87 NTSTATUS STDCALL
88 NtQueryTimerResolution(OUT PULONG MinimumResolution,
89 OUT PULONG MaximumResolution,
90 OUT PULONG ActualResolution)
91 {
92 UNIMPLEMENTED;
93 return STATUS_NOT_IMPLEMENTED;
94 }
95
96
97 NTSTATUS STDCALL
98 NtSetTimerResolution(IN ULONG RequestedResolution,
99 IN BOOL SetOrUnset,
100 OUT PULONG ActualResolution)
101 {
102 UNIMPLEMENTED;
103 return STATUS_NOT_IMPLEMENTED;
104 }
105
106
107 NTSTATUS STDCALL
108 NtQueryPerformanceCounter(IN PLARGE_INTEGER Counter,
109 IN PLARGE_INTEGER Frequency)
110 {
111 LARGE_INTEGER PerfCounter;
112 LARGE_INTEGER PerfFrequency;
113 NTSTATUS Status;
114
115 PerfCounter = KeQueryPerformanceCounter(&PerfFrequency);
116
117 if (Counter != NULL)
118 {
119 Status = MmCopyToCaller(&Counter->QuadPart, &PerfCounter.QuadPart, sizeof(PerfCounter.QuadPart));
120 if (!NT_SUCCESS(Status))
121 {
122 return(Status);
123 }
124 }
125
126 if (Frequency != NULL)
127 {
128 Status = MmCopyToCaller(&Frequency->QuadPart, &PerfFrequency.QuadPart, sizeof(PerfFrequency.QuadPart));
129 if (!NT_SUCCESS(Status))
130 {
131 return(Status);
132 }
133 }
134
135 return(STATUS_SUCCESS);
136 }
137
138
139 NTSTATUS STDCALL
140 NtDelayExecution(IN ULONG Alertable,
141 IN TIME* Interval)
142 {
143 NTSTATUS Status;
144 LARGE_INTEGER Timeout;
145
146 Status = MmCopyFromCaller(&Timeout, Interval, sizeof(Timeout));
147 if (!NT_SUCCESS(Status))
148 {
149 return(Status);
150 }
151
152 Timeout = *((PLARGE_INTEGER)Interval);
153 DPRINT("NtDelayExecution(Alertable %d, Internal %x) IntervalP %x\n",
154 Alertable, Internal, Timeout);
155
156 DPRINT("Execution delay is %d/%d\n",
157 Timeout.u.HighPart, Timeout.u.LowPart);
158 Status = KeDelayExecutionThread(UserMode, (BOOLEAN)Alertable, &Timeout);
159 return(Status);
160 }
161
162
163 /*
164 * @implemented
165 */
166 NTSTATUS STDCALL
167 KeDelayExecutionThread (KPROCESSOR_MODE WaitMode,
168 BOOLEAN Alertable,
169 PLARGE_INTEGER Interval)
170 /*
171 * FUNCTION: Puts the current thread into an alertable or nonalertable
172 * wait state for a given internal
173 * ARGUMENTS:
174 * WaitMode = Processor mode in which the caller is waiting
175 * Altertable = Specifies if the wait is alertable
176 * Interval = Specifies the interval to wait
177 * RETURNS: Status
178 */
179 {
180 PKTHREAD Thread = KeGetCurrentThread();
181
182 KeSetTimer(&Thread->Timer, *Interval, NULL);
183 return (KeWaitForSingleObject(&Thread->Timer,
184 (WaitMode == KernelMode) ? Executive : UserRequest, /* TMN: Was unconditionally Executive */
185 WaitMode, /* TMN: Was UserMode */
186 Alertable,
187 NULL));
188 }
189
190
191 /*
192 * @implemented
193 */
194 ULONG STDCALL
195 KeQueryTimeIncrement(VOID)
196 /*
197 * FUNCTION: Gets the increment (in 100-nanosecond units) that is added to
198 * the system clock every time the clock interrupts
199 * RETURNS: The increment
200 */
201 {
202 return(CLOCK_INCREMENT);
203 }
204
205
206 /*
207 * @implemented
208 */
209 VOID STDCALL
210 KeQuerySystemTime(PLARGE_INTEGER CurrentTime)
211 /*
212 * FUNCTION: Gets the current system time
213 * ARGUMENTS:
214 * CurrentTime (OUT) = The routine stores the current time here
215 * NOTE: The time is the number of 100-nanosecond intervals since the
216 * 1st of January, 1601.
217 */
218 {
219 do
220 {
221 CurrentTime->u.HighPart = SharedUserData->SystemTime.High1Part;
222 CurrentTime->u.LowPart = SharedUserData->SystemTime.LowPart;
223 }
224 while (CurrentTime->u.HighPart != SharedUserData->SystemTime.High2Part);
225 }
226
227 ULONGLONG STDCALL
228 KeQueryInterruptTime(VOID)
229 {
230 LARGE_INTEGER CurrentTime;
231
232 do
233 {
234 CurrentTime.u.HighPart = SharedUserData->InterruptTime.High1Part;
235 CurrentTime.u.LowPart = SharedUserData->InterruptTime.LowPart;
236 }
237 while (CurrentTime.u.HighPart != SharedUserData->InterruptTime.High2Part);
238
239 return CurrentTime.QuadPart;
240 }
241
242 /*
243 * @implemented
244 */
245 ULONG
246 STDCALL
247 NtGetTickCount(VOID)
248 {
249 LARGE_INTEGER TickCount;
250 KeQueryTickCount(&TickCount);
251 return TickCount.u.LowPart;
252 }
253
254 /*
255 * @implemented
256 */
257 BOOLEAN STDCALL
258 KeSetTimer (PKTIMER Timer,
259 LARGE_INTEGER DueTime,
260 PKDPC Dpc)
261 /*
262 * FUNCTION: Sets the absolute or relative interval at which a timer object
263 * is to be set to the signaled state and optionally supplies a
264 * CustomTimerDpc to be executed when the timer expires.
265 * ARGUMENTS:
266 * Timer = Points to a previously initialized timer object
267 * DueTimer = If positive then absolute time to expire at
268 * If negative then the relative time to expire at
269 * Dpc = If non-NULL then a dpc to be called when the timer expires
270 * RETURNS: True if the timer was already in the system timer queue
271 * False otherwise
272 */
273 {
274 return(KeSetTimerEx(Timer, DueTime, 0, Dpc));
275 }
276
277 /*
278 * @implemented
279 */
280 BOOLEAN STDCALL
281 KeSetTimerEx (PKTIMER Timer,
282 LARGE_INTEGER DueTime,
283 LONG Period,
284 PKDPC Dpc)
285 /*
286 * FUNCTION: Sets the absolute or relative interval at which a timer object
287 * is to be set to the signaled state and optionally supplies a
288 * CustomTimerDpc to be executed when the timer expires.
289 * ARGUMENTS:
290 * Timer = Points to a previously initialized timer object
291 * DueTimer = If positive then absolute time to expire at
292 * If negative then the relative time to expire at
293 * Dpc = If non-NULL then a dpc to be called when the timer expires
294 * RETURNS: True if the timer was already in the system timer queue
295 * False otherwise
296 */
297 {
298 KIRQL oldlvl;
299 LARGE_INTEGER Time;
300 BOOLEAN AlreadyInList;
301
302 DPRINT("KeSetTimerEx(Timer %x), DueTime: \n",Timer);
303
304 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
305
306 KeAcquireSpinLock(&TimerListLock, &oldlvl);
307
308 Timer->Dpc = Dpc;
309 if (DueTime.QuadPart < 0)
310 {
311 Timer->Header.Absolute = 0;
312 Timer->DueTime.QuadPart = KeQueryInterruptTime() - DueTime.QuadPart;
313 }
314 else
315 {
316 KeQuerySystemTime(&Time);
317 Timer->Header.Absolute = 1;
318 if (DueTime.QuadPart >= Time.QuadPart)
319 {
320 Timer->DueTime.QuadPart = DueTime.QuadPart;
321 }
322 else
323 {
324 Timer->DueTime.QuadPart = Time.QuadPart;
325 }
326 }
327 Timer->Period = Period;
328 Timer->Header.SignalState = FALSE;
329 AlreadyInList = (Timer->TimerListEntry.Flink == NULL) ? FALSE : TRUE;
330 ASSERT((Timer->TimerListEntry.Flink == NULL && Timer->TimerListEntry.Blink == NULL) ||
331 (Timer->TimerListEntry.Flink != NULL && Timer->TimerListEntry.Blink != NULL));
332 if (AlreadyInList)
333 {
334 RemoveEntryList(&Timer->TimerListEntry);
335 }
336 if (Timer->Header.Absolute)
337 {
338 InsertAscendingList(&AbsoluteTimerListHead,
339 KTIMER,
340 TimerListEntry,
341 Timer,
342 DueTime.QuadPart);
343
344 }
345 else
346 {
347 InsertAscendingList(&RelativeTimerListHead,
348 KTIMER,
349 TimerListEntry,
350 Timer,
351 DueTime.QuadPart);
352
353 }
354
355 KeReleaseSpinLock(&TimerListLock, oldlvl);
356
357 return AlreadyInList;
358 }
359
360 /*
361 * @implemented
362 */
363 BOOLEAN STDCALL
364 KeCancelTimer (PKTIMER Timer)
365 /*
366 * FUNCTION: Removes a timer from the system timer list
367 * ARGUMENTS:
368 * Timer = timer to cancel
369 * RETURNS: True if the timer was running
370 * False otherwise
371 */
372 {
373 KIRQL oldlvl;
374
375 DPRINT("KeCancelTimer(Timer %x)\n",Timer);
376
377 KeAcquireSpinLock(&TimerListLock, &oldlvl);
378
379 if (Timer->TimerListEntry.Flink == NULL)
380 {
381 KeReleaseSpinLock(&TimerListLock, oldlvl);
382 return(FALSE);
383 }
384 if (Timer->Header.Absolute)
385 {
386 ASSERT(&Timer->TimerListEntry != &AbsoluteTimerListHead);
387 }
388 else
389 {
390 ASSERT(&Timer->TimerListEntry != &RelativeTimerListHead);
391 }
392 ASSERT(Timer->TimerListEntry.Flink != &Timer->TimerListEntry);
393 RemoveEntryList(&Timer->TimerListEntry);
394 Timer->TimerListEntry.Flink = Timer->TimerListEntry.Blink = NULL;
395 KeReleaseSpinLock(&TimerListLock, oldlvl);
396
397 return(TRUE);
398 }
399
400 /*
401 * @implemented
402 */
403 BOOLEAN STDCALL
404 KeReadStateTimer (PKTIMER Timer)
405 {
406 return (BOOLEAN)(Timer->Header.SignalState);
407 }
408
409 /*
410 * @implemented
411 */
412 VOID STDCALL
413 KeInitializeTimer (PKTIMER Timer)
414 /*
415 * FUNCTION: Initalizes a kernel timer object
416 * ARGUMENTS:
417 * Timer = caller supplied storage for the timer
418 * NOTE: This function initializes a notification timer
419 */
420 {
421 KeInitializeTimerEx(Timer, NotificationTimer);
422 }
423
424 /*
425 * @implemented
426 */
427 VOID STDCALL
428 KeInitializeTimerEx (PKTIMER Timer,
429 TIMER_TYPE Type)
430 /*
431 * FUNCTION: Initializes a kernel timer object
432 * ARGUMENTS:
433 * Timer = caller supplied storage for the timer
434 * Type = the type of timer (notification or synchronization)
435 * NOTE: When a notification type expires all waiting threads are released
436 * and the timer remains signalled until it is explicitly reset. When a
437 * syncrhonization timer expires its state is set to signalled until a
438 * single waiting thread is released and then the timer is reset.
439 */
440 {
441 ULONG IType;
442
443 if (Type == NotificationTimer)
444 {
445 IType = InternalNotificationTimer;
446 }
447 else if (Type == SynchronizationTimer)
448 {
449 IType = InternalSynchronizationTimer;
450 }
451 else
452 {
453 ASSERT(FALSE);
454 return;
455 }
456
457 KeInitializeDispatcherHeader(&Timer->Header,
458 IType,
459 sizeof(KTIMER) / sizeof(ULONG),
460 FALSE);
461 Timer->TimerListEntry.Flink = Timer->TimerListEntry.Blink = NULL;
462 }
463
464 /*
465 * @implemented
466 */
467 VOID STDCALL
468 KeQueryTickCount(PLARGE_INTEGER TickCount)
469 /*
470 * FUNCTION: Returns the number of ticks since the system was booted
471 * ARGUMENTS:
472 * TickCount (OUT) = Points to storage for the number of ticks
473 */
474 {
475 TickCount->QuadPart = KeTickCount;
476 }
477
478 /*
479 * @implemented
480 */
481 ULONG
482 STDCALL
483 KeQueryRuntimeThread(
484 IN PKTHREAD Thread,
485 OUT PULONG UserTime
486 )
487 {
488 /* Return the User Time */
489 *UserTime = Thread->UserTime;
490
491 /* Return the Kernel Time */
492 return Thread->KernelTime;
493 }
494
495 /*
496 * @implemented
497 */
498 VOID
499 STDCALL
500 KeSetTimeIncrement(
501 IN ULONG MaxIncrement,
502 IN ULONG MinIncrement
503 )
504 {
505 /* Set some Internal Variables */
506 /* FIXME: We use a harcoded CLOCK_INCREMENT. That *must* be changed */
507 KeMaximumIncrement = MaxIncrement;
508 KeMinimumIncrement = MinIncrement;
509 }
510
511 /*
512 * We enter this function at IRQL DISPATCH_LEVEL, and with the
513 * TimerListLock held.
514 */
515 STATIC VOID
516 HandleExpiredTimer(PKTIMER Timer)
517 {
518 DPRINT("HandleExpiredTime(Timer %x)\n", Timer);
519 if (Timer->Dpc != NULL)
520 {
521 DPRINT("Timer->Dpc %x Timer->Dpc->DeferredRoutine %x\n",
522 Timer->Dpc, Timer->Dpc->DeferredRoutine);
523 KeInsertQueueDpc(Timer->Dpc,
524 NULL,
525 NULL);
526 DPRINT("Finished dpc routine\n");
527 }
528
529 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
530
531 KeAcquireDispatcherDatabaseLockAtDpcLevel();
532 Timer->Header.SignalState = TRUE;
533 KeDispatcherObjectWake(&Timer->Header);
534 KeReleaseDispatcherDatabaseLockFromDpcLevel();
535
536 if (Timer->Period != 0)
537 {
538 Timer->DueTime.QuadPart +=
539 Timer->Period * SYSTEM_TIME_UNITS_PER_MSEC;
540 if (Timer->Header.Absolute)
541 {
542 InsertAscendingList(&AbsoluteTimerListHead,
543 KTIMER,
544 TimerListEntry,
545 Timer,
546 DueTime.QuadPart);
547 }
548 else
549 {
550 InsertAscendingList(&RelativeTimerListHead,
551 KTIMER,
552 TimerListEntry,
553 Timer,
554 DueTime.QuadPart);
555 }
556 }
557 }
558
559 VOID STDCALL
560 KeExpireTimers(PKDPC Dpc,
561 PVOID Context1,
562 PVOID Arg1,
563 PVOID Arg2)
564 {
565 PLIST_ENTRY current_entry = NULL;
566 PKTIMER current = NULL;
567 ULONG Eip = (ULONG)Arg1;
568 LARGE_INTEGER InterruptTime;
569 LARGE_INTEGER SystemTime;
570 LIST_ENTRY TimerList;
571
572 DPRINT("KeExpireTimers()\n");
573
574 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
575
576 InitializeListHead(&TimerList);
577
578 KeAcquireSpinLockAtDpcLevel(&TimerListLock);
579
580 InterruptTime.QuadPart = KeQueryInterruptTime();
581 KeQuerySystemTime(&SystemTime);
582
583 current_entry = RelativeTimerListHead.Flink;
584 ASSERT(current_entry);
585 while (current_entry != &RelativeTimerListHead)
586 {
587 current = CONTAINING_RECORD(current_entry, KTIMER, TimerListEntry);
588 ASSERT(current);
589 ASSERT(current_entry != &RelativeTimerListHead);
590 ASSERT(current_entry->Flink != current_entry);
591 if ((ULONGLONG)InterruptTime.QuadPart < current->DueTime.QuadPart)
592 {
593 break;
594 }
595 current_entry = current_entry->Flink;
596 RemoveEntryList(&current->TimerListEntry);
597 InsertTailList(&TimerList, &current->TimerListEntry);
598 }
599
600 current_entry = AbsoluteTimerListHead.Flink;
601 ASSERT(current_entry);
602 while (current_entry != &AbsoluteTimerListHead)
603 {
604 current = CONTAINING_RECORD(current_entry, KTIMER, TimerListEntry);
605 ASSERT(current);
606 ASSERT(current_entry != &AbsoluteTimerListHead);
607 ASSERT(current_entry->Flink != current_entry);
608 if ((ULONGLONG)SystemTime.QuadPart < current->DueTime.QuadPart)
609 {
610 break;
611 }
612 current_entry = current_entry->Flink;
613 RemoveEntryList(&current->TimerListEntry);
614 InsertTailList(&TimerList, &current->TimerListEntry);
615 }
616
617 while (!IsListEmpty(&TimerList))
618 {
619 current_entry = RemoveHeadList(&TimerList);
620 current = CONTAINING_RECORD(current_entry, KTIMER, TimerListEntry);
621 current->TimerListEntry.Flink = current->TimerListEntry.Blink = NULL;
622 HandleExpiredTimer(current);
623 }
624
625 KiAddProfileEvent(ProfileTime, Eip);
626
627 KeReleaseSpinLockFromDpcLevel(&TimerListLock);
628 }
629
630
631 VOID
632 KiUpdateSystemTime(KIRQL oldIrql,
633 PKIRQ_TRAPFRAME Tf)
634 /*
635 * FUNCTION: Handles a timer interrupt
636 */
637 {
638 LARGE_INTEGER Time;
639
640 ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
641
642 KiRawTicks++;
643
644 if (TimerInitDone == FALSE)
645 {
646 return;
647 }
648 /*
649 * Increment the number of timers ticks
650 */
651 KeTickCount++;
652 SharedUserData->TickCountLow++;
653 KiAcquireSpinLock(&TimerValueLock);
654
655 Time.u.LowPart = SharedUserData->InterruptTime.LowPart;
656 Time.u.HighPart = SharedUserData->InterruptTime.High1Part;
657 Time.QuadPart += CLOCK_INCREMENT;
658 SharedUserData->InterruptTime.High2Part = Time.u.HighPart;
659 SharedUserData->InterruptTime.LowPart = Time.u.LowPart;
660 SharedUserData->InterruptTime.High1Part = Time.u.HighPart;
661
662 Time.u.LowPart = SharedUserData->SystemTime.LowPart;
663 Time.u.HighPart = SharedUserData->SystemTime.High1Part;
664 Time.QuadPart += CLOCK_INCREMENT;
665 SharedUserData->SystemTime.High2Part = Time.u.HighPart;
666 SharedUserData->SystemTime.LowPart = Time.u.LowPart;
667 SharedUserData->SystemTime.High1Part = Time.u.HighPart;
668
669 KiReleaseSpinLock(&TimerValueLock);
670
671 /* Update process and thread times */
672 KiUpdateProcessThreadTime(oldIrql, Tf);
673
674 /*
675 * Queue a DPC that will expire timers
676 */
677 KeInsertQueueDpc(&ExpireTimerDpc, (PVOID)Tf->Eip, 0);
678 }
679
680
681 VOID INIT_FUNCTION
682 KeInitializeTimerImpl(VOID)
683 /*
684 * FUNCTION: Initializes timer irq handling
685 * NOTE: This is only called once from main()
686 */
687 {
688 TIME_FIELDS TimeFields;
689
690 DPRINT("KeInitializeTimerImpl()\n");
691 InitializeListHead(&AbsoluteTimerListHead);
692 InitializeListHead(&RelativeTimerListHead);
693 KeInitializeSpinLock(&TimerListLock);
694 KeInitializeSpinLock(&TimerValueLock);
695 KeInitializeDpc(&ExpireTimerDpc, KeExpireTimers, 0);
696 /*
697 * Calculate the starting time for the system clock
698 */
699 HalQueryRealTimeClock(&TimeFields);
700 RtlTimeFieldsToTime(&TimeFields, &SystemBootTime);
701
702 SharedUserData->TickCountLow = 0;
703 SharedUserData->TickCountMultiplier = 167783691; // 2^24 * 1193182 / 119310
704 SharedUserData->InterruptTime.High2Part = 0;
705 SharedUserData->InterruptTime.LowPart = 0;
706 SharedUserData->InterruptTime.High1Part = 0;
707 SharedUserData->SystemTime.High2Part = SystemBootTime.u.HighPart;
708 SharedUserData->SystemTime.LowPart = SystemBootTime.u.LowPart;
709 SharedUserData->SystemTime.High1Part = SystemBootTime.u.HighPart;
710
711 TimerInitDone = TRUE;
712 DPRINT("Finished KeInitializeTimerImpl()\n");
713 }
714
715
716 VOID
717 KiUpdateProcessThreadTime(KIRQL oldIrql, PKIRQ_TRAPFRAME Tf)
718 {
719 PKTHREAD CurrentThread;
720 PEPROCESS ThreadsProcess;
721 PKPCR Pcr;
722
723 Pcr = KeGetCurrentKPCR();
724
725 /*
726 * Make sure no counting can take place until Processes and Threads are
727 * running!
728 */
729 if ((PsInitialSystemProcess == NULL) || (Pcr->PrcbData.IdleThread == NULL) ||
730 (KiTimerSystemAuditing == 0))
731 {
732 return;
733 }
734
735 DPRINT("KernelTime %u, UserTime %u \n", Kpcr->PrcbData.KernelTime, Kpcr->PrcbData.UserTime);
736
737 if (oldIrql > DISPATCH_LEVEL)
738 {
739 Pcr->PrcbData.InterruptTime++;
740 }
741 else if (oldIrql == DISPATCH_LEVEL)
742 {
743 Pcr->PrcbData.DpcTime++;
744 }
745 else
746 {
747 CurrentThread = KeGetCurrentThread();
748 ThreadsProcess = ((PETHREAD)CurrentThread)->ThreadsProcess;
749 /*
750 * Cs bit 0 is always set for user mode if we are in protected mode.
751 * V86 mode is counted as user time.
752 */
753 if (Tf->Cs & 0x1 ||
754 Tf->Eflags & X86_EFLAGS_VM)
755 {
756 #ifdef MP
757 InterlockedIncrement((PLONG)&ThreadsProcess->Pcb.UserTime);
758 #else
759 ThreadsProcess->Pcb.UserTime++;
760 #endif
761 CurrentThread->UserTime++;
762 Pcr->PrcbData.UserTime++;
763 }
764 else
765 {
766 #ifdef MP
767 InterlockedIncrement((PLONG)&ThreadsProcess->Pcb.KernelTime);
768 #else
769 ThreadsProcess->Pcb.KernelTime++;
770 #endif
771 CurrentThread->KernelTime++;
772 Pcr->PrcbData.KernelTime++;
773 }
774 }
775 }
776
777 /*
778 * @unimplemented
779 */
780 VOID
781 FASTCALL
782 KeSetTimeUpdateNotifyRoutine(
783 IN PTIME_UPDATE_NOTIFY_ROUTINE NotifyRoutine
784 )
785 {
786 UNIMPLEMENTED;
787 }
788
789
790 /*
791 * @unimplemented
792 */
793 VOID
794 STDCALL
795 KeUpdateRunTime(
796 IN PKTRAP_FRAME TrapFrame
797 )
798 {
799 KIRQL OldIrql = PASSIVE_LEVEL;
800
801 /* These are equivalent... we should just remove the Ki and stick it here... */
802 KiUpdateProcessThreadTime(OldIrql, (PKIRQ_TRAPFRAME)TrapFrame);
803 }
804
805 /*
806 * @unimplemented
807 */
808 VOID
809 STDCALL
810 KeUpdateSystemTime(
811 IN PKTRAP_FRAME TrapFrame,
812 IN ULONG Increment
813 )
814 {
815 KIRQL OldIrql = PASSIVE_LEVEL;
816
817 /* These are equivalent... we should just remove the Ki and stick it here... */
818 KiUpdateSystemTime(OldIrql, (PKIRQ_TRAPFRAME)TrapFrame);
819 }
820
821 /*EOF*/
822