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
posted on 2007-08-23 17:28 垃圾一堆 阅读(2994)
评论(1) 编辑 收藏