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

balmgr.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1991-1994 Microsoft Corporation 00004 00005 Module Name: 00006 00007 balmgr.c 00008 00009 Abstract: 00010 00011 This module implements the NT balance set manager. Normally the kernel 00012 does not contain "policy" code. However, the balance set manager needs 00013 to be able to traverse the kernel data structures and, therefore, the 00014 code has been located as logically part of the kernel. 00015 00016 The balance set manager performs the following operations: 00017 00018 1. Makes the kernel stack of threads that have been waiting for a 00019 certain amount of time, nonresident. 00020 00021 2. Removes processes from the balance set when memory gets tight 00022 and brings processes back into the balance set when there is 00023 more memory available. 00024 00025 3. Makes the kernel stack resident for threads whose wait has been 00026 completed, but whose stack is nonresident. 00027 00028 4. Arbitrarily boosts the priority of a selected set of threads 00029 to prevent priority inversion in variable priority levels. 00030 00031 In general, the balance set manager only is active during periods when 00032 memory is tight. 00033 00034 Author: 00035 00036 David N. Cutler (davec) 13-Jul-1991 00037 00038 Environment: 00039 00040 Kernel mode only. 00041 00042 Revision History: 00043 00044 --*/ 00045 00046 #include "ki.h" 00047 00048 // 00049 // Define balance set wait object types. 00050 // 00051 00052 typedef enum _BALANCE_OBJECT { 00053 TimerExpiration, 00054 WorkingSetManagerEvent, 00055 MaximumObject 00056 } BALANCE_OBJECT; 00057 00058 // 00059 // Define maximum number of thread stacks that can be out swapped in 00060 // a single time period. 00061 // 00062 00063 #define MAXIMUM_THREAD_STACKS 20 00064 00065 // 00066 // Define periodic wait interval value. 00067 // 00068 00069 #define PERIODIC_INTERVAL (1 * 1000 * 1000 * 10) 00070 00071 // 00072 // Define amount of time a thread can be in the ready state without having 00073 // is priority boosted (approximately 4 seconds). 00074 // 00075 00076 #define READY_WITHOUT_RUNNING (4 * 75) 00077 00078 // 00079 // Define kernel stack protect time. For small systems the protect time 00080 // is 3 seconds. For all other systems, the protect time is 7 seconds. 00081 // 00082 00083 #define SMALL_SYSTEM_STACK_PROTECT_TIME (3 * 75) 00084 #define STACK_PROTECT_TIME (7 * 75) 00085 #define STACK_SCAN_PERIOD 4 00086 ULONG KiStackProtectTime; 00087 00088 // 00089 // Define number of threads to scan each period and the priority boost bias. 00090 // 00091 00092 #define THREAD_BOOST_BIAS 1 00093 #define THREAD_BOOST_PRIORITY (LOW_REALTIME_PRIORITY - THREAD_BOOST_BIAS) 00094 #define THREAD_SCAN_PRIORITY (THREAD_BOOST_PRIORITY - 1) 00095 #define THREAD_READY_COUNT 10 00096 #define THREAD_SCAN_COUNT 16 00097 00098 #define EXECUTION_TIME_LIMITS_PERIOD 7 00099 00100 // 00101 // Define local procedure prototypes. 00102 // 00103 00104 VOID 00105 KiInSwapKernelStacks ( 00106 IN KIRQL PreviousIrql 00107 ); 00108 00109 VOID 00110 KiInSwapProcesses ( 00111 IN KIRQL PreviousIrql 00112 ); 00113 00114 VOID 00115 KiOutSwapKernelStacks ( 00116 IN KIRQL PreviousIrql 00117 ); 00118 00119 VOID 00120 KiOutSwapProcesses ( 00121 IN KIRQL PreviousIrql 00122 ); 00123 00124 VOID 00125 KiScanReadyQueues ( 00126 VOID 00127 ); 00128 00129 // 00130 // Define thread table index static data. 00131 // 00132 00133 ULONG KiReadyQueueIndex = 1; 00134 00135 // 00136 // Define swap request flag. 00137 // 00138 00139 BOOLEAN KiStackOutSwapRequest = FALSE; 00140 00141 VOID 00142 KeBalanceSetManager ( 00143 IN PVOID Context 00144 ) 00145 00146 /*++ 00147 00148 Routine Description: 00149 00150 This function is the startup code for the balance set manager. The 00151 balance set manager thread is created during system initialization 00152 and begins execution in this function. 00153 00154 Arguments: 00155 00156 Context - Supplies a pointer to an arbitrary data structure (NULL). 00157 00158 Return Value: 00159 00160 None. 00161 00162 --*/ 00163 00164 { 00165 00166 LARGE_INTEGER DueTime; 00167 KTIMER PeriodTimer; 00168 KIRQL OldIrql; 00169 ULONG StackScanPeriod; 00170 ULONG ExecutionTimeLimitPeriod; 00171 NTSTATUS Status; 00172 KWAIT_BLOCK WaitBlockArray[MaximumObject]; 00173 PVOID WaitObjects[MaximumObject]; 00174 00175 // 00176 // Raise the thread priority to the lowest realtime level. 00177 // 00178 00179 KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY); 00180 00181 // 00182 // Initialize the periodic timer, set it to expire one period from 00183 // now, and set the stack scan period. 00184 // 00185 00186 KeInitializeTimer(&PeriodTimer); 00187 DueTime.QuadPart = - PERIODIC_INTERVAL; 00188 KeSetTimer(&PeriodTimer, DueTime, NULL); 00189 StackScanPeriod = STACK_SCAN_PERIOD; 00190 ExecutionTimeLimitPeriod = EXECUTION_TIME_LIMITS_PERIOD; 00191 // 00192 // Compute the stack protect time based on the system size. 00193 // 00194 00195 if (MmQuerySystemSize() == MmSmallSystem) { 00196 KiStackProtectTime = SMALL_SYSTEM_STACK_PROTECT_TIME; 00197 00198 } else { 00199 KiStackProtectTime = STACK_PROTECT_TIME; 00200 } 00201 00202 // 00203 // Initialize the wait objects array. 00204 // 00205 00206 WaitObjects[TimerExpiration] = (PVOID)&PeriodTimer; 00207 WaitObjects[WorkingSetManagerEvent] = (PVOID)&MmWorkingSetManagerEvent; 00208 00209 // 00210 // Loop forever processing balance set manager events. 00211 // 00212 00213 do { 00214 00215 // 00216 // Wait for a memory management memory low event, a swap event, 00217 // or the expiration of the period timout rate that the balance 00218 // set manager runs at. 00219 // 00220 00221 Status = KeWaitForMultipleObjects(MaximumObject, 00222 &WaitObjects[0], 00223 WaitAny, 00224 Executive, 00225 KernelMode, 00226 FALSE, 00227 NULL, 00228 &WaitBlockArray[0]); 00229 00230 // 00231 // Switch on the wait status. 00232 // 00233 00234 switch (Status) { 00235 00236 // 00237 // Periodic timer expiration. 00238 // 00239 00240 case TimerExpiration: 00241 00242 // 00243 // Attempt to initiate outswaping of kernel stacks. 00244 // 00245 00246 StackScanPeriod -= 1; 00247 if (StackScanPeriod == 0) { 00248 StackScanPeriod = STACK_SCAN_PERIOD; 00249 KiLockDispatcherDatabase(&OldIrql); 00250 if (KiStackOutSwapRequest == FALSE) { 00251 KiStackOutSwapRequest = TRUE; 00252 KiUnlockDispatcherDatabase(OldIrql); 00253 KeSetEvent(&KiSwapEvent, 0, FALSE); 00254 00255 } else { 00256 KiUnlockDispatcherDatabase(OldIrql); 00257 } 00258 } 00259 00260 // 00261 // Adjust the depth of lookaside lists. 00262 // 00263 00264 ExAdjustLookasideDepth(); 00265 00266 // 00267 // Scan ready queues and boost thread priorities as appropriate. 00268 // 00269 00270 KiScanReadyQueues(); 00271 00272 // 00273 // Execute the virtual memory working set manager. 00274 // 00275 00276 MmWorkingSetManager(); 00277 00278 // 00279 // Enforce execution time limits 00280 // 00281 00282 ExecutionTimeLimitPeriod -= 1; 00283 if (ExecutionTimeLimitPeriod == 0) { 00284 ExecutionTimeLimitPeriod = EXECUTION_TIME_LIMITS_PERIOD; 00285 PsEnforceExecutionTimeLimits(); 00286 } 00287 00288 // 00289 // Set the timer to expire at the next periodic interval. 00290 // 00291 00292 KeSetTimer(&PeriodTimer, DueTime, NULL); 00293 break; 00294 00295 // 00296 // Working set manager event. 00297 // 00298 00299 case WorkingSetManagerEvent: 00300 00301 // 00302 // Call the working set manager to trim working sets. 00303 // 00304 00305 MmWorkingSetManager(); 00306 break; 00307 00308 // 00309 // Illegal return status. 00310 // 00311 00312 default: 00313 KdPrint(("BALMGR: Illegal wait status, %lx =\n", Status)); 00314 break; 00315 } 00316 00317 } while (TRUE); 00318 return; 00319 } 00320 00321 VOID 00322 KeSwapProcessOrStack ( 00323 IN PVOID Context 00324 ) 00325 00326 /*++ 00327 00328 Routine Description: 00329 00330 This thread controls the swapping of processes and kernel stacks. The 00331 order of evaluation is: 00332 00333 Outswap kernel stacks 00334 Outswap processes 00335 Inswap processes 00336 Inswap kernel stacks 00337 00338 Arguments: 00339 00340 Context - Supplies a pointer to the routine context - not used. 00341 00342 Return Value: 00343 00344 None. 00345 00346 --*/ 00347 00348 { 00349 00350 KIRQL OldIrql; 00351 NTSTATUS Status; 00352 00353 // 00354 // Raise the thread priority to the lowest realtime level + 7 (i.e., 00355 // priority 23). 00356 // 00357 00358 KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY + 7); 00359 00360 // 00361 // Loop for ever processing swap events. 00362 // 00363 00364 do { 00365 00366 // 00367 // Wait for a swap event to occur. 00368 // 00369 00370 Status = KeWaitForSingleObject(&KiSwapEvent, 00371 Executive, 00372 KernelMode, 00373 FALSE, 00374 NULL); 00375 00376 // 00377 // Raise IRQL to dispatcher level and lock dispatcher database. 00378 // 00379 00380 KiLockDispatcherDatabase(&OldIrql); 00381 00382 // 00383 // Loop until all of the four possible actions cannot be initiated. 00384 // 00385 00386 do { 00387 00388 // 00389 // If a request has been made to out swap kernel stacks, then 00390 // attempt to outswap kernel stacks. Otherwise, if the process 00391 // out swap list is not empty, then initiate process outswapping. 00392 // Otherwise, if the process inswap list is not empty, then start 00393 // process inswapping. Otherwise, if the kernal stack inswap list 00394 // is not active, then initiate kernel stack inswapping. Otherwise, 00395 // no work is available. 00396 // 00397 00398 if (KiStackOutSwapRequest != FALSE) { 00399 KiStackOutSwapRequest = FALSE; 00400 KiOutSwapKernelStacks(OldIrql); 00401 continue; 00402 00403 } else if (IsListEmpty(&KiProcessOutSwapListHead) == FALSE) { 00404 KiOutSwapProcesses(OldIrql); 00405 continue; 00406 00407 } else if (IsListEmpty(&KiProcessInSwapListHead) == FALSE) { 00408 KiInSwapProcesses(OldIrql); 00409 continue; 00410 00411 } else if (IsListEmpty(&KiStackInSwapListHead) == FALSE) { 00412 KiInSwapKernelStacks(OldIrql); 00413 continue; 00414 00415 } else { 00416 break; 00417 } 00418 } while (TRUE); 00419 00420 // 00421 // Unlock the dispatcher database and lower IRQL to its previous 00422 // value. 00423 // 00424 00425 KiUnlockDispatcherDatabase(OldIrql); 00426 } while (TRUE); 00427 return; 00428 } 00429 00430 VOID 00431 KiInSwapKernelStacks ( 00432 IN KIRQL PreviousIrql 00433 ) 00434 00435 /*++ 00436 00437 Routine Description: 00438 00439 This function in swaps the kernel stack for threads whose wait has been 00440 completed and whose kernel stack is nonresident. 00441 00442 N.B. The dispatcher data lock is held on entry to this routine and must 00443 be help on exit to this routine. 00444 00445 Arguments: 00446 00447 PreviousIrql - Supplies the previous IRQL. 00448 00449 Return Value: 00450 00451 None. 00452 00453 --*/ 00454 00455 { 00456 00457 PLIST_ENTRY NextEntry; 00458 KIRQL OldIrql; 00459 PKTHREAD Thread; 00460 00461 // 00462 // Process the stack in swap list and for each thread removed from the 00463 // list, make its kernel stack resident, and ready it for execution. 00464 // 00465 00466 OldIrql = PreviousIrql; 00467 NextEntry = KiStackInSwapListHead.Flink; 00468 while (NextEntry != &KiStackInSwapListHead) { 00469 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry); 00470 RemoveEntryList(NextEntry); 00471 KiUnlockDispatcherDatabase(OldIrql); 00472 MmInPageKernelStack(Thread); 00473 KiLockDispatcherDatabase(&OldIrql); 00474 Thread->KernelStackResident = TRUE; 00475 KiReadyThread(Thread); 00476 NextEntry = KiStackInSwapListHead.Flink; 00477 } 00478 00479 return; 00480 } 00481 00482 VOID 00483 KiInSwapProcesses ( 00484 IN KIRQL PreviousIrql 00485 ) 00486 00487 /*++ 00488 00489 Routine Description: 00490 00491 This function in swaps processes. 00492 00493 N.B. The dispatcher data lock is held on entry to this routine and must 00494 be help on exit to this routine. 00495 00496 Arguments: 00497 00498 PreviousIrql - Supplies the previous IRQL. 00499 00500 Return Value: 00501 00502 None. 00503 00504 --*/ 00505 00506 { 00507 00508 PLIST_ENTRY NextEntry; 00509 KIRQL OldIrql; 00510 PKPROCESS Process; 00511 PKTHREAD Thread; 00512 00513 // 00514 // Process the process in swap list and for each process removed from 00515 // the list, make the process resident, and process its ready list. 00516 // 00517 00518 OldIrql = PreviousIrql; 00519 NextEntry = KiProcessInSwapListHead.Flink; 00520 while (NextEntry != &KiProcessInSwapListHead) { 00521 Process = CONTAINING_RECORD(NextEntry, KPROCESS, SwapListEntry); 00522 RemoveEntryList(NextEntry); 00523 Process->State = ProcessInSwap; 00524 KiUnlockDispatcherDatabase(OldIrql); 00525 MmInSwapProcess(Process); 00526 KiLockDispatcherDatabase(&OldIrql); 00527 Process->State = ProcessInMemory; 00528 NextEntry = Process->ReadyListHead.Flink; 00529 while (NextEntry != &Process->ReadyListHead) { 00530 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry); 00531 RemoveEntryList(NextEntry); 00532 Thread->ProcessReadyQueue = FALSE; 00533 KiReadyThread(Thread); 00534 NextEntry = Process->ReadyListHead.Flink; 00535 } 00536 00537 NextEntry = KiProcessInSwapListHead.Flink; 00538 } 00539 00540 return; 00541 } 00542 00543 VOID 00544 KiOutSwapKernelStacks ( 00545 IN KIRQL PreviousIrql 00546 ) 00547 00548 /*++ 00549 00550 Routine Description: 00551 00552 This function attempts to out swap the kernel stack for threads whose 00553 wait mode is user and which have been waiting longer than the stack 00554 protect time. 00555 00556 N.B. The dispatcher data lock is held on entry to this routine and must 00557 be help on exit to this routine. 00558 00559 Arguments: 00560 00561 PreviousIrql - Supplies the previous IRQL. 00562 00563 Return Value: 00564 00565 None. 00566 00567 --*/ 00568 00569 { 00570 00571 ULONG CurrentTick; 00572 PLIST_ENTRY NextEntry; 00573 ULONG NumberOfThreads; 00574 KIRQL OldIrql; 00575 PKPROCESS Process; 00576 PKTHREAD Thread; 00577 PKTHREAD ThreadObjects[MAXIMUM_THREAD_STACKS]; 00578 ULONG WaitTime; 00579 00580 // 00581 // Scan the waiting in list and check if the wait time exceeds the 00582 // stack protect time. If the protect time is exceeded, then make 00583 // the kernel stack of the waiting thread nonresident. If the count 00584 // of the number of stacks that are resident for the process reaches 00585 // zero, then insert the process in the outswap list and set its state 00586 // to transition. 00587 // 00588 00589 CurrentTick = KiQueryLowTickCount(); 00590 OldIrql = PreviousIrql; 00591 NextEntry = KiWaitInListHead.Flink; 00592 NumberOfThreads = 0; 00593 while ((NextEntry != &KiWaitInListHead) && 00594 (NumberOfThreads < MAXIMUM_THREAD_STACKS)) { 00595 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry); 00596 00597 ASSERT(Thread->WaitMode == UserMode); 00598 00599 NextEntry = NextEntry->Flink; 00600 WaitTime = CurrentTick - Thread->WaitTime; 00601 if ((WaitTime >= KiStackProtectTime) && 00602 KiIsThreadNumericStateSaved(Thread)) { 00603 Thread->KernelStackResident = FALSE; 00604 ThreadObjects[NumberOfThreads] = Thread; 00605 NumberOfThreads += 1; 00606 RemoveEntryList(&Thread->WaitListEntry); 00607 InsertTailList(&KiWaitOutListHead, &Thread->WaitListEntry); 00608 Process = Thread->ApcState.Process; 00609 Process->StackCount -= 1; 00610 if (Process->StackCount == 0) { 00611 Process->State = ProcessInTransition; 00612 InsertTailList(&KiProcessOutSwapListHead, 00613 &Process->SwapListEntry); 00614 } 00615 } 00616 } 00617 00618 // 00619 // Unlock the dispatcher database and lower IRQL to its previous 00620 // value. 00621 // 00622 00623 KiUnlockDispatcherDatabase(OldIrql); 00624 00625 // 00626 // Out swap the kernels stack for the selected set of threads. 00627 // 00628 00629 while (NumberOfThreads > 0) { 00630 NumberOfThreads -= 1; 00631 Thread = ThreadObjects[NumberOfThreads]; 00632 MmOutPageKernelStack(Thread); 00633 } 00634 00635 // 00636 // Raise IRQL to dispatcher level and lock dispatcher database. 00637 // 00638 00639 KiLockDispatcherDatabase(&OldIrql); 00640 return; 00641 } 00642 00643 VOID 00644 KiOutSwapProcesses ( 00645 IN KIRQL PreviousIrql 00646 ) 00647 00648 /*++ 00649 00650 Routine Description: 00651 00652 This function out swaps processes. 00653 00654 N.B. The dispatcher data lock is held on entry to this routine and must 00655 be help on exit to this routine. 00656 00657 Arguments: 00658 00659 PreviousIrql - Supplies the previous IRQL. 00660 00661 Return Value: 00662 00663 None. 00664 00665 --*/ 00666 00667 { 00668 00669 PLIST_ENTRY NextEntry; 00670 KIRQL OldIrql; 00671 PKPROCESS Process; 00672 PKTHREAD Thread; 00673 00674 // 00675 // Process the process out swap list and for each process removed from 00676 // the list, make the process nonresident, and process its ready list. 00677 // 00678 00679 OldIrql = PreviousIrql; 00680 NextEntry = KiProcessOutSwapListHead.Flink; 00681 while (NextEntry != &KiProcessOutSwapListHead) { 00682 Process = CONTAINING_RECORD(NextEntry, KPROCESS, SwapListEntry); 00683 RemoveEntryList(NextEntry); 00684 00685 // 00686 // If there are any threads in the process ready list, then don't 00687 // out swap the process and ready all threads in the process ready 00688 // list. Otherwsie, out swap the process. 00689 // 00690 00691 NextEntry = Process->ReadyListHead.Flink; 00692 if (NextEntry != &Process->ReadyListHead) { 00693 Process->State = ProcessInMemory; 00694 while (NextEntry != &Process->ReadyListHead) { 00695 Thread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry); 00696 RemoveEntryList(NextEntry); 00697 Thread->ProcessReadyQueue = FALSE; 00698 KiReadyThread(Thread); 00699 NextEntry = Process->ReadyListHead.Flink; 00700 } 00701 00702 } else { 00703 Process->State = ProcessOutSwap; 00704 KiUnlockDispatcherDatabase(OldIrql); 00705 MmOutSwapProcess(Process); 00706 KiLockDispatcherDatabase(&OldIrql); 00707 00708 // 00709 // While the process was being outswapped there may have been one 00710 // or more threads that attached to the process. If the process 00711 // ready list is not empty, then in swap the process. Otherwise, 00712 // mark the process as out of memory. 00713 // 00714 00715 NextEntry = Process->ReadyListHead.Flink; 00716 if (NextEntry != &Process->ReadyListHead) { 00717 Process->State = ProcessInTransition; 00718 InsertTailList(&KiProcessInSwapListHead, &Process->SwapListEntry); 00719 00720 } else { 00721 Process->State = ProcessOutOfMemory; 00722 } 00723 } 00724 00725 NextEntry = KiProcessOutSwapListHead.Flink; 00726 } 00727 00728 return; 00729 } 00730 00731 VOID 00732 KiScanReadyQueues ( 00733 VOID 00734 ) 00735 00736 /*++ 00737 00738 Routine Description: 00739 00740 This function scans a section of the ready queues and attempts to 00741 boost the priority of threads that run at variable priority levels. 00742 00743 Arguments: 00744 00745 None. 00746 00747 Return Value: 00748 00749 None. 00750 00751 --*/ 00752 00753 { 00754 00755 ULONG Count = 0; 00756 ULONG CurrentTick; 00757 PLIST_ENTRY Entry; 00758 ULONG Index; 00759 PLIST_ENTRY ListHead; 00760 ULONG Number = 0; 00761 KIRQL OldIrql; 00762 PKPROCESS Process; 00763 ULONG Summary; 00764 PKTHREAD Thread; 00765 ULONG WaitTime; 00766 00767 // 00768 // Lock the dispatcher database and check if there are any ready threads 00769 // queued at the scannable priority levels. 00770 // 00771 00772 KiLockDispatcherDatabase(&OldIrql); 00773 Summary = KiReadySummary & ((1 << THREAD_BOOST_PRIORITY) - 2); 00774 if (Summary != 0) { 00775 Count = THREAD_READY_COUNT; 00776 CurrentTick = KiQueryLowTickCount(); 00777 Index = KiReadyQueueIndex; 00778 Number = THREAD_SCAN_COUNT; 00779 do { 00780 00781 // 00782 // If the current ready queue index is beyond the end of the range 00783 // of priorities that are scanned, then wrap back to the beginning 00784 // priority. 00785 // 00786 00787 if (Index > THREAD_SCAN_PRIORITY) { 00788 Index = 1; 00789 } 00790 00791 // 00792 // If there are any ready threads queued at the current priority 00793 // level, then attempt to boost the thread priority. 00794 // 00795 00796 if (((Summary >> Index) & 1) != 0) { 00797 Summary ^= (1 << Index); 00798 ListHead = &KiDispatcherReadyListHead[Index]; 00799 Entry = ListHead->Flink; 00800 00801 ASSERT(Entry != ListHead); 00802 00803 do { 00804 Thread = CONTAINING_RECORD(Entry, KTHREAD, WaitListEntry); 00805 00806 // 00807 // If the thread has been waiting for an extended period, 00808 // then boost the priority of the selected. 00809 // 00810 00811 WaitTime = CurrentTick - Thread->WaitTime; 00812 if (WaitTime >= READY_WITHOUT_RUNNING) { 00813 00814 // 00815 // Remove the thread from the respective ready queue. 00816 // 00817 00818 Entry = Entry->Blink; 00819 RemoveEntryList(Entry->Flink); 00820 if (IsListEmpty(ListHead) != FALSE) { 00821 ClearMember(Index, KiReadySummary); 00822 } 00823 00824 // 00825 // Compute the priority decrement value, set the new 00826 // thread priority, set the decrement count, set the 00827 // thread quantum, and ready the thread for execution. 00828 // 00829 00830 Thread->PriorityDecrement += 00831 THREAD_BOOST_PRIORITY - Thread->Priority; 00832 00833 Thread->DecrementCount = ROUND_TRIP_DECREMENT_COUNT; 00834 Thread->Priority = THREAD_BOOST_PRIORITY; 00835 Process = Thread->ApcState.Process; 00836 Thread->Quantum = Process->ThreadQuantum * 2; 00837 KiReadyThread(Thread); 00838 Count -= 1; 00839 } 00840 00841 Entry = Entry->Flink; 00842 Number -= 1; 00843 } while ((Entry != ListHead) & (Number != 0) & (Count != 0)); 00844 } 00845 00846 Index += 1; 00847 } while ((Summary != 0) & (Number != 0) & (Count != 0)); 00848 } 00849 00850 // 00851 // Unlock the dispatcher database and save the last read queue index 00852 // for the next scan. 00853 // 00854 00855 KiUnlockDispatcherDatabase(OldIrql); 00856 if ((Count != 0) && (Number != 0)) { 00857 KiReadyQueueIndex = 1; 00858 00859 } else { 00860 KiReadyQueueIndex = Index; 00861 } 00862 00863 return; 00864 } 00865 

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