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