PART 1: Kernel Object//每一位表示对应这个特权级的队列中是否有线程(主要在KiSwapThread用,详细代码见PART3) ULONG KiReadySummary = 0
- Referenced by KeSetAffinityThread(),KiFindReadyThread(),KiReadyThread(), KiScanReadyQueues(), KiSetPriorityThread(), and NtYieldExecution().
// LIST_ENTRY KeBugCheckCallbackListHead
// LIST_ENTRY KiDispatcherReadyListHead[MAXIMUM_PRIORITY]
- Referenced by KeSetAffinityThread(), KiFindReadyThread(), KiInitSystem(), KiReadyThread(), KiScanReadyQueues(), KiSetPriorityThread(), and NtYieldExecution().
// LIST_ENTRY KiProfileListHead
- Referenced by KeStartProfile(), and KiInitSystem().
LIST_ENTRY KiProfileSourceListHead
- Referenced by KeStartProfile(), KeStopProfile(), and KiInitSystem().
// LIST_ENTRY KiProcessOutSwapListHead
- Referenced by KeDetachProcess(), KeSwapProcessOrStack(), KeTerminateThread(), KeUnstackDetachProcess(), KiInitSystem(), KiOutSwapKernelStacks(), and KiOutSwapProcesses().
LIST_ENTRY KiProcessInSwapListHead
- Referenced by KeSwapProcessOrStack(), KiAttachProcess(), KiInitSystem(), KiInSwapProcesses(), KiOutSwapProcesses(), and KiReadyThread().
LIST_ENTRY KiStackInSwapListHead
- Referenced by KeSwapProcessOrStack(), KiInitSystem(), KiInSwapKernelStacks(), and KiReadyThread().
// LIST_ENTRY KiTimerTableListHead[TIMER_TABLE_SIZE]
- Referenced by KeCheckForTimer(), KeSetSystemTime(), KiInitSystem(), KiInsertTimerTable(), KiTimerExpiration(), and VerifierKeInitializeTimerEx().
// LIST_ENTRY KiWaitInListHead
- Referenced by KiInitSystem(), and KiOutSwapKernelStacks().
LIST_ENTRY KiWaitOutListHead
- Referenced by KiInitSystem(), and KiOutSwapKernelStacks().
PART 2: Kernel Object of KPROCESS
LIST_ENTRY _KPROCESS::ThreadListHead - Referenced by ExpGetProcessInformation(), KeDetachProcess(), KeFreezeAllThreads(), KeTerminateThread(), KeThawAllThreads(), and KeUnstackDetachProcess().
LIST_ENTRY _KPROCESS::SwapListEntry
- Referenced by KeDetachProcess(), KeTerminateThread(), KeUnstackDetachProcess(), KiOutSwapKernelStacks(), KiOutSwapProcesses(), and KiReadyThread().
LIST_ENTRY _KPROCESS::ReadyListHead
- Referenced by KiInSwapProcesses(), KiOutSwapProcesses(), and KiReadyThread().
PART 3:
/*------------------------- MmInitSystem -------------------------
- MmInitSystem启动两个线程: KeBalanceSetManager 和 KeSwapProcessOrStack;
- 平衡集管理器(balance set manager)
- 交换管理器(KeSwapProcessOrStack)
- 其实它还启动了MiModifiedPageWriter(将某些页面置入pagefile中)
-----------------------------------------------------------------*/ 01337 // 01338 // Start the modified page writer. 01339 // 01340 01341 InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); 01342 01343 if (!NT_SUCCESS(PsCreateSystemThread( 01344 &ThreadHandle, 01345 THREAD_ALL_ACCESS, 01346 &ObjectAttributes, 01347 0L, 01348 NULL, 01349 MiModifiedPageWriter, 01350 NULL 01351 ))) { 01352 return FALSE; 01353 } 01354 ZwClose (ThreadHandle); 01355 01356 // 01357 // Start the balance set manager. 01358 // 01359 // The balance set manager performs stack swapping and working 01360 // set management and requires two threads. 01361 // 01362 01363 KeInitializeEvent (&MmWorkingSetManagerEvent, 01364 SynchronizationEvent, 01365 FALSE); 01366 01367 InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); 01368 01369 if (!NT_SUCCESS(PsCreateSystemThread( 01370 &ThreadHandle, 01371 THREAD_ALL_ACCESS, 01372 &ObjectAttributes, 01373 0L, 01374 NULL, 01375 KeBalanceSetManager, 01376 NULL 01377 ))) { 01378 01379 return FALSE; 01380 } 01381 ZwClose (ThreadHandle); 01382 01383 if (!NT_SUCCESS(PsCreateSystemThread( 01384 &ThreadHandle, 01385 THREAD_ALL_ACCESS, 01386 &ObjectAttributes, 01387 0L, 01388 NULL, 01389 KeSwapProcessOrStack, 01390 NULL 01391 ))) { 01392 01393 return FALSE; 01394 }
/*---------------------- KeBalanceSetManager ---------------------
- KeBalanceSetManager也一直循环着并等待着一个MmWorkingSetManagerEvent事件 (当内存低时调整工作集的大小)和另一个定时器.
- 定时器事件处理程序周期性地将KiStackOutSwapRequest设置为TRUE, 并且触发KiSwapEvent信号通知KeSwapProcessOrStack线程, KeSwapProcessOrStack线程 不得不将长时间等待某个东西的线程的内核堆栈交换出去.
- KeBalanceSetManager也调用KiScanReadyQueues 来提高在就绪队列中线程(KiDispatcherReadyListHead数组)的优先级.
- 对于每一个提高了优先级的线程, KiReadyThread将会被调用, 所以马上将PRCB.NextThread设置为提高了优先级的线程也是很有可能的 (KiReadyThread 会抢占原先的NextThread).
-----------------------------------------------------------------*/
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 }
/*---------------------- KeSwapProcessOrStack ---------------------
- 将内核堆栈交换出去(由BOOLEAN KiStackOutSwapRequest指定) - 将进程交换出去 (需要交换出去的进程存放在KiProcessOutSwapListHead中) - 将进程交换进来 (需要交换出去的进程存放在KiProcessInSwapListHead中) - 将内核堆栈交换进来(需要交换进来的线程存放在KiStackInSwapListHead中).
-----------------------------------------------------------------*/
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 }
/*------------------------ KiSwapThread -------------------------
-----------------------------------------------------------------*/ ;++ ; ; VOID ; KiSwapThread ( ; VOID ; ) ; ; Routine Description: ; ; This routine is called to select the next thread to run on the ; current processor and to perform a context switch to the thread. ; ; Arguments: ; ; None. ; ; Return Value: ; ; Wait completion status (eax). ; ;--
cPublicFastCall KiSwapThread, 0 .fpo (0, 0, 0, 4, 1, 0)
; ; N.B. The following registers MUST be saved such that ebp is saved last. ; This is done so the debugger can find the saved ebp for a thread ; that is not currently in the running state. ;
sub esp, 4*4 mov [esp+12], ebx ; save registers mov [esp+8], esi ; mov [esp+4], edi ; mov [esp+0], ebp ;
mov ebx, PCR[PcSelfPcr] ; get address of PCR mov edx, [ebx].PcPrcbData.PbNextThread ; get next thread address or edx, edx ; check if next thread selected jnz Swt140 ; if nz, next thread selected
; ; Find the highest nibble in the ready summary that contains a set bit ; and left justify so the nibble is in bits <31:28> ;
mov ecx, 16 ; set base bit number mov edi, _KiReadySummary ; get ready summary mov esi, edi ; copy ready summary shr esi, 16 ; isolate bits <31:16> of summary jnz short Swt10 ; if nz, bits <31:16> are nonzero xor ecx, ecx ; set base bit number mov esi, edi ; set bits <15:0> of summary Swt10: shr esi, 8 ; isolate bits <15:8> of low bits jz short Swt20 ; if z, bits <15:8> are zero add ecx, 8 ; add offset to nonzero byte Swt20: mov esi, edi ; isolate highest nonzero byte shr esi, cl ; add ecx, 3 ; adjust to high bit of nibble cmp esi, 10h ; check if high nibble nonzero jb short Swt30 ; if b, then high nibble is zero add ecx, 4 ; compute ready queue priority Swt30: mov esi, ecx ; left justify ready summary nibble not ecx ; shl edi, cl ; or edi, edi ;
; ; If the next bit is set in the ready summary, then scan the corresponding ; dispatcher ready queue. ;
Swt40: js short Swt60 ; if s, queue contains an entry Swt50: sub esi, 1 ; decrement ready queue priority shl edi, 1 ; position next ready summary bit jnz short Swt40 ; if nz, more queues to scan
; ; If the next bit is set in the ready summary, then scan the corresponding ; dispatcher ready queue. ;
Swt40: js short Swt60 ; if s, queue contains an entry Swt50: sub esi, 1 ; decrement ready queue priority shl edi, 1 ; position next ready summary bit jnz short Swt40 ; if nz, more queues to scan
href="http://blog.vckbase.com/windowssky/Services/Pingback.aspx" rel="pingback" /># re: 线程调度的部分资料(乱)Comments
垃圾一堆 Posted @ 2007-08-27 11:18
00188 typedef enum _KTHREAD_STATE { 00189 Initialized, 00190 Ready, 00191 Running, 00192 Standby, 00193 Terminated, 00194 Waiting, 00195 Transition 00196 } KTHREAD_STATE; //PS:Transition(转换状态) 处于此状态的线程的内核堆栈不在内存中; Insert KiStackInSwapListHead 等待平衡集管理器 通知 交换管理器 进行换进动作;
//一般情况下线程处于等待状态,是因为等待的内核对象(当然是可等待对象含有DISPATCH_HEAD & WaitBlock)还未触发; 如果触发了,线程从等待状态 切换的到 准备状态;下面这几个函数实现了这个功能; /*------------------------ KeSetEvent --------------------------
-----------------------------------------------------------------*/
00343 KeSetEvent ( 00344 IN PRKEVENT Event, 00345 IN KPRIORITY Increment, 00346 IN BOOLEAN Wait 00347 ) 00348 00349 /*++ 00350 00351 Routine Description: 00352 00353 This function sets the signal state of an event object to Signaled 00354 and attempts to satisfy as many Waits as possible. The previous 00355 signal state of the event object is returned as the function value. 00356 00357 Arguments: 00358 00359 Event - Supplies a pointer to a dispatcher object of type event. 00360 00361 Increment - Supplies the priority increment that is to be applied 00362 if setting the event causes a Wait to be satisfied. 00363 00364 Wait - Supplies a boolean value that signifies whether the call to 00365 KePulseEvent will be immediately followed by a call to one of the 00366 kernel Wait functions. 00367 00368 Return Value: 00369 00370 The previous signal state of the event object. 00371 00372 --*/ 00373 00374 { 00375 00376 KIRQL OldIrql; 00377 LONG OldState; 00378 PRKTHREAD Thread; 00379 PRKWAIT_BLOCK WaitBlock; 00380 00381 ASSERT_EVENT(Event); 00382 ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); 00383 00384 // 00385 // Collect call data. 00386 // 00387 00388 #if defined(_COLLECT_SET_EVENT_CALLDATA_) 00389 00390 RECORD_CALL_DATA(&KiSetEventCallData); 00391 00392 #endif 00393 00394 // 00395 // Raise IRQL to dispatcher level and lock dispatcher database. 00396 // 00397 00398 KiLockDispatcherDatabase(&OldIrql); 00399 00400 // 00401 // If the wait list is empty, then set the state of the event to signaled. 00402 // Otherwise, check if the wait can be satisfied immediately. 00403 // 00404 00405 OldState = Event->Header.SignalState; 00406 if (IsListEmpty(&Event->Header.WaitListHead) != FALSE) { 00407 Event->Header.SignalState = 1; 00408 00409 } else { 00410 00411 // 00412 // If the event is a notification event or the wait is not a wait any, 00413 // then set the state of the event to signaled and attempt to satisfy 00414 // as many waits as possible. Otherwise, the wait can be satisfied by 00415 // directly unwaiting the thread. 00416 // 00417 00418 WaitBlock = CONTAINING_RECORD(Event->Header.WaitListHead.Flink, 00419 KWAIT_BLOCK, 00420 WaitListEntry); 00421 00422 if ((Event->Header.Type == NotificationEvent) || 00423 (WaitBlock->WaitType != WaitAny)) { 00424 if (OldState == 0) { 00425 Event->Header.SignalState = 1; 00426 KiWaitTest(Event, Increment); 00427 } 00428 00429 } else { 00430 KiUnwaitThread(WaitBlock->Thread, (NTSTATUS)WaitBlock->WaitKey, Increment); 00431 } 00432 } 00433 00434 // 00435 // If the value of the Wait argument is TRUE, then return to the 00436 // caller with IRQL raised and the dispatcher database locked. Else 00437 // release the dispatcher database lock and lower IRQL to its 00438 // previous value. 00439 // 00440 00441 if (Wait != FALSE) { 00442 Thread = KeGetCurrentThread(); 00443 Thread->WaitNext = Wait; 00444 Thread->WaitIrql = OldIrql; 00445 00446 } else { 00447 KiUnlockDispatcherDatabase(OldIrql); 00448 } 00449 00450 // 00451 // Return previous signal state of event object. 00452 // 00453 00454 return OldState; 00455 }
/*------------------------ KiUnwaitThread-------------------------
-----------------------------------------------------------------*/
00029 VOID 00030 FASTCALL 00031 KiUnwaitThread ( 00032 IN PRKTHREAD Thread, 00033 IN LONG_PTR WaitStatus, 00034 IN KPRIORITY Increment 00035 ) 00036 00037 /*++ 00038 00039 Routine Description: 00040 00041 This function unwaits a thread, sets the thread's wait completion status, 00042 calculates the thread's new priority, and readies the thread for execution. 00043 00044 Arguments: 00045 00046 Thread - Supplies a pointer to a dispatcher object of type thread. 00047 00048 WaitStatus - Supplies the wait completion status. 00049 00050 Increment - Supplies the priority increment that is to be applied to 00051 the thread's priority. 00052 00053 Return Value: 00054 00055 None. 00056 00057 --*/ 00058 00059 { 00060 00061 KPRIORITY NewPriority; 00062 PKPROCESS Process; 00063 PKQUEUE Queue; 00064 PKTIMER Timer; 00065 PRKWAIT_BLOCK WaitBlock; 00066 00067 // 00068 // Set wait completion status, remove wait blocks from object wait 00069 // lists, and remove thread from wait list. 00070 // 00071 00072 Thread->WaitStatus |= WaitStatus; 00073 WaitBlock = Thread->WaitBlockList; 00074 do { 00075 RemoveEntryList(&WaitBlock->WaitListEntry); 00076 WaitBlock = WaitBlock->NextWaitBlock; 00077 } while (WaitBlock != Thread->WaitBlockList); 00078 00079 RemoveEntryList(&Thread->WaitListEntry); 00080 00081 // 00082 // If thread timer is still active, then cancel thread timer. 00083 // 00084 00085 Timer = &Thread->Timer; 00086 if (Timer->Header.Inserted != FALSE) { 00087 KiRemoveTreeTimer(Timer); 00088 } 00089 00090 // 00091 // If the thread is processing a queue entry, then increment the 00092 // count of currently active threads. 00093 // 00094 00095 Queue = Thread->Queue; 00096 if (Queue != NULL) { 00097 Queue->CurrentCount += 1; 00098 } 00099 00100 // 00101 // If the thread runs at a realtime priority level, then reset the 00102 // thread quantum. Otherwise, compute the next thread priority and 00103 // charge the thread for the wait operation. 00104 // 00105 00106 Process = Thread->ApcState.Process; 00107 if (Thread->Priority < LOW_REALTIME_PRIORITY) { 00108 if ((Thread->PriorityDecrement == 0) && 00109 (Thread->DisableBoost == FALSE)) { 00110 NewPriority = Thread->BasePriority + Increment; 00111 if (((PEPROCESS)Process)->Vm.MemoryPriority == MEMORY_PRIORITY_FOREGROUND) { 00112 NewPriority += PsPrioritySeperation; 00113 } 00114 00115 if (NewPriority > Thread->Priority) { 00116 if (NewPriority >= LOW_REALTIME_PRIORITY) { 00117 Thread->Priority = LOW_REALTIME_PRIORITY - 1; 00118 00119 } else { 00120 Thread->Priority = (SCHAR)NewPriority; 00121 } 00122 } 00123 } 00124 00125 if (Thread->BasePriority >= TIME_CRITICAL_PRIORITY_BOUND) { 00126 Thread->Quantum = Process->ThreadQuantum; 00127 00128 } else { 00129 Thread->Quantum -= WAIT_QUANTUM_DECREMENT; 00130 if (Thread->Quantum <= 0) { 00131 Thread->Quantum = Process->ThreadQuantum; 00132 Thread->Priority -= (Thread->PriorityDecrement + 1); 00133 if (Thread->Priority < Thread->BasePriority) { 00134 Thread->Priority = Thread->BasePriority; 00135 } 00136 00137 Thread->PriorityDecrement = 0; 00138 } 00139 } 00140 00141 } else { 00142 Thread->Quantum = Process->ThreadQuantum; 00143 } 00144 00145 // 00146 // Reready the thread for execution. 00147 // 00148 00149 KiReadyThread(Thread); 00150 return; 00151 }
/*------------------------ KiReadyThread -------------------------
-----------------------------------------------------------------*/
00268 VOID 00269 FASTCALL 00270 KiReadyThread ( 00271 IN PRKTHREAD Thread 00272 ) 00273 00274 /*++ 00275 00276 Routine Description: 00277 00278 This function readies a thread for execution and attempts to immediately 00279 dispatch the thread for execution by preempting another lower priority 00280 thread. If a thread can be preempted, then the specified thread enters 00281 the standby state and the target processor is requested to dispatch. If 00282 another thread cannot be preempted, then the specified thread is inserted 00283 either at the head or tail of the dispatcher ready selected by its priority 00284 acccording to whether it was preempted or not. 00285 00286 Arguments: 00287 00288 Thread - Supplies a pointer to a dispatcher object of type thread. 00289 00290 Return Value: 00291 00292 None. 00293 00294 --*/ 00295 00296 { 00297 00298 PRKPRCB Prcb; 00299 BOOLEAN Preempted; 00300 KPRIORITY Priority; 00301 PRKPROCESS Process; 00302 ULONG Processor; 00303 KPRIORITY ThreadPriority; 00304 PRKTHREAD Thread1; 00305 KAFFINITY IdleSet; 00306 00307 // 00308 // Save value of thread's preempted flag, set thread preempted FALSE, 00309 // capture the thread priority, and set clear the read wait time. 00310 // 00311 00312 Preempted = Thread->Preempted; 00313 Thread->Preempted = FALSE; 00314 ThreadPriority = Thread->Priority; 00315 Thread->WaitTime = KiQueryLowTickCount(); 00316 00317 // 00318 // If the thread's process is not in memory, then insert the thread in 00319 // the process ready queue and inswap the process. 00320 // 00321 00322 Process = Thread->ApcState.Process; 00323 if (Process->State != ProcessInMemory) { 00324 Thread->State = Ready; 00325 Thread->ProcessReadyQueue = TRUE; 00326 InsertTailList(&Process->ReadyListHead, &Thread->WaitListEntry); 00327 if (Process->State == ProcessOutOfMemory) { 00328 Process->State = ProcessInTransition; 00329 InsertTailList(&KiProcessInSwapListHead, &Process->SwapListEntry); 00330 KiSwapEvent.Header.SignalState = 1; 00331 if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) { 00332 KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT); 00333 } 00334 } 00335 00336 return; 00337 00338 } else if (Thread->KernelStackResident == FALSE) { 00339 00340 // 00341 // The thread's kernel stack is not resident. Increment the process 00342 // stack count, set the state of the thread to transition, insert 00343 // the thread in the kernel stack inswap list, and set the kernel 00344 // stack inswap event. 00345 // 00346 00347 Process->StackCount += 1; 00348 Thread->State = Transition; 00349 InsertTailList(&KiStackInSwapListHead, &Thread->WaitListEntry); 00350 KiSwapEvent.Header.SignalState = 1; 00351 if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) { 00352 KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT); 00353 } 00354 00355 return; 00356 00357 } else { 00358 00359 // 00360 // If there is an idle processor, then schedule the thread on an 00361 // idle processor giving preference to the processor the thread 00362 // last ran on. Otherwise, try to preempt either a thread in the 00363 // standby or running state. 00364 // 00365 00366 #if defined(NT_UP) 00367 00368 Prcb = KiProcessorBlock[0]; 00369 if (KiIdleSummary != 0) { 00370 KiIdleSummary = 0; 00371 KiIncrementSwitchCounter(IdleLast); 00372 Prcb->NextThread = Thread; 00373 Thread->State = Standby; 00374 00375 #else 00376 00377 IdleSet = KiIdleSummary & Thread->Affinity; 00378 if (IdleSet != 0) { 00379 Prcb = KeGetCurrentPrcb(); 00380 Processor = Thread->IdealProcessor; 00381 if ((IdleSet & (1 << Processor)) == 0) { 00382 Processor = Thread->NextProcessor; 00383 if ((IdleSet & (1 << Processor)) == 0) { 00384 if ((IdleSet & Prcb->SetMember) == 0) { 00385 FindFirstSetLeftMember(IdleSet, &Processor); 00386 KiIncrementSwitchCounter(IdleAny); 00387 00388 } else { 00389 Processor = Prcb->Number; 00390 KiIncrementSwitchCounter(IdleCurrent); 00391 } 00392 00393 } else { 00394 KiIncrementSwitchCounter(IdleLast); 00395 } 00396 00397 } else { 00398 KiIncrementSwitchCounter(IdleIdeal); 00399 } 00400 00401 Thread->NextProcessor = (CCHAR)Processor; 00402 ClearMember(Processor, KiIdleSummary); 00403 KiProcessorBlock[Processor]->NextThread = Thread; 00404 Thread->State = Standby; 00405 00406 if ((PoSleepingSummary & (1 << Processor)) && 00407 Processor != (ULONG) Prcb->Number) { 00408 KiIpiSend(1 << Processor, IPI_DPC); 00409 } 00410 #endif 00411 00412 return; 00413 00414 } else { 00415 00416 #if !defined(NT_UP) 00417 00418 Processor = Thread->IdealProcessor; 00419 if ((Thread->Affinity & (1 << Processor)) == 0) { 00420 Processor = Thread->NextProcessor; 00421 if ((Thread->Affinity & (1 << Processor)) == 0) { 00422 FindFirstSetLeftMember(Thread->Affinity, &Processor); 00423 } 00424 } 00425 00426 Thread->NextProcessor = (CCHAR)Processor; 00427 Prcb = KiProcessorBlock[Processor]; 00428 00429 #endif 00430 00431 if (Prcb->NextThread != NULL) { 00432 Thread1 = Prcb->NextThread; 00433 if (ThreadPriority > Thread1->Priority) { 00434 Thread1->Preempted = TRUE; 00435 Prcb->NextThread = Thread; 00436 Thread->State = Standby; 00437 KiReadyThread(Thread1); 00438 KiIncrementSwitchCounter(PreemptLast); 00439 return; 00440 } 00441 00442 } else { 00443 Thread1 = Prcb->CurrentThread; 00444 if (ThreadPriority > Thread1->Priority) { 00445 Thread1->Preempted = TRUE; 00446 Prcb->NextThread = Thread; 00447 Thread->State = Standby; 00448 KiRequestDispatchInterrupt(Thread->NextProcessor); 00449 KiIncrementSwitchCounter(PreemptLast); 00450 return; 00451 } 00452 } 00453 } 00454 } 00455 00456 // 00457 // No thread can be preempted. Insert the thread in the dispatcher 00458 // queue selected by its priority. If the thread was preempted and 00459 // runs at a realtime priority level, then insert the thread at the 00460 // front of the queue. Else insert the thread at the tail of the queue. 00461 // 00462 00463 Thread->State = Ready; 00464 if (Preempted != FALSE) { 00465 InsertHeadList(&KiDispatcherReadyListHead[ThreadPriority], 00466 &Thread->WaitListEntry); 00467 00468 } else { 00469 InsertTailList(&KiDispatcherReadyListHead[ThreadPriority], 00470 &Thread->WaitListEntry); 00471 } 00472 00473 SetMember(ThreadPriority, KiReadySummary); 00474 return; 00475 }