ReactOS  0.4.14-dev-52-g6116262
time.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: BSD - See COPYING.ARM in the top level directory
4  * FILE: ntoskrnl/ke/time.c
5  * PURPOSE: Implements timebase functionality
6  * PROGRAMMERS: ReactOS Portable Systems Group
7  */
8 
9 /* INCLUDES *******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* GLOBALS ********************************************************************/
16 
20 
21 /* FUNCTIONS ******************************************************************/
22 
24 VOID
25 KiWriteSystemTime(volatile KSYSTEM_TIME *SystemTime, ULARGE_INTEGER NewTime)
26 {
27 #ifdef _WIN64
28  /* Do a single atomic write */
29  *(ULONGLONG*)SystemTime = NewTime.QuadPart;
30 #else
31  /* Update in 3 steps, so that a reader can recognize partial updates */
32  SystemTime->High1Time = NewTime.HighPart;
33  SystemTime->LowPart = NewTime.LowPart;
34  SystemTime->High2Time = NewTime.HighPart;
35 #endif
36 }
37 
39 VOID
41  PKPRCB Prcb,
42  PKTRAP_FRAME TrapFrame,
43  ULARGE_INTEGER InterruptTime)
44 {
45  ULONG Hand;
46 
47  /* Check for timer expiration */
48  Hand = KeTickCount.LowPart & (TIMER_TABLE_SIZE - 1);
49  if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
50  {
51  /* Check if we are already doing expiration */
52  if (!Prcb->TimerRequest)
53  {
54  /* Request a DPC to handle this */
55  Prcb->TimerRequest = (ULONG_PTR)TrapFrame;
56  Prcb->TimerHand = Hand;
58  }
59  }
60 }
61 
62 VOID
66  IN KIRQL Irql)
67 {
68  PKPRCB Prcb = KeGetCurrentPrcb();
69  ULARGE_INTEGER CurrentTime, InterruptTime;
70  LONG OldTickOffset;
71 
72  /* Check if this tick is being skipped */
73  if (Prcb->SkipTick)
74  {
75  /* Handle it next time */
76  Prcb->SkipTick = FALSE;
77 
78  /* Increase interrupt count and end the interrupt */
79  Prcb->InterruptCount++;
80  KiEndInterrupt(Irql, TrapFrame);
81 
82  /* Note: non-x86 return back to the caller! */
83  return;
84  }
85 
86  /* Add the increment time to the shared data */
87  InterruptTime.QuadPart = *(ULONGLONG*)&SharedUserData->InterruptTime;
88  InterruptTime.QuadPart += Increment;
89  KiWriteSystemTime(&SharedUserData->InterruptTime, InterruptTime);
90 
91  /* Check for timer expiration */
92  KiCheckForTimerExpiration(Prcb, TrapFrame, InterruptTime);
93 
94  /* Update the tick offset */
96 
97  /* If the debugger is enabled, check for break-in request */
99  {
100  /* Break-in requested! */
102  }
103 
104  /* Check for full tick */
105  if (OldTickOffset <= (LONG)Increment)
106  {
107  /* Update the system time */
108  CurrentTime.QuadPart = *(ULONGLONG*)&SharedUserData->SystemTime;
109  CurrentTime.QuadPart += KeTimeAdjustment;
110  KiWriteSystemTime(&SharedUserData->SystemTime, CurrentTime);
111 
112  /* Update the tick count */
113  CurrentTime.QuadPart = (*(ULONGLONG*)&KeTickCount) + 1;
114  KiWriteSystemTime(&KeTickCount, CurrentTime);
115 
116  /* Update it in the shared user data */
117  KiWriteSystemTime(&SharedUserData->TickCount, CurrentTime);
118 
119  /* Check for expiration with the new tick count as well */
120  KiCheckForTimerExpiration(Prcb, TrapFrame, InterruptTime);
121 
122  /* Reset the tick offset */
124 
125  /* Update processor/thread runtime */
126  KeUpdateRunTime(TrapFrame, Irql);
127  }
128  else
129  {
130  /* Increase interrupt count only */
131  Prcb->InterruptCount++;
132  }
133 
134  /* Disable interrupts and end the interrupt */
135  KiEndInterrupt(Irql, TrapFrame);
136 }
137 
138 VOID
139 NTAPI
141  IN KIRQL Irql)
142 {
144  PKPRCB Prcb = KeGetCurrentPrcb();
145 
146  /* Check if this tick is being skipped */
147  if (Prcb->SkipTick)
148  {
149  /* Handle it next time */
150  Prcb->SkipTick = FALSE;
151  return;
152  }
153 
154  /* Increase interrupt count */
155  Prcb->InterruptCount++;
156 
157  /* Check if we came from user mode */
158 #ifndef _M_ARM
159  if (KiUserTrap(TrapFrame) || (TrapFrame->EFlags & EFLAGS_V86_MASK))
160 #else
161  if (TrapFrame->PreviousMode == UserMode)
162 #endif
163  {
164  /* Increase thread user time */
165  Prcb->UserTime++;
166  Thread->UserTime++;
167  }
168  else
169  {
170  /* See if we were in an ISR */
171  Prcb->KernelTime++;
172  if (Irql > DISPATCH_LEVEL)
173  {
174  /* Handle that */
175  Prcb->InterruptTime++;
176  }
177  else if ((Irql < DISPATCH_LEVEL) || !(Prcb->DpcRoutineActive))
178  {
179  /* Handle being in kernel mode */
180  Thread->KernelTime++;
181  }
182  else
183  {
184  /* Handle being in a DPC */
185  Prcb->DpcTime++;
186 
187 #if DBG
188  /* Update the DPC time */
189  Prcb->DebugDpcTime++;
190 
191  /* Check if we have timed out */
192  if (Prcb->DebugDpcTime == KiDPCTimeout)
193  {
194  /* We did! */
195  DbgPrint("*** DPC routine > 1 sec --- This is not a break in KeUpdateSystemTime\n");
196 
197  /* Break if debugger is enabled */
199 
200  /* Clear state */
201  Prcb->DebugDpcTime = 0;
202  }
203 #endif
204  }
205  }
206 
207  /* Update DPC rates */
208  Prcb->DpcRequestRate = ((Prcb->DpcData[0].DpcCount - Prcb->DpcLastCount) +
209  Prcb->DpcRequestRate) >> 1;
210  Prcb->DpcLastCount = Prcb->DpcData[0].DpcCount;
211 
212  /* Check if the queue is large enough */
213  if ((Prcb->DpcData[0].DpcQueueDepth) && !(Prcb->DpcRoutineActive))
214  {
215  /* Request a DPC */
218 
219  /* Fix the maximum queue depth */
220  if ((Prcb->DpcRequestRate < KiIdealDpcRate) &&
221  (Prcb->MaximumDpcQueueDepth > 1))
222  {
223  /* Make it smaller */
224  Prcb->MaximumDpcQueueDepth--;
225  }
226  }
227  else
228  {
229  /* Check if we've reached the adjustment limit */
230  if (!(--Prcb->AdjustDpcThreshold))
231  {
232  /* Reset it, and check the queue maximum */
235  {
236  /* Increase it */
237  Prcb->MaximumDpcQueueDepth++;
238  }
239  }
240  }
241 
242  /* Decrement the thread quantum */
243  Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
244 
245  /* Check if the time expired */
246  if ((Thread->Quantum <= 0) && (Thread != Prcb->IdleThread))
247  {
248  /* Schedule a quantum end */
249  Prcb->QuantumEnd = 1;
251  }
252 }
BOOLEAN KiTimeAdjustmentEnabled
Definition: time.c:19
ULONG KeMaximumIncrement
Definition: clock.c:20
ULONG LowPart
Definition: ketypes.h:910
#define IN
Definition: typedefs.h:38
FORCEINLINE VOID KiWriteSystemTime(volatile KSYSTEM_TIME *SystemTime, ULARGE_INTEGER NewTime)
Definition: time.c:25
ULONG InterruptTime
Definition: ketypes.h:736
#define DbgPrint
Definition: loader.c:25
KDPC_DATA DpcData[2]
Definition: ketypes.h:676
FORCEINLINE struct _KPRCB * KeGetCurrentPrcb(VOID)
Definition: ketypes.h:1062
#define CLOCK_QUANTUM_DECREMENT
Definition: ketypes.h:138
$ULONG LowPart
Definition: ntbasedef.h:576
ULONG KiAdjustDpcThreshold
Definition: dpc.c:21
UCHAR QuantumEnd
Definition: ketypes.h:696
void DbgBreakPoint()
Definition: mach.c:553
#define FASTCALL
Definition: nt_native.h:50
_Out_ PKIRQL Irql
Definition: csq.h:179
ULONG DpcTime
Definition: ketypes.h:735
ULONG DebugDpcTime
Definition: ketypes.h:518
#define EFLAGS_V86_MASK
Definition: ketypes.h:129
ULONG DpcLastCount
Definition: ketypes.h:694
ULONG KeTimeAdjustment
Definition: time.c:18
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
ULONGLONG QuadPart
Definition: ms-dtyp.idl:185
long LONG
Definition: pedump.c:60
BOOLEAN NTAPI KdPollBreakIn(VOID)
Definition: kdmain.c:352
ULONG KiDPCTimeout
Definition: dpc.c:27
unsigned char BOOLEAN
#define KiEndInterrupt(x, y)
Definition: ke.h:175
UCHAR SkipTick
Definition: ketypes.h:738
BOOLEAN KdDebuggerEnabled
Definition: kdmain.c:16
#define FORCEINLINE
Definition: ntbasedef.h:221
ULONG KiIdealDpcRate
Definition: dpc.c:22
ULONG KernelTime
Definition: ketypes.h:733
LONG KiTickOffset
Definition: time.c:17
ULONG DpcCount
Definition: ketypes.h:748
#define InterlockedExchangeAdd
Definition: interlocked.h:181
ULONG InterruptCount
Definition: ketypes.h:732
FORCEINLINE VOID KiCheckForTimerExpiration(PKPRCB Prcb, PKTRAP_FRAME TrapFrame, ULARGE_INTEGER InterruptTime)
Definition: time.c:40
#define TIMER_TABLE_SIZE
Definition: ketypes.h:836
$ULONG HighPart
Definition: ntbasedef.h:577
UINT64 TimerRequest
Definition: ketypes.h:691
LONG High1Time
Definition: ketypes.h:911
uint64_t ULONGLONG
Definition: typedefs.h:65
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
KTIMER_TABLE_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]
Definition: timerobj.c:17
#define SharedUserData
UCHAR DpcRoutineActive
Definition: ketypes.h:688
NTKERNELAPI volatile KSYSTEM_TIME KeTickCount
Definition: clock.c:19
ULONG UserTime
Definition: ketypes.h:734
struct _KTHREAD * IdleThread
Definition: ketypes.h:568
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
ULONG KiMaximumDpcQueueDepth
Definition: dpc.c:19
VOID FASTCALL HalRequestSoftwareInterrupt(IN KIRQL Irql)
Definition: pic.c:271
LONG High2Time
Definition: ketypes.h:912
volatile ULONG DpcQueueDepth
Definition: ketypes.h:746
UINT64 TimerHand
Definition: ketypes.h:690
VOID NTAPI KeUpdateRunTime(IN PKTRAP_FRAME TrapFrame, IN KIRQL Irql)
Definition: time.c:140
#define DBG_STATUS_CONTROL_C
Definition: kdtypes.h:39
unsigned int ULONG
Definition: retypes.h:1
#define ULONG_PTR
Definition: config.h:101
VOID FASTCALL KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame, IN ULONG Increment, IN KIRQL Irql)
Definition: time.c:64
__analysis_noreturn NTSYSAPI VOID NTAPI DbgBreakPointWithStatus(_In_ ULONG Status)
ULONG DpcRequestRate
Definition: ketypes.h:684
#define KeGetCurrentThread
Definition: hal.h:44
LONG MaximumDpcQueueDepth
Definition: ketypes.h:683
IN OUT PLONG IN OUT PLONG Addend IN OUT PLONG IN LONG Increment
Definition: CrNtStubs.h:42
static PLARGE_INTEGER Time
Definition: time.c:105
BOOLEAN FORCEINLINE KiUserTrap(IN PKTRAP_FRAME TrapFrame)
Definition: ke.h:305
LONGLONG QuadPart
Definition: typedefs.h:112
ULONG AdjustDpcThreshold
Definition: ketypes.h:737