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

dpcsup.c File Reference

#include "ki.h"

Go to the source code of this file.

Classes

struct  _DPC_ENTRY

Defines

#define MAXIMUM_DPC_LIST_SIZE   16

Typedefs

typedef _DPC_ENTRY DPC_ENTRY
typedef _DPC_ENTRYPDPC_ENTRY

Functions

PRKTHREAD KiQuantumEnd (VOID)
VOID KiTimerExpiration (IN PKDPC TimerDpc, IN PVOID DeferredContext, IN PVOID SystemArgument1, IN PVOID SystemArgument2)
VOID FASTCALL KiTimerListExpire (IN PLIST_ENTRY ExpiredListHead, IN KIRQL OldIrql)


Define Documentation

#define MAXIMUM_DPC_LIST_SIZE   16
 

Definition at line 33 of file dpcsup.c.

Referenced by KiTimerListExpire().


Typedef Documentation

typedef struct _DPC_ENTRY DPC_ENTRY
 

typedef struct _DPC_ENTRY * PDPC_ENTRY
 


Function Documentation

PRKTHREAD KiQuantumEnd VOID   ) 
 

Definition at line 43 of file dpcsup.c.

References _KTHREAD::ApcState, _KTHREAD::BasePriority, _KPROCESS::DisableQuantum, FALSE, KeGetCurrentPrcb, KeGetCurrentThread, KiFindReadyThread(), KiLockDispatcherDatabase, KiSetPriorityThread(), KiUnlockDispatcherDatabase(), _KTHREAD::NextProcessor, NULL, _KTHREAD::Preempted, _KTHREAD::Priority, _KTHREAD::PriorityDecrement, _KAPC_STATE::Process, _KTHREAD::Quantum, Standby, _KTHREAD::State, and _KPROCESS::ThreadQuantum.

