00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
#include "ki.h"
00047
00048
00049
00050
00051
00052 typedef enum _BALANCE_OBJECT {
00053
TimerExpiration,
00054
WorkingSetManagerEvent,
00055
MaximumObject
00056 }
BALANCE_OBJECT;
00057
00058
00059
00060
00061
00062
00063 #define MAXIMUM_THREAD_STACKS 20
00064
00065
00066
00067
00068
00069 #define PERIODIC_INTERVAL (1 * 1000 * 1000 * 10)
00070
00071
00072
00073
00074
00075
00076 #define READY_WITHOUT_RUNNING (4 * 75)
00077
00078
00079
00080
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
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
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
00131
00132
00133 ULONG
KiReadyQueueIndex = 1;
00134
00135
00136
00137
00138
00139 BOOLEAN
KiStackOutSwapRequest =
FALSE;
00140
00141
VOID
00142 KeBalanceSetManager (
00143 IN PVOID Context
00144 )
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
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
00177
00178
00179
KeSetPriorityThread(
KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
00180
00181
00182
00183
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
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
00204
00205
00206 WaitObjects[
TimerExpiration] = (PVOID)&PeriodTimer;
00207 WaitObjects[
WorkingSetManagerEvent] = (PVOID)&
MmWorkingSetManagerEvent;
00208
00209
00210
00211
00212
00213
do {
00214
00215
00216
00217
00218
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
00232
00233
00234
switch (
Status) {
00235
00236
00237
00238
00239
00240
case TimerExpiration:
00241
00242
00243
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
00262
00263
00264
ExAdjustLookasideDepth();
00265
00266
00267
00268
00269
00270
KiScanReadyQueues();
00271
00272
00273
00274
00275
00276
MmWorkingSetManager();
00277
00278
00279
00280
00281
00282 ExecutionTimeLimitPeriod -= 1;
00283
if (ExecutionTimeLimitPeriod == 0) {
00284 ExecutionTimeLimitPeriod =
EXECUTION_TIME_LIMITS_PERIOD;
00285
PsEnforceExecutionTimeLimits();
00286 }
00287
00288
00289
00290
00291
00292
KeSetTimer(&PeriodTimer, DueTime,
NULL);
00293
break;
00294
00295
00296
00297
00298
00299
case WorkingSetManagerEvent:
00300
00301
00302
00303
00304
00305
MmWorkingSetManager();
00306
break;
00307
00308
00309
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
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348 {
00349
00350 KIRQL OldIrql;
00351
NTSTATUS Status;
00352
00353
00354
00355
00356
00357
00358
KeSetPriorityThread(
KeGetCurrentThread(), LOW_REALTIME_PRIORITY + 7);
00359
00360
00361
00362
00363
00364
do {
00365
00366
00367
00368
00369
00370
Status =
KeWaitForSingleObject(&
KiSwapEvent,
00371
Executive,
00372
KernelMode,
00373
FALSE,
00374
NULL);
00375
00376
00377
00378
00379
00380
KiLockDispatcherDatabase(&OldIrql);
00381
00382
00383
00384
00385
00386
do {
00387
00388
00389
00390
00391
00392
00393
00394
00395
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
00422
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
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455 {
00456
00457 PLIST_ENTRY NextEntry;
00458 KIRQL OldIrql;
00459
PKTHREAD Thread;
00460
00461
00462
00463
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
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506 {
00507
00508 PLIST_ENTRY NextEntry;
00509 KIRQL OldIrql;
00510
PKPROCESS Process;
00511
PKTHREAD Thread;
00512
00513
00514
00515
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
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
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
00582
00583
00584
00585
00586
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
00620
00621
00622
00623
KiUnlockDispatcherDatabase(OldIrql);
00624
00625
00626
00627
00628
00629
while (NumberOfThreads > 0) {
00630 NumberOfThreads -= 1;
00631 Thread = ThreadObjects[NumberOfThreads];
00632
MmOutPageKernelStack(Thread);
00633 }
00634
00635
00636
00637
00638
00639
KiLockDispatcherDatabase(&OldIrql);
00640
return;
00641 }
00642
00643
VOID
00644 KiOutSwapProcesses (
00645 IN KIRQL PreviousIrql
00646 )
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667 {
00668
00669 PLIST_ENTRY NextEntry;
00670 KIRQL OldIrql;
00671
PKPROCESS Process;
00672
PKTHREAD Thread;
00673
00674
00675
00676
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
00687
00688
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
00710
00711
00712
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
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
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
00769
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
00783
00784
00785
00786
00787
if (
Index >
THREAD_SCAN_PRIORITY) {
00788
Index = 1;
00789 }
00790
00791
00792
00793
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
00808
00809
00810
00811 WaitTime = CurrentTick - Thread->
WaitTime;
00812
if (WaitTime >=
READY_WITHOUT_RUNNING) {
00813
00814
00815
00816
00817
00818 Entry = Entry->Blink;
00819 RemoveEntryList(Entry->Flink);
00820
if (IsListEmpty(ListHead) !=
FALSE) {
00821
ClearMember(
Index,
KiReadySummary);
00822 }
00823
00824
00825
00826
00827
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
00852
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