xref: /reactos/ntoskrnl/ke/balmgr.c (revision c2c66aff)
1*c2c66affSColin Finck /*
2*c2c66affSColin Finck * PROJECT:         ReactOS Kernel
3*c2c66affSColin Finck * LICENSE:         GPL - See COPYING in the top level directory
4*c2c66affSColin Finck * FILE:            ntoskrnl/ke/balmgr.c
5*c2c66affSColin Finck * PURPOSE:         Balance Set Manager
6*c2c66affSColin Finck * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7*c2c66affSColin Finck */
8*c2c66affSColin Finck 
9*c2c66affSColin Finck /* INCLUDES ******************************************************************/
10*c2c66affSColin Finck 
11*c2c66affSColin Finck #include <ntoskrnl.h>
12*c2c66affSColin Finck #define NDEBUG
13*c2c66affSColin Finck #include <debug.h>
14*c2c66affSColin Finck 
15*c2c66affSColin Finck /* GLOBALS *******************************************************************/
16*c2c66affSColin Finck 
17*c2c66affSColin Finck #define THREAD_BOOST_PRIORITY (LOW_REALTIME_PRIORITY - 1)
18*c2c66affSColin Finck ULONG KiReadyScanLast;
19*c2c66affSColin Finck 
20*c2c66affSColin Finck /* PRIVATE FUNCTIONS *********************************************************/
21*c2c66affSColin Finck 
22*c2c66affSColin Finck VOID
23*c2c66affSColin Finck NTAPI
KiScanReadyQueues(IN PKDPC Dpc,IN PVOID DeferredContext,IN PVOID SystemArgument1,IN PVOID SystemArgument2)24*c2c66affSColin Finck KiScanReadyQueues(IN PKDPC Dpc,
25*c2c66affSColin Finck                   IN PVOID DeferredContext,
26*c2c66affSColin Finck                   IN PVOID SystemArgument1,
27*c2c66affSColin Finck                   IN PVOID SystemArgument2)
28*c2c66affSColin Finck {
29*c2c66affSColin Finck     PULONG ScanLast = DeferredContext;
30*c2c66affSColin Finck     ULONG ScanIndex = *ScanLast;
31*c2c66affSColin Finck     ULONG Count = 10, Number = 16;
32*c2c66affSColin Finck     PKPRCB Prcb = KiProcessorBlock[ScanIndex];
33*c2c66affSColin Finck     ULONG Index = Prcb->QueueIndex;
34*c2c66affSColin Finck     ULONG WaitLimit = KeTickCount.LowPart - 300;
35*c2c66affSColin Finck     ULONG Summary;
36*c2c66affSColin Finck     KIRQL OldIrql;
37*c2c66affSColin Finck     PLIST_ENTRY ListHead, NextEntry;
38*c2c66affSColin Finck     PKTHREAD Thread;
39*c2c66affSColin Finck 
40*c2c66affSColin Finck     /* Lock the dispatcher and PRCB */
41*c2c66affSColin Finck     OldIrql = KiAcquireDispatcherLock();
42*c2c66affSColin Finck     KiAcquirePrcbLock(Prcb);
43*c2c66affSColin Finck     /* Check if there's any thread that need help */
44*c2c66affSColin Finck     Summary = Prcb->ReadySummary & ((1 << THREAD_BOOST_PRIORITY) - 2);
45*c2c66affSColin Finck     if (Summary)
46*c2c66affSColin Finck     {
47*c2c66affSColin Finck         /* Start scan loop */
48*c2c66affSColin Finck         do
49*c2c66affSColin Finck         {
50*c2c66affSColin Finck             /* Normalize the index */
51*c2c66affSColin Finck             if (Index > (THREAD_BOOST_PRIORITY - 1)) Index = 1;
52*c2c66affSColin Finck 
53*c2c66affSColin Finck             /* Loop for ready threads */
54*c2c66affSColin Finck             if (Summary & PRIORITY_MASK(Index))
55*c2c66affSColin Finck             {
56*c2c66affSColin Finck                 /* Sanity check */
57*c2c66affSColin Finck                 ASSERT(!IsListEmpty(&Prcb->DispatcherReadyListHead[Index]));
58*c2c66affSColin Finck 
59*c2c66affSColin Finck                 /* Update summary and select list */
60*c2c66affSColin Finck                 Summary ^= PRIORITY_MASK(Index);
61*c2c66affSColin Finck                 ListHead = &Prcb->DispatcherReadyListHead[Index];
62*c2c66affSColin Finck                 NextEntry = ListHead->Flink;
63*c2c66affSColin Finck                 do
64*c2c66affSColin Finck                 {
65*c2c66affSColin Finck                     /* Select a thread */
66*c2c66affSColin Finck                     Thread = CONTAINING_RECORD(NextEntry,
67*c2c66affSColin Finck                                                KTHREAD,
68*c2c66affSColin Finck                                                WaitListEntry);
69*c2c66affSColin Finck                     ASSERT(Thread->Priority == Index);
70*c2c66affSColin Finck 
71*c2c66affSColin Finck                     /* Check if the thread has been waiting too long */
72*c2c66affSColin Finck                     if (WaitLimit >= Thread->WaitTime)
73*c2c66affSColin Finck                     {
74*c2c66affSColin Finck                         /* Remove the thread from the queue */
75*c2c66affSColin Finck                         NextEntry = NextEntry->Blink;
76*c2c66affSColin Finck                         ASSERT((Prcb->ReadySummary & PRIORITY_MASK(Index)));
77*c2c66affSColin Finck                         if (RemoveEntryList(NextEntry->Flink))
78*c2c66affSColin Finck                         {
79*c2c66affSColin Finck                             /* The list is empty now */
80*c2c66affSColin Finck                             Prcb->ReadySummary ^= PRIORITY_MASK(Index);
81*c2c66affSColin Finck                         }
82*c2c66affSColin Finck 
83*c2c66affSColin Finck                         /* Verify priority decrement and set the new one */
84*c2c66affSColin Finck                         ASSERT((Thread->PriorityDecrement >= 0) &&
85*c2c66affSColin Finck                                (Thread->PriorityDecrement <=
86*c2c66affSColin Finck                                 Thread->Priority));
87*c2c66affSColin Finck                         Thread->PriorityDecrement += (THREAD_BOOST_PRIORITY -
88*c2c66affSColin Finck                                                       Thread->Priority);
89*c2c66affSColin Finck                         ASSERT((Thread->PriorityDecrement >= 0) &&
90*c2c66affSColin Finck                                (Thread->PriorityDecrement <=
91*c2c66affSColin Finck                                 THREAD_BOOST_PRIORITY));
92*c2c66affSColin Finck 
93*c2c66affSColin Finck                         /* Update priority and insert into ready list */
94*c2c66affSColin Finck                         Thread->Priority = THREAD_BOOST_PRIORITY;
95*c2c66affSColin Finck                         Thread->Quantum = WAIT_QUANTUM_DECREMENT * 4;
96*c2c66affSColin Finck                         KiInsertDeferredReadyList(Thread);
97*c2c66affSColin Finck                         Count --;
98*c2c66affSColin Finck                     }
99*c2c66affSColin Finck 
100*c2c66affSColin Finck                     /* Go to the next entry */
101*c2c66affSColin Finck                     NextEntry = NextEntry->Flink;
102*c2c66affSColin Finck                     Number--;
103*c2c66affSColin Finck                 } while((NextEntry != ListHead) && (Number) && (Count));
104*c2c66affSColin Finck             }
105*c2c66affSColin Finck 
106*c2c66affSColin Finck             /* Increase index */
107*c2c66affSColin Finck             Index++;
108*c2c66affSColin Finck         } while ((Summary) && (Number) && (Count));
109*c2c66affSColin Finck     }
110*c2c66affSColin Finck 
111*c2c66affSColin Finck     /* Release the locks and dispatcher */
112*c2c66affSColin Finck     KiReleasePrcbLock(Prcb);
113*c2c66affSColin Finck     KiReleaseDispatcherLock(OldIrql);
114*c2c66affSColin Finck 
115*c2c66affSColin Finck     /* Update the queue index for next time */
116*c2c66affSColin Finck     if ((Count) && (Number))
117*c2c66affSColin Finck     {
118*c2c66affSColin Finck         /* Reset the queue at index 1 */
119*c2c66affSColin Finck         Prcb->QueueIndex = 1;
120*c2c66affSColin Finck     }
121*c2c66affSColin Finck     else
122*c2c66affSColin Finck     {
123*c2c66affSColin Finck         /* Set the index we're in now */
124*c2c66affSColin Finck         Prcb->QueueIndex = Index;
125*c2c66affSColin Finck     }
126*c2c66affSColin Finck 
127*c2c66affSColin Finck     /* Increment the CPU number for next time and normalize to CPU count */
128*c2c66affSColin Finck     ScanIndex++;
129*c2c66affSColin Finck     if (ScanIndex == KeNumberProcessors) ScanIndex = 0;
130*c2c66affSColin Finck 
131*c2c66affSColin Finck     /* Return the index */
132*c2c66affSColin Finck     *ScanLast = ScanIndex;
133*c2c66affSColin Finck }
134*c2c66affSColin Finck 
135*c2c66affSColin Finck VOID
136*c2c66affSColin Finck NTAPI
KeBalanceSetManager(IN PVOID Context)137*c2c66affSColin Finck KeBalanceSetManager(IN PVOID Context)
138*c2c66affSColin Finck {
139*c2c66affSColin Finck     KDPC ScanDpc;
140*c2c66affSColin Finck     KTIMER PeriodTimer;
141*c2c66affSColin Finck     LARGE_INTEGER DueTime;
142*c2c66affSColin Finck     KWAIT_BLOCK WaitBlockArray[1];
143*c2c66affSColin Finck     PVOID WaitObjects[1];
144*c2c66affSColin Finck     NTSTATUS Status;
145*c2c66affSColin Finck 
146*c2c66affSColin Finck     /* Set us at a low real-time priority level */
147*c2c66affSColin Finck     KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
148*c2c66affSColin Finck 
149*c2c66affSColin Finck     /* Setup the timer and scanner DPC */
150*c2c66affSColin Finck     KeInitializeTimerEx(&PeriodTimer, SynchronizationTimer);
151*c2c66affSColin Finck     KeInitializeDpc(&ScanDpc, KiScanReadyQueues, &KiReadyScanLast);
152*c2c66affSColin Finck 
153*c2c66affSColin Finck     /* Setup the periodic timer */
154*c2c66affSColin Finck     DueTime.QuadPart = -1 * 10 * 1000 * 1000;
155*c2c66affSColin Finck     KeSetTimerEx(&PeriodTimer, DueTime, 1000, &ScanDpc);
156*c2c66affSColin Finck 
157*c2c66affSColin Finck     /* Setup the wait objects */
158*c2c66affSColin Finck     WaitObjects[0] = &PeriodTimer;
159*c2c66affSColin Finck     //WaitObjects[1] = MmWorkingSetManagerEvent; // NO WS Management Yet!
160*c2c66affSColin Finck 
161*c2c66affSColin Finck     /* Start wait loop */
162*c2c66affSColin Finck     do
163*c2c66affSColin Finck     {
164*c2c66affSColin Finck         /* Wait on our objects */
165*c2c66affSColin Finck         Status = KeWaitForMultipleObjects(1,
166*c2c66affSColin Finck                                           WaitObjects,
167*c2c66affSColin Finck                                           WaitAny,
168*c2c66affSColin Finck                                           Executive,
169*c2c66affSColin Finck                                           KernelMode,
170*c2c66affSColin Finck                                           FALSE,
171*c2c66affSColin Finck                                           NULL,
172*c2c66affSColin Finck                                           WaitBlockArray);
173*c2c66affSColin Finck         switch (Status)
174*c2c66affSColin Finck         {
175*c2c66affSColin Finck             /* Check if our timer expired */
176*c2c66affSColin Finck             case STATUS_WAIT_0:
177*c2c66affSColin Finck 
178*c2c66affSColin Finck                 /* Adjust lookaside lists */
179*c2c66affSColin Finck                 //ExAdjustLookasideDepth();
180*c2c66affSColin Finck 
181*c2c66affSColin Finck                 /* Call the working set manager */
182*c2c66affSColin Finck                 //MmWorkingSetManager();
183*c2c66affSColin Finck 
184*c2c66affSColin Finck                 /* FIXME: Outswap stacks */
185*c2c66affSColin Finck 
186*c2c66affSColin Finck                 /* Done */
187*c2c66affSColin Finck                 break;
188*c2c66affSColin Finck 
189*c2c66affSColin Finck             /* Check if the working set manager notified us */
190*c2c66affSColin Finck             case STATUS_WAIT_1:
191*c2c66affSColin Finck 
192*c2c66affSColin Finck                 /* Call the working set manager */
193*c2c66affSColin Finck                 //MmWorkingSetManager();
194*c2c66affSColin Finck                 break;
195*c2c66affSColin Finck 
196*c2c66affSColin Finck             /* Anything else */
197*c2c66affSColin Finck             default:
198*c2c66affSColin Finck                 DPRINT1("BALMGR: Illegal wait status, %lx =\n", Status);
199*c2c66affSColin Finck                 break;
200*c2c66affSColin Finck         }
201*c2c66affSColin Finck     } while (TRUE);
202*c2c66affSColin Finck }
203