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