Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

clock.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Module Name: 00004 00005 clock.c 00006 00007 Abstract: 00008 00009 This module implements the platform specific clock interrupt processing 00010 routines in for the kernel. 00011 00012 Author: 00013 00014 Edward G. Chron (echron) 10-Apr-1996 00015 00016 Environment: 00017 00018 Kernel mode only. 00019 00020 Revision History: 00021 00022 --*/ 00023 00024 #include "ki.h" 00025 #include <ia64.h> 00026 #include <ntia64.h> 00027 #include <ntexapi.h> 00028 00029 VOID 00030 KiProcessProfileList ( 00031 IN PKTRAP_FRAME TrFrame, 00032 IN KPROFILE_SOURCE Source, 00033 IN PLIST_ENTRY ListHead 00034 ); 00035 00036 00037 BOOLEAN 00038 KiChkTimerExpireSysDpc ( 00039 IN ULONGLONG TickCount 00040 ) 00041 00042 /*++ 00043 00044 Routine Description: 00045 00046 This routine determines if it should attempt to place a timer expiration DPC 00047 in the system DPC list and to drive the DPC by initiating a dispatch level interrupt 00048 on the current processor. 00049 00050 N.B. If DPC is already inserted on the DPC list, we're done. 00051 00052 Arguments: 00053 00054 TickCount - The lower tick count, timer table hand value 00055 00056 Return Value: 00057 00058 BOOLEAN - Set to true if Queued DPC or if DPC already Queued. 00059 00060 --*/ 00061 00062 { 00063 BOOLEAN ret = FALSE; // No DPC queued, default return value. 00064 00065 PLIST_ENTRY ListHead = &KiTimerTableListHead[(ULONG)TickCount%TIMER_TABLE_SIZE]; 00066 PLIST_ENTRY NextEntry = ListHead->Flink; 00067 00068 // 00069 // Check to see if the list is empty. 00070 // 00071 if (NextEntry != ListHead) { 00072 PKTIMER Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); 00073 ULONGLONG TimeValue = Timer->DueTime.QuadPart; 00074 00075 // 00076 // See if timer expired. 00077 // 00078 00079 if (TimeValue <= SharedUserData->InterruptTime) { 00080 00081 PKPRCB Prcb = KeGetCurrentPrcb(); 00082 PKDPC Dpc = &KiTimerExpireDpc; 00083 00084 _disable(); 00085 #if !defined(NT_UP) 00086 KiAcquireSpinLock(&Prcb->DpcLock); 00087 #endif 00088 // 00089 // Insert DPC only if not already inserted. 00090 // 00091 if (Dpc->Lock == NULL) { 00092 00093 // 00094 // Put timer expiration DPC in the system DPC list and initiate 00095 // a dispatch interrupt on the current processor. 00096 // 00097 00098 Prcb->DpcCount += 1; 00099 Prcb->DpcQueueDepth += 1; 00100 Dpc->Lock = &Prcb->DpcLock; 00101 Dpc->SystemArgument1 = (PVOID)TickCount; 00102 Dpc->SystemArgument2 = 0; 00103 InsertTailList(&Prcb->DpcListHead, &Dpc->DpcListEntry); 00104 KiRequestSoftwareInterrupt(DISPATCH_LEVEL); 00105 } 00106 00107 ret = TRUE; 00108 00109 #if !defined(NT_UP) 00110 KiReleaseSpinLock(&Prcb->DpcLock); 00111 #endif 00112 00113 _enable(); 00114 } 00115 } 00116 00117 return(ret); 00118 } 00119 00120 00121 VOID 00122 KeUpdateSystemTime ( 00123 IN PKTRAP_FRAME TrFrame, 00124 IN ULONG Increment 00125 ) 00126 00127 /*++ 00128 00129 Routine Description: 00130 00131 This routine is executed on a single processor in the processor complex. 00132 It's function is to update the system time and to check to determine if a 00133 timer has expired. 00134 00135 N.B. This routine is executed on a single processor in a multiprocess system. 00136 The remainder of the processors in the complex execute the quantum end and 00137 runtime update code. 00138 00139 Arguments: 00140 00141 TrFrame - Supplies a pointer to a trap frame. 00142 00143 Increment - The time increment to be used to adjust the time slice for the next 00144 tick. The value is supplied in 100ns units. 00145 00146 Return Value: 00147 00148 None. 00149 00150 --*/ 00151 00152 { 00153 long SaveTickOffset; 00154 LARGE_INTEGER SystemTime; 00155 00156 SharedUserData->InterruptTime += Increment; 00157 SharedUserData->InterruptHigh2Time = (LONG)(SharedUserData->InterruptTime >> 32); 00158 KiTickOffset -= Increment; 00159 00160 SaveTickOffset = KiTickOffset; 00161 00162 if ((LONG)KiTickOffset > 0) 00163 { 00164 // 00165 // Tick has not completed (100ns time units remain). 00166 // 00167 // Determine if a timer has expired at the current hand value. 00168 // 00169 00170 KiChkTimerExpireSysDpc(KeTickCount); 00171 00172 } else { 00173 00174 // 00175 // Tick has completed, tick count set to maximum increase plus any 00176 // residue and system time is updated. 00177 // 00178 // Compute next tick offset. 00179 // 00180 00181 KiTickOffset += KeMaximumIncrement; 00182 SystemTime.HighPart = SharedUserData->SystemHigh1Time; 00183 SystemTime.LowPart = SharedUserData->SystemLowTime; 00184 SystemTime.QuadPart += KeTimeAdjustment; 00185 SharedUserData->SystemHigh1Time = SystemTime.HighPart; 00186 SharedUserData->SystemLowTime = SystemTime.LowPart; 00187 SharedUserData->SystemHigh2Time = SystemTime.HighPart; 00188 ++KeTickCount; 00189 SharedUserData->TickCountLow = (ULONG)KeTickCount; 00190 00191 // 00192 // Determine if a timer has expired at either the current hand value or 00193 // the next hand value. 00194 // 00195 00196 if (!KiChkTimerExpireSysDpc(KeTickCount - 1)) 00197 KiChkTimerExpireSysDpc(KeTickCount); 00198 00199 } 00200 00201 if (SaveTickOffset <= 0) { 00202 KeUpdateRunTime(TrFrame); 00203 } 00204 } 00205 00206 00207 VOID 00208 KeUpdateRunTime ( 00209 IN PKTRAP_FRAME TrFrame 00210 ) 00211 00212 /*++ 00213 00214 Routine Description: 00215 00216 This routine is executed on all processors in the processor complex. 00217 It's function is to update the run time of the current thread, udpate the run 00218 time for the thread's process, and decrement the current thread's quantum. 00219 00220 Arguments: 00221 00222 TrFrame - Supplies a pointer to a trap frame. 00223 00224 Return Value: 00225 00226 None. 00227 00228 --*/ 00229 00230 { 00231 KSPIN_LOCK Lock; 00232 PKPRCB Prcb = KeGetCurrentPrcb(); 00233 PKTHREAD Thread = KeGetCurrentThread(); 00234 PKPROCESS Process = Thread->ApcState.Process; 00235 00236 // 00237 // If thread was executing in user mode: 00238 // increment the thread user time. 00239 // atomically increment the process user time. 00240 // else If the old IRQL is greater than the DPC level: 00241 // increment the time executing interrupt service routines. 00242 // else If the old IRQL is less than the DPC level or If a DPC is not active: 00243 // increment the thread kernel time. 00244 // atomically increment the process kernel time. 00245 // else 00246 // increment time executing DPC routines. 00247 // 00248 00249 if (TrFrame->PreviousMode != KernelMode) { 00250 ++Thread->UserTime; 00251 00252 // Atomic Update of Process User Time required. 00253 ExInterlockedIncrementLong(&Process->UserTime, &Lock); 00254 00255 // Update the time spent in user mode for the current processor. 00256 ++Prcb->UserTime; 00257 } else { 00258 00259 if (TrFrame->OldIrql > DISPATCH_LEVEL) { 00260 ++Prcb->InterruptTime; 00261 } else if ((TrFrame->OldIrql < DISPATCH_LEVEL) || 00262 (Prcb->DpcRoutineActive == 0)) { 00263 ++Thread->KernelTime; 00264 ExInterlockedIncrementLong(&Process->KernelTime, &Lock); 00265 } else { 00266 ++Prcb->DpcTime; 00267 } 00268 00269 // 00270 // Update the time spent in kernel mode for the current processor. 00271 // 00272 00273 ++Prcb->KernelTime; 00274 } 00275 00276 // 00277 // Update the DPC request rate which is computed as the average between the 00278 // previous rate and the current rate. 00279 // Update the DPC last count with the current DPC count. 00280 // 00281 Prcb->DpcRequestRate = ((Prcb->DpcCount - Prcb->DpcLastCount) + Prcb->DpcRequestRate) >> 1; 00282 Prcb->DpcLastCount = Prcb->DpcCount; 00283 00284 // 00285 // If the DPC queue depth is not zero and a DPC routine is not active. 00286 // Request a dispatch interrupt. 00287 // Decrement the maximum DPC queue depth. 00288 // Reset the threshold counter if appropriate. 00289 // 00290 if (Prcb->DpcQueueDepth != 0 && Prcb->DpcRoutineActive == 0) { 00291 00292 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; 00293 00294 // Need to request a DPC interrupt. 00295 KiRequestSoftwareInterrupt(DISPATCH_LEVEL); 00296 00297 if (Prcb->DpcRequestRate < KiIdealDpcRate && Prcb->MaximumDpcQueueDepth > 1) 00298 --Prcb->MaximumDpcQueueDepth; 00299 } else { 00300 // 00301 // The DPC queue is empty or a DPC routine is active or a DPC interrupt 00302 // has been requested. Count down the adjustment threshold and if the count 00303 // reaches zero, then increment the maximum DPC queue depth but not above 00304 // the initial value. Also, reset the adjustment threshold value. 00305 // 00306 --Prcb->AdjustDpcThreshold; 00307 if (Prcb->AdjustDpcThreshold == 0) { 00308 Prcb->AdjustDpcThreshold = KiAdjustDpcThreshold; 00309 if (KiMaximumDpcQueueDepth != Prcb->MaximumDpcQueueDepth) 00310 ++Prcb->MaximumDpcQueueDepth; 00311 } 00312 } 00313 00314 // 00315 // Decrement current thread quantum and determine if quantum end has occurred. 00316 // 00317 Thread->Quantum -= CLOCK_QUANTUM_DECREMENT; 00318 00319 // Set quantum end if time expired, for any thread except idle thread. 00320 if (Thread->Quantum == 0 && Thread != Prcb->IdleThread) { 00321 00322 Prcb->QuantumEnd = 1; 00323 00324 // Need to request a DPC interrupt. 00325 KiRequestSoftwareInterrupt(DISPATCH_LEVEL); 00326 } 00327 00328 } 00329 00330 00331 VOID 00332 KiDecrementQuantum ( 00333 ) 00334 00335 /*++ 00336 00337 Routine Description: 00338 00339 This routine is executed on all processors in the processor complex. 00340 Decrement current thread quantum and check to determine if a quantum end 00341 has occurred. 00342 00343 Arguments: 00344 00345 None. 00346 00347 Return Value: 00348 00349 None. 00350 00351 --*/ 00352 00353 { 00354 PKTHREAD Thread = KeGetCurrentThread(); 00355 PKPRCB Prcb = KeGetCurrentPrcb(); 00356 00357 Thread->Quantum -= CLOCK_QUANTUM_DECREMENT; 00358 00359 // Set quantum end if time expired, for any thread except idle thread. 00360 if (Thread->Quantum == 0 && Thread != Prcb->IdleThread) 00361 Prcb->QuantumEnd = 1; 00362 } 00363 00364 00365 VOID 00366 KeProfileInterrupt ( 00367 IN PKTRAP_FRAME TrFrame 00368 ) 00369 /*++ 00370 00371 Routine Description: 00372 00373 This routine is executed on all processors in the processor complex. 00374 The routine is entered as the result of an interrupt generated by the profile 00375 timer. Its function is to update the profile information for the currently 00376 active profile objects. 00377 00378 N.B. KeProfileInterrupt is an alternate entry for backwards compatability that 00379 sets the source to zero (ProfileTime). 00380 00381 Arguments: 00382 00383 TrFrame - Supplies a pointer to a trap frame. 00384 00385 Return Value: 00386 00387 None. 00388 00389 --*/ 00390 00391 { 00392 KPROFILE_SOURCE Source = 0; 00393 00394 KeProfileInterruptWithSource(TrFrame, Source); 00395 00396 return; 00397 } 00398 00399 00400 VOID 00401 KeProfileInterruptWithSource ( 00402 IN PKTRAP_FRAME TrFrame, 00403 IN KPROFILE_SOURCE Source 00404 ) 00405 /*++ 00406 00407 Routine Description: 00408 00409 This routine is executed on all processors in the processor complex. 00410 The routine is entered as the result of an interrupt generated by the profile 00411 timer. Its function is to update the profile information for the currently 00412 active profile objects. 00413 00414 N.B. KeProfileInterruptWithSource is not currently fully implemented by any of 00415 the architectures. 00416 00417 Arguments: 00418 00419 TrFrame - Supplies a pointer to a trap frame. 00420 00421 Source - Supplies the source of the profile interrupt. 00422 00423 Return Value: 00424 00425 None. 00426 00427 --*/ 00428 00429 { 00430 PKTHREAD Thread = KeGetCurrentThread(); 00431 PKPROCESS Process = Thread->ApcState.Process; 00432 00433 #if !defined(NT_UP) 00434 KiAcquireSpinLock(&KiProfileLock); 00435 #endif 00436 00437 KiProcessProfileList(TrFrame, Source, &Process->ProfileListHead); 00438 00439 KiProcessProfileList(TrFrame, Source, &KiProfileListHead); 00440 00441 #if !defined(NT_UP) 00442 KiAcquireSpinLock(&KiProfileLock); 00443 #endif 00444 return; 00445 } 00446 00447 00448 VOID 00449 KiProcessProfileList ( 00450 IN PKTRAP_FRAME TrFrame, 00451 IN KPROFILE_SOURCE Source, 00452 IN PLIST_ENTRY ListHead 00453 ) 00454 /*++ 00455 00456 Routine Description: 00457 00458 This routine is executed on all processors in the processor complex. 00459 The routine is entered as the result of an interrupt generated by the profile 00460 timer. Its function is to update the profile information for the currently 00461 active profile objects. 00462 00463 N.B. KeProfileInterruptWithSource is not currently fully implemented by any of 00464 the architectures. 00465 00466 Arguments: 00467 00468 TrFrame - Supplies a pointer to a trap frame. 00469 00470 Source - Supplies the source of the profile interrupt. 00471 00472 ListHead - Supplies a pointer to a profile list. 00473 00474 Return Value: 00475 00476 None. 00477 00478 --*/ 00479 00480 { 00481 PLIST_ENTRY NextEntry = ListHead->Flink; 00482 PKPRCB Prcb = KeGetCurrentPrcb(); 00483 00484 // 00485 // Scan profile list and increment profile buckets as appropriate. 00486 // 00487 for (; NextEntry != ListHead; NextEntry = NextEntry->Flink) { 00488 00489 PCHAR BucketPter; 00490 PULONG BucketValue; 00491 00492 PKPROFILE Profile = CONTAINING_RECORD(NextEntry, KPROFILE, ProfileListEntry); 00493 00494 if (Profile->Source != Source || ((Profile->Affinity & Prcb->SetMember) == 0)) 00495 continue; 00496 00497 if ((PVOID)TrFrame->StIIP < Profile->RangeBase || (PVOID)TrFrame->StIIP > Profile->RangeLimit) 00498 continue; 00499 00500 BucketPter = (PCHAR)Profile->Buffer + 00501 ((((PCHAR)TrFrame->StIIP - (PCHAR)Profile->RangeBase) 00502 >> Profile->BucketShift) & 0xFFFFFFFC); 00503 00504 BucketValue = (PULONG) BucketPter; 00505 ++BucketValue; 00506 } 00507 00508 return; 00509 }

Generated on Sat May 15 19:39:25 2004 for test by doxygen 1.3.7