Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

525 lines
14 KiB

  1. /*++
  2. Module Name:
  3. clock.c
  4. Abstract:
  5. This module implements the platform specific clock interrupt processing
  6. routines in for the kernel.
  7. Author:
  8. Edward G. Chron (echron) 10-Apr-1996
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "ki.h"
  14. #include <ia64.h>
  15. #include <ntia64.h>
  16. #include <ntexapi.h>
  17. VOID
  18. KiProcessProfileList (
  19. IN PKTRAP_FRAME TrFrame,
  20. IN KPROFILE_SOURCE Source,
  21. IN PLIST_ENTRY ListHead
  22. );
  23. BOOLEAN
  24. KiChkTimerExpireSysDpc (
  25. IN ULONGLONG TickCountFirst,
  26. IN ULONGLONG TickCountLast
  27. )
  28. /*++
  29. Routine Description:
  30. This routine determines if it should attempt to place a timer expiration DPC
  31. in the system DPC list and to drive the DPC by initiating a dispatch level interrupt
  32. on the current processor.
  33. N.B. If DPC is already inserted on the DPC list, we're done.
  34. Arguments:
  35. TickCount - The lower tick count, timer table hand value
  36. Return Value:
  37. BOOLEAN - Set to true if Queued DPC or if DPC already Queued.
  38. --*/
  39. {
  40. ULONGLONG TickCount;
  41. ULONG Index;
  42. //
  43. // We use the first and last TickCount to figure out which entries in the
  44. // TimerTable to check. There is no point in going around the table
  45. // multiple times. If more ticks expire than there are timer table entries
  46. // we will expire timers out of order. We cap the number of TICKs in
  47. // KeUpdateSystemTime so just ASSERT that all is well here.
  48. //
  49. ASSERT((TickCountLast - TickCountFirst) < TIMER_TABLE_SIZE);
  50. Index = (ULONG)TickCountFirst % TIMER_TABLE_SIZE;
  51. for (TickCount = TickCountFirst; TickCount <= TickCountLast; TickCount++) {
  52. PLIST_ENTRY ListHead = &KiTimerTableListHead[Index];
  53. PLIST_ENTRY NextEntry = ListHead->Flink;
  54. //
  55. // Check to see if the list is empty.
  56. //
  57. if (NextEntry != ListHead) {
  58. PKTIMER Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry);
  59. ULONGLONG TimeValue = Timer->DueTime.QuadPart;
  60. ULARGE_INTEGER CurrentTime;
  61. //
  62. // See if timer expired.
  63. //
  64. CurrentTime.QuadPart = *((PULONGLONG)&SharedUserData->InterruptTime);
  65. if (TimeValue <= CurrentTime.QuadPart) {
  66. PKPRCB Prcb = KeGetCurrentPrcb();
  67. if (Prcb->TimerHand == 0) {
  68. Prcb->TimerHand = TickCount;
  69. KiRequestSoftwareInterrupt(DISPATCH_LEVEL);
  70. }
  71. return TRUE;
  72. }
  73. }
  74. if (++Index == TIMER_TABLE_SIZE) {
  75. Index = 0;
  76. }
  77. }
  78. return FALSE;
  79. }
  80. VOID
  81. KeUpdateSystemTime (
  82. IN PKTRAP_FRAME TrFrame,
  83. IN ULONG Increment
  84. )
  85. /*++
  86. Routine Description:
  87. This routine is executed on a single processor in the processor complex.
  88. It's function is to update the system time and to check to determine if a
  89. timer has expired.
  90. N.B. This routine is executed on a single processor in a multiprocess system.
  91. The remainder of the processors in the complex execute the quantum end and
  92. runtime update code.
  93. Arguments:
  94. TrFrame - Supplies a pointer to a trap frame.
  95. Increment - The time increment to be used to adjust the time slice for the next
  96. tick. The value is supplied in 100ns units.
  97. Return Value:
  98. None.
  99. --*/
  100. {
  101. ULONG LowTime;
  102. LONG HighTime;
  103. ULONGLONG SaveTickCount;
  104. ULONG TickCount;
  105. ULONG TimeAdjustment;
  106. ULONG TickAdjustment;
  107. if (Increment > KiMaxIntervalPerTimerInterrupt) {
  108. Increment = KiMaxIntervalPerTimerInterrupt;
  109. }
  110. //
  111. // Update the interrupt time in the shared region.
  112. //
  113. SaveTickCount = *((PULONGLONG)&SharedUserData->InterruptTime) + Increment;
  114. SharedUserData->InterruptTime.High2Time = (ULONG) (SaveTickCount >> 32);
  115. *((PULONGLONG)&SharedUserData->InterruptTime) = SaveTickCount;
  116. KiTickOffset -= Increment;
  117. if ((LONG)KiTickOffset > 0)
  118. {
  119. //
  120. // Tick has not completed (100ns time units remain).
  121. //
  122. // Determine if a timer has expired at the current hand value.
  123. //
  124. KiChkTimerExpireSysDpc(KeTickCount.QuadPart, KeTickCount.QuadPart);
  125. } else {
  126. //
  127. // One or more ticks have completed, tick count set to maximum increase
  128. // plus any residue and system time is updated.
  129. //
  130. // Compute next tick offset.
  131. //
  132. SaveTickCount = KeTickCount.QuadPart;
  133. //
  134. // We need to figure out how many ticks have elapsed. In the normal
  135. // case the answer will be one. Sometimes we may miss one or two.
  136. // So we will provide optimizations for 1 - 4 ticks and then fallback
  137. // to the more expensive divide and multiply for the generic case.
  138. //
  139. TimeAdjustment = KeTimeAdjustment;
  140. TickAdjustment = KeMaximumIncrement;
  141. for (TickCount = 1; TickCount <= 4; TickCount++) {
  142. if ((LONG)(KiTickOffset + TickAdjustment) > 0) {
  143. break;
  144. }
  145. TimeAdjustment += KeTimeAdjustment;
  146. TickAdjustment += KeMaximumIncrement;
  147. }
  148. if (TickCount > 4) {
  149. TickCount = -(LONG)KiTickOffset / KeMaximumIncrement + 1;
  150. TimeAdjustment = (ULONG)(KeTimeAdjustment * TickCount);
  151. TickAdjustment = (ULONG)(KeMaximumIncrement * TickCount);
  152. }
  153. LowTime = SharedUserData->SystemTime.LowPart + TimeAdjustment;
  154. HighTime = SharedUserData->SystemTime.High1Time + (LowTime < TimeAdjustment);
  155. SharedUserData->SystemTime.High2Time = HighTime;
  156. SharedUserData->SystemTime.LowPart = LowTime;
  157. SharedUserData->SystemTime.High1Time = HighTime;
  158. KeTickCount.QuadPart += TickCount;
  159. SharedUserData->TickCount.High2Time = KeTickCount.HighPart;
  160. SharedUserData->TickCountQuad = KeTickCount.QuadPart;
  161. KiTickOffset += TickAdjustment;
  162. ASSERT((LONG)KiTickOffset > 0 && KiTickOffset <= KeMaximumIncrement);
  163. KiChkTimerExpireSysDpc(SaveTickCount, KeTickCount.QuadPart);
  164. KeUpdateRunTime(TrFrame);
  165. }
  166. }
  167. VOID
  168. KeUpdateRunTime (
  169. IN PKTRAP_FRAME TrFrame
  170. )
  171. /*++
  172. Routine Description:
  173. This routine is executed on all processors in the processor complex.
  174. It's function is to update the run time of the current thread, udpate the run
  175. time for the thread's process, and decrement the current thread's quantum.
  176. Arguments:
  177. TrFrame - Supplies a pointer to a trap frame.
  178. Return Value:
  179. None.
  180. --*/
  181. {
  182. PKPRCB Prcb = KeGetCurrentPrcb();
  183. PKTHREAD Thread = KeGetCurrentThread();
  184. PKPROCESS Process = Thread->ApcState.Process;
  185. //
  186. // If thread was executing in user mode:
  187. // increment the thread user time.
  188. // atomically increment the process user time.
  189. // else If the old IRQL is greater than the DPC level:
  190. // increment the time executing interrupt service routines.
  191. // else If the old IRQL is less than the DPC level or If a DPC is not active:
  192. // increment the thread kernel time.
  193. // atomically increment the process kernel time.
  194. // else
  195. // increment time executing DPC routines.
  196. //
  197. if (TrFrame->PreviousMode != KernelMode) {
  198. ++Thread->UserTime;
  199. // Atomic Update of Process User Time required.
  200. InterlockedIncrement((PLONG)&Process->UserTime);
  201. // Update the time spent in user mode for the current processor.
  202. ++Prcb->UserTime;
  203. } else {
  204. if (TrFrame->OldIrql > DISPATCH_LEVEL) {
  205. ++Prcb->InterruptTime;
  206. } else if ((TrFrame->OldIrql < DISPATCH_LEVEL) ||
  207. (Prcb->DpcRoutineActive == 0)) {
  208. ++Thread->KernelTime;
  209. InterlockedIncrement((PLONG)&Process->KernelTime);
  210. } else {
  211. ++Prcb->DpcTime;
  212. #if 0 // DBG // Disable this until the Intel NIC is fixed.
  213. if (++Prcb->DebugDpcTime > KiDPCTimeout && KdDebuggerEnabled) {
  214. DbgPrint("\n*** DPC routine > 1 sec --- Currently at %p This is not a break in KeUpdateSystemTime\n", TrFrame->StIIP);
  215. DbgBreakPoint();
  216. Prcb->DebugDpcTime = 0;
  217. }
  218. #endif
  219. }
  220. //
  221. // Update the time spent in kernel mode for the current processor.
  222. //
  223. ++Prcb->KernelTime;
  224. }
  225. //
  226. // Update the DPC request rate which is computed as the average between the
  227. // previous rate and the current rate.
  228. // Update the DPC last count with the current DPC count.
  229. //
  230. Prcb->DpcRequestRate = ((Prcb->DpcData[DPC_NORMAL].DpcCount - Prcb->DpcLastCount) + Prcb->DpcRequestRate) >> 1;
  231. Prcb->DpcLastCount = Prcb->DpcData[DPC_NORMAL].DpcCount;
  232. //
  233. // If the DPC queue depth is not zero and a DPC routine is not active.
  234. // Request a dispatch interrupt.
  235. // Decrement the maximum DPC queue depth.
  236. // Reset the threshold counter if appropriate.
  237. //
  238. if (Prcb->DpcData[DPC_NORMAL].DpcQueueDepth != 0 && Prcb->DpcRoutineActive == 0) {
  239. Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
  240. // Need to request a DPC interrupt.
  241. KiRequestSoftwareInterrupt(DISPATCH_LEVEL);
  242. if (Prcb->DpcRequestRate < KiIdealDpcRate && Prcb->MaximumDpcQueueDepth > 1)
  243. --Prcb->MaximumDpcQueueDepth;
  244. } else {
  245. //
  246. // The DPC queue is empty or a DPC routine is active or a DPC interrupt
  247. // has been requested. Count down the adjustment threshold and if the count
  248. // reaches zero, then increment the maximum DPC queue depth but not above
  249. // the initial value. Also, reset the adjustment threshold value.
  250. //
  251. --Prcb->AdjustDpcThreshold;
  252. if (Prcb->AdjustDpcThreshold == 0) {
  253. Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold;
  254. if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth)
  255. ++Prcb->MaximumDpcQueueDepth;
  256. }
  257. }
  258. //
  259. // Decrement current thread quantum and determine if quantum end has occurred.
  260. //
  261. Thread->Quantum -= CLOCK_QUANTUM_DECREMENT;
  262. // Set quantum end if time expired, for any thread except idle thread.
  263. if (Thread->Quantum <= 0 && Thread != Prcb->IdleThread) {
  264. Prcb->QuantumEnd = 1;
  265. // Need to request a DPC interrupt.
  266. KiRequestSoftwareInterrupt(DISPATCH_LEVEL);
  267. }
  268. #ifdef _MERCED_A0_
  269. //
  270. // if SignalDone of the processor prcb is set, an IPI is to be serviced
  271. // but the corresponding IPI may have been lost on pre-B3 processors;
  272. // therefore, send another IPI to workaround this problem
  273. //
  274. if (KeGetCurrentPrcb()->SignalDone != 0) {
  275. HalRequestIpi(PCR->SetMember);
  276. }
  277. #endif // _MERCED_A0_
  278. }
  279. VOID
  280. KeProfileInterrupt (
  281. IN PKTRAP_FRAME TrFrame
  282. )
  283. /*++
  284. Routine Description:
  285. This routine is executed on all processors in the processor complex.
  286. The routine is entered as the result of an interrupt generated by the profile
  287. timer. Its function is to update the profile information for the currently
  288. active profile objects.
  289. N.B. KeProfileInterrupt is an alternate entry for backwards compatability that
  290. sets the source to zero (ProfileTime).
  291. Arguments:
  292. TrFrame - Supplies a pointer to a trap frame.
  293. Return Value:
  294. None.
  295. --*/
  296. {
  297. KPROFILE_SOURCE Source = 0;
  298. KeProfileInterruptWithSource(TrFrame, Source);
  299. return;
  300. }
  301. VOID
  302. KeProfileInterruptWithSource (
  303. IN PKTRAP_FRAME TrFrame,
  304. IN KPROFILE_SOURCE Source
  305. )
  306. /*++
  307. Routine Description:
  308. This routine is executed on all processors in the processor complex.
  309. The routine is entered as the result of an interrupt generated by the profile
  310. timer. Its function is to update the profile information for the currently
  311. active profile objects.
  312. N.B. KeProfileInterruptWithSource is not currently fully implemented by any of
  313. the architectures.
  314. Arguments:
  315. TrFrame - Supplies a pointer to a trap frame.
  316. Source - Supplies the source of the profile interrupt.
  317. Return Value:
  318. None.
  319. --*/
  320. {
  321. PKTHREAD Thread = KeGetCurrentThread();
  322. PKPROCESS Process = Thread->ApcState.Process;
  323. PERFINFO_PROFILE(TrFrame, Source);
  324. #if !defined(NT_UP)
  325. KiAcquireSpinLock(&KiProfileLock);
  326. #endif
  327. KiProcessProfileList(TrFrame, Source, &Process->ProfileListHead);
  328. KiProcessProfileList(TrFrame, Source, &KiProfileListHead);
  329. #if !defined(NT_UP)
  330. KiReleaseSpinLock(&KiProfileLock);
  331. #endif
  332. return;
  333. }
  334. VOID
  335. KiProcessProfileList (
  336. IN PKTRAP_FRAME TrFrame,
  337. IN KPROFILE_SOURCE Source,
  338. IN PLIST_ENTRY ListHead
  339. )
  340. /*++
  341. Routine Description:
  342. This routine is executed on all processors in the processor complex.
  343. The routine is entered as the result of an interrupt generated by the profile
  344. timer. Its function is to update the profile information for the currently
  345. active profile objects.
  346. N.B. KeProfileInterruptWithSource is not currently fully implemented by any of
  347. the architectures.
  348. Arguments:
  349. TrFrame - Supplies a pointer to a trap frame.
  350. Source - Supplies the source of the profile interrupt.
  351. ListHead - Supplies a pointer to a profile list.
  352. Return Value:
  353. None.
  354. --*/
  355. {
  356. PLIST_ENTRY NextEntry = ListHead->Flink;
  357. PKPRCB Prcb = KeGetCurrentPrcb();
  358. //
  359. // Scan profile list and increment profile buckets as appropriate.
  360. //
  361. for (; NextEntry != ListHead; NextEntry = NextEntry->Flink) {
  362. PCHAR BucketPter;
  363. PULONG BucketValue;
  364. PKPROFILE Profile = CONTAINING_RECORD(NextEntry, KPROFILE, ProfileListEntry);
  365. if ( (Profile->Source != Source) || ((Profile->Affinity & Prcb->SetMember) == 0) ) {
  366. continue;
  367. }
  368. if ( ((PVOID)TrFrame->StIIP < Profile->RangeBase) || ((PVOID)TrFrame->StIIP > Profile->RangeLimit) ) {
  369. continue;
  370. }
  371. BucketPter = (PCHAR)Profile->Buffer +
  372. ((((PCHAR)TrFrame->StIIP - (PCHAR)Profile->RangeBase)
  373. >> Profile->BucketShift) & 0xFFFFFFFC);
  374. BucketValue = (PULONG) BucketPter;
  375. (*BucketValue)++;
  376. }
  377. return;
  378. }