00049 : 00050 00051 This function is called when a quantum end event occurs on the current 00052 processor. Its function is to determine whether the thread priority should 00053 be decremented and whether a redispatch of the processor should occur. 00054 00055 Arguments: 00056 00057 None. 00058 00059 Return Value: 00060 00061 The next thread to be schedule on the current processor is returned as 00062 the function value. If this value is not NULL, then the return is with 00063 the dispatcher database locked. Otherwise, the dispatcher database is 00064 unlocked. 00065 00066 --*/ 00067 00068 { 00069 00070 KPRIORITY NewPriority; 00071 KIRQL OldIrql; 00072 PKPRCB Prcb; 00073 KPRIORITY Priority; 00074 PKPROCESS Process; 00075 PRKTHREAD Thread; 00076 PRKTHREAD NextThread; 00077 00078 // 00079 // Acquire the dispatcher database lock. 00080 // 00081 00082 Prcb = KeGetCurrentPrcb(); 00083 Thread = KeGetCurrentThread(); 00084 KiLockDispatcherDatabase(&OldIrql); 00085 00086 // 00087 // If the quantum has expired for the current thread, then update its 00088 // quantum and priority. 00089 // 00090 00091 if (Thread->Quantum <= 0) { 00092 00093 // 00094 // If quantum runout is disabled for the thread's process and 00095 // the thread is running at a realtime priority, then set the 00096 // thread quantum to the highest value and do not round robin 00097 // at the thread's priority level. Otherwise, reset the thread 00098 // quantum and decay the thread's priority as appropriate. 00099 // 00100 00101 Process = Thread->ApcState.Process; 00102 if ((Process->DisableQuantum != FALSE) && 00103 (Thread->Priority >= LOW_REALTIME_PRIORITY)) { 00104 Thread->Quantum = MAXCHAR; 00105 00106 } else { 00107 Thread->Quantum = Process->ThreadQuantum; 00108 00109 // 00110 // Decrement the thread's current priority if the thread is not 00111 // running in a realtime priority class and check to determine 00112 // if the processor should be redispatched. 00113 // 00114 00115 Priority = Thread->Priority; 00116 if (Priority < LOW_REALTIME_PRIORITY) { 00117 NewPriority = Priority - Thread->PriorityDecrement - 1; 00118 if (NewPriority < Thread->BasePriority) { 00119 NewPriority = Thread->BasePriority; 00120 } 00121 00122 Thread->PriorityDecrement = 0; 00123 00124 } else { 00125 NewPriority = Priority; 00126 } 00127 00128 // 00129 // If the new thread priority is different that the current thread 00130 // priority, then the thread does not run at a realtime level and 00131 // its priority should be set. Otherwise, attempt to round robin 00132 // at the current level. 00133 // 00134 00135 if (Priority != NewPriority) { 00136 KiSetPriorityThread(Thread, NewPriority); 00137 00138 } else { 00139 if (Prcb->NextThread == NULL) { 00140 NextThread = KiFindReadyThread(Thread->NextProcessor, Priority); 00141 00142 if (NextThread != NULL) { 00143 NextThread->State = Standby; 00144 Prcb->NextThread = NextThread; 00145 } 00146 00147 } else { 00148 Thread->Preempted = FALSE; 00149 } 00150 } 00151 } 00152 } 00153 00154 // 00155 // If a thread was scheduled for execution on the current processor, 00156 // then return the address of the thread with the dispatcher database 00157 // locked. Otherwise, return NULL with the dispatcher data unlocked. 00158 // 00159 00160 NextThread = Prcb->NextThread; 00161 if (NextThread == NULL) { 00162 KiUnlockDispatcherDatabase(OldIrql); 00163 } 00164 00165 return NextThread; 00166 }

VOID KiTimerExpiration IN PKDPC  TimerDpc,
IN PVOID  DeferredContext,
IN PVOID  SystemArgument1,
IN PVOID  SystemArgument2
 

Definition at line 217 of file dpcsup.c.

References _KTIMER::DueTime, Index, KeNumberProcessors, KiLockDispatcherDatabase, KiTimerListExpire(), KiTimerTableListHead, TIMER_TABLE_SIZE, and _KTIMER::TimerListEntry.

Referenced by KiInitSystem().

00226 : 00227 00228 This function is called when the clock interupt routine discovers that 00229 a timer has expired. 00230 00231 Arguments: 00232 00233 TimerDpc - Supplies a pointer to a control object of type DPC. 00234 00235 DeferredContext - Not used. 00236 00237 SystemArgument1 - Supplies the starting timer table index value to 00238 use for the timer table scan. 00239 00240 SystemArgument2 - Not used. 00241 00242 Return Value: 00243 00244 None. 00245 00246 --*/ 00247 00248 { 00249 ULARGE_INTEGER CurrentTime; 00250 LIST_ENTRY ExpiredListHead; 00251 LONG HandLimit; 00252 LONG Index; 00253 PLIST_ENTRY ListHead; 00254 PLIST_ENTRY NextEntry; 00255 KIRQL OldIrql; 00256 PKTIMER Timer; 00257 00258 // 00259 // Acquire the dispatcher database lock and read the current interrupt 00260 // time to determine which timers have expired. 00261 // 00262 00263 KiLockDispatcherDatabase(&OldIrql); 00264 KiQueryInterruptTime((PLARGE_INTEGER)&CurrentTime); 00265 00266 // 00267 // If the timer table has not wrapped, then start with the specified 00268 // timer table index value, and scan for timer entries that have expired. 00269 // Otherwise, start with the first entry in the timer table and scan the 00270 // entire table for timer entries that have expired. 00271 // 00272 // N.B. This later condition exists when DPC processing is blocked for a 00273 // period longer than one round trip throught the timer table. 00274 // 00275 00276 HandLimit = (LONG)KiQueryLowTickCount(); 00277 if (((ULONG)(HandLimit - PtrToLong(SystemArgument1))) >= TIMER_TABLE_SIZE) { 00278 Index = - 1; 00279 HandLimit = TIMER_TABLE_SIZE - 1; 00280 00281 } else { 00282 Index = (PtrToLong(SystemArgument1) - 1) & (TIMER_TABLE_SIZE - 1); 00283 HandLimit &= (TIMER_TABLE_SIZE - 1); 00284 } 00285 00286 InitializeListHead(&ExpiredListHead); 00287 do { 00288 Index = (Index + 1) & (TIMER_TABLE_SIZE - 1); 00289 ListHead = &KiTimerTableListHead[Index]; 00290 NextEntry = ListHead->Flink; 00291 while (NextEntry != ListHead) { 00292 Timer = CONTAINING_RECORD(NextEntry, KTIMER, TimerListEntry); 00293 if (Timer->DueTime.QuadPart <= CurrentTime.QuadPart) { 00294 00295 // 00296 // The next timer in the current timer list has expired. 00297 // Remove the entry from the timer list and insert the 00298 // timer in the expired list. 00299 // 00300 00301 RemoveEntryList(&Timer->TimerListEntry); 00302 InsertTailList(&ExpiredListHead, &Timer->TimerListEntry); 00303 NextEntry = ListHead->Flink; 00304 00305 } else { 00306 break; 00307 } 00308 } 00309 00310 } while(Index != HandLimit); 00311 00312 #if DBG 00313 00314 if ((PtrToUlong(SystemArgument2) == 0) && (KeNumberProcessors == 1)) { 00315 KiCheckTimerTable(CurrentTime); 00316 } 00317 00318 #endif 00319 00320 // 00321 // Process the expired timer list. 00322 // 00323 // N.B. The following function returns with the dispatcher database 00324 // unlocked. 00325 // 00326 00327 KiTimerListExpire(&ExpiredListHead, OldIrql); 00328 return; 00329 }

VOID FASTCALL KiTimerListExpire IN PLIST_ENTRY  ExpiredListHead,
IN KIRQL  OldIrql
 

Definition at line 333 of file dpcsup.c.

References _DPC_ENTRY::Context, Count, _KDPC::DeferredContext, _KDPC::DeferredRoutine, DISPATCH_LEVEL, _KTIMER::Dpc, _DPC_ENTRY::Dpc, FALSE, _KTIMER::Header, Index, KeGetCurrentPrcb, KeInsertQueueDpc(), KeLowerIrql(), KiInsertTreeTimer(), KiLockDispatcherDatabase, KiRemoveTreeTimer, KiUnlockDispatcherDatabase(), KiWaitTest(), MAXIMUM_DPC_LIST_SIZE, MAXIMUM_PROCESSORS, NULL, _KDPC::Number, _KTIMER::Period, _DPC_ENTRY::Routine, _DISPATCHER_HEADER::SignalState, TIMER_EXPIRE_INCREMENT, and _DISPATCHER_HEADER::WaitListHead.

Referenced by KeSetSystemTime(), and KiTimerExpiration().

00340 : 00341 00342 This function is called to process a list of timers that have expired. 00343 00344 N.B. This function is called with the dispatcher database locked and 00345 returns with the dispatcher database unlocked. 00346 00347 Arguments: 00348 00349 ExpiredListHead - Supplies a pointer to a list of timers that have 00350 expired. 00351 00352 OldIrql - Supplies the previous IRQL. 00353 00354 Return Value: 00355 00356 None. 00357 00358 --*/ 00359 00360 { 00361 00362 LONG Count; 00363 PKDPC Dpc; 00364 DPC_ENTRY DpcList[MAXIMUM_DPC_LIST_SIZE]; 00365 LONG Index; 00366 LARGE_INTEGER Interval; 00367 KIRQL OldIrql1; 00368 LARGE_INTEGER SystemTime; 00369 PKTIMER Timer; 00370 00371 // 00372 // Capture the timer expiration time. 00373 // 00374 00375 KiQuerySystemTime(&SystemTime); 00376 00377 // 00378 // Remove the next timer from the expired timer list, set the state of 00379 // the timer to signaled, reinsert the timer in the timer tree if it is 00380 // periodic, and optionally call the DPC routine if one is specified. 00381 // 00382 00383 RestartScan: 00384 Count = 0; 00385 while (ExpiredListHead->Flink != ExpiredListHead) { 00386 Timer = CONTAINING_RECORD(ExpiredListHead->Flink, KTIMER, TimerListEntry); 00387 KiRemoveTreeTimer(Timer); 00388 Timer->Header.SignalState = 1; 00389 if (IsListEmpty(&Timer->Header.WaitListHead) == FALSE) { 00390 KiWaitTest(Timer, TIMER_EXPIRE_INCREMENT); 00391 } 00392 00393 // 00394 // If the timer is periodic, then compute the next interval time 00395 // and reinsert the timer in the timer tree. 00396 // 00397 // N.B. Even though the timer insertion is relative, it can still 00398 // fail if the period of the timer elapses in between computing 00399 // the time and inserting the timer in the table. If this happens, 00400 // try again. 00401 // 00402 if (Timer->Period != 0) { 00403 Interval.QuadPart = Int32x32To64(Timer->Period, - 10 * 1000); 00404 while (!KiInsertTreeTimer(Timer, Interval)) { 00405 ; 00406 } 00407 } 00408 00409 if (Timer->Dpc != NULL) { 00410 Dpc = Timer->Dpc; 00411 00412 // 00413 // If the DPC is explicitly targeted to another processor, then 00414 // queue the DPC to the target processor. Otherwise, capture the 00415 // DPC parameters for execution on the current processor. 00416 // 00417 00418 #if defined(NT_UP) 00419 00420 DpcList[Count].Dpc = Dpc; 00421 DpcList[Count].Routine = Dpc->DeferredRoutine; 00422 DpcList[Count].Context = Dpc->DeferredContext; 00423 Count += 1; 00424 if (Count == MAXIMUM_DPC_LIST_SIZE) { 00425 break; 00426 } 00427 00428 #else 00429 00430 if ((Dpc->Number >= MAXIMUM_PROCESSORS) && 00431 (((ULONG)Dpc->Number - MAXIMUM_PROCESSORS) != (ULONG)KeGetCurrentProcessorNumber())) { 00432 KeInsertQueueDpc(Dpc, 00433 ULongToPtr(SystemTime.LowPart), 00434 ULongToPtr(SystemTime.HighPart)); 00435 00436 } else { 00437 DpcList[Count].Dpc = Dpc; 00438 DpcList[Count].Routine = Dpc->DeferredRoutine; 00439 DpcList[Count].Context = Dpc->DeferredContext; 00440 Count += 1; 00441 if (Count == MAXIMUM_DPC_LIST_SIZE) { 00442 break; 00443 } 00444 } 00445 00446 #endif 00447 00448 } 00449 } 00450 00451 // 00452 // Unlock the dispacher database and process DPC list entries. 00453 // 00454 00455 if (Count != 0) { 00456 KiUnlockDispatcherDatabase(DISPATCH_LEVEL); 00457 Index = 0; 00458 do { 00459 00460 #if DBG && (defined(i386) || defined(ALPHA)) 00461 00462 // 00463 // Reset the dpc tick count. If the tick count handler, 00464 // which increments this value, detects that it has crossed 00465 // a certain threshold, a breakpoint will be generated. 00466 // 00467 00468 KeGetCurrentPrcb()->DebugDpcTime = 0; 00469 #endif 00470 00471 (DpcList[Index].Routine)(DpcList[Index].Dpc, 00472 DpcList[Index].Context, 00473 ULongToPtr(SystemTime.LowPart), 00474 ULongToPtr(SystemTime.HighPart)); 00475 00476 00477 Index += 1; 00478 } while (Index < Count); 00479 00480 // 00481 // If processing of the expired timer list was terminated because 00482 // the DPC List was full, then process any remaining entries. 00483 // 00484 00485 if (Count == MAXIMUM_DPC_LIST_SIZE) { 00486 KiLockDispatcherDatabase(&OldIrql1); 00487 goto RestartScan; 00488 } 00489 00490 KeLowerIrql(OldIrql); 00491 00492 } else { 00493 KiUnlockDispatcherDatabase(OldIrql); 00494 } 00495 00496 return; 00497 } }


Generated on Sat May 15 19:43:29 2004 for test by doxygen 1.3.7