windowssky 阅读(1203) 评论(1)


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


评论列表
垃圾一堆
re: 线程调度的部分资料(乱)

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 }

 

发表评论
切换编辑模式