在Windows操作系统内核把软件中断分为三个中断级别:DISPATCH_LEVEL,APC_LEVEL,PASSVIE_LEVEL。同时他们与线程的调试相关,WINDOWS内核中没有一个专门的程序来做线程的调度工作,它是散落在系统各个部分的。总结一下主要以下几种情况。

当空闲线程运行时粗略讲是1.先检查当前处理的DPC例程队列,分发DPC调用。2.检查NextThread是否为空,如果存在不为空就切换到这个线程,若为空进行第三步3.执行线程的调试算法。

当HalpDispatchSoftwareInterrupt被调用时。这个函数主要流程还是比较简单的,判断了第一个参数是否为1(APC_LEVEL)如果是调用KiDeliverApc来分发APC例程。若不是接看是否为2(DISPATCH_LEVEL),是的话就调用KiDispatchInterrupt。KiDispatchInterrupt这个函数内容较多,不过流程上跟空闲进程差不多。只是它检查了当前处理器的QuantumEnd标记,若不为0就执行KiQuantumEnd,KiQuantumEnd这个函数进行了线程的调试。

hal!HalpDispatchSoftwareInterrupt:

83c1f8c6 8bff            mov     edi,edi

83c1f8c8 55              push    ebp

83c1f8c9 8bec            mov     ebp,esp

83c1f8cb51              push    ecx

83c1f8cc53              push    ebx

83c1f8cd56              push    esi

83c1f8ce 9c              pushfd

83c1f8cf58              pop     eax

83c1f8d08945fc          mov     dword ptr [ebp-4],eax

83c1f8d38b75fc          mov     esi,dword ptr [ebp-4]

83c1f8d681e600020000    and     esi,200h

83c1f8dc 8a4508          mov     al,byte ptr [ebp+8]

83c1f8df 64a224000000    mov    byte ptr fs:[00000024h],al

83c1f8e57501            jne     hal!HalpDispatchSoftwareInterrupt+0x22 (83c1f8e8)

hal!HalpDispatchSoftwareInterrupt+0x21:

83c1f8e7fb              sti

hal!HalpDispatchSoftwareInterrupt+0x22:

83c1f8e833db            xor     ebx,ebx

83c1f8ea381dbd6ac383    cmp    byte ptr [hal!HalpEnableIrqlAudit (83c36abd)],bl

83c1f8f0 7405            je      hal!HalpDispatchSoftwareInterrupt+0x31 (83c1f8f7)

hal!HalpDispatchSoftwareInterrupt+0x2c:

83c1f8f2e8e9feffff      call    hal!HalpValidatePendingInterrupts (83c1f7e0)

hal!HalpDispatchSoftwareInterrupt+0x31:

83c1f8f7807d0801        cmp     byte ptr [ebp+8],1

83c1f8fb7514            jne     hal!HalpDispatchSoftwareInterrupt+0x4b (83c1f911)

hal!HalpDispatchSoftwareInterrupt+0x37:

83c1f8fdff750c          push    dword ptr [ebp+0Ch]

83c1f90064881d96000000  mov     byte ptr fs:[96h],bl

83c1f90753              push    ebx

83c1f90853              push    ebx

83c1f909ff15e4b0c183    call   dword ptr [hal!_imp__KiDeliverApc (83c1b0e4)]

83c1f90f eb1e            jmp     hal!HalpDispatchSoftwareInterrupt+0x69 (83c1f92f)

hal!HalpDispatchSoftwareInterrupt+0x4b:

83c1f911807d0802        cmp     byte ptr [ebp+8],2

83c1f915 750f            jne     hal!HalpDispatchSoftwareInterrupt+0x60 (83c1f926)

hal!HalpDispatchSoftwareInterrupt+0x51:

83c1f91764881d97000000  mov     byte ptr fs:[97h],bl

83c1f91eff15e0b0c183    call   dword ptr [hal!_imp__KiDispatchInterrupt (83c1b0e0)]

83c1f924eb09            jmp     hal!HalpDispatchSoftwareInterrupt+0x69 (83c1f92f)

hal!HalpDispatchSoftwareInterrupt+0x60:

83c1f926381dbd6ac383    cmp    byte ptr [hal!HalpEnableIrqlAudit (83c36abd)],bl

83c1f92c 7401            je      hal!HalpDispatchSoftwareInterrupt+0x69 (83c1f92f)

hal!HalpDispatchSoftwareInterrupt+0x68:

83c1f92ecc              int     3

hal!HalpDispatchSoftwareInterrupt+0x69:

83c1f92f 3bf3            cmp     esi,ebx

83c1f9317501            jne     hal!HalpDispatchSoftwareInterrupt+0x6e (83c1f934)

hal!HalpDispatchSoftwareInterrupt+0x6d:

83c1f933fa              cli

hal!HalpDispatchSoftwareInterrupt+0x6e:

83c1f934381dbd6ac383    cmp    byte ptr [hal!HalpEnableIrqlAudit (83c36abd)],bl

83c1f93a 7411            je      hal!HalpDispatchSoftwareInterrupt+0x87 (83c1f94d)

hal!HalpDispatchSoftwareInterrupt+0x76:

83c1f93c 64a024000000    mov    al,byte ptr fs:[00000024h]

83c1f942 3a4508          cmp     al,byte ptr [ebp+8]

83c1f9457401            je      hal!HalpDispatchSoftwareInterrupt+0x82 (83c1f948)

hal!HalpDispatchSoftwareInterrupt+0x81:

83c1f947cc              int     3

hal!HalpDispatchSoftwareInterrupt+0x82:

83c1f948e893feffff      call    hal!HalpValidatePendingInterrupts (83c1f7e0)

hal!HalpDispatchSoftwareInterrupt+0x87:

83c1f94d5e              pop     esi

83c1f94e5b              pop     ebx

83c1f94f c9              leave

83c1f950 c20800          ret     8

还有一种情况是当执行了一些等锁或事件等函数时,这时会发生线程切换。这里有一个特殊情况是(Thread->ApcState.KernelApcPending &&            (Thread->SpecialApcDisable == 0)&& (Thread->WaitIrql < APC_LEVEL))时会进入KiExitDispatcher流程;基本上是先Thread->WaitIrql = KeRaiseIrqlToSynchLevel();InitializeDelayExecution();最后通过KiUnlockDispatcherDatabase(Thread->WaitIrql);调入KiExitDispatcher(\*Thread->WaitIrql*\)中。

8aed3c5883cbe403 00000000 86a3e240ffffffff nt!KiSwapThread+0x254

8aed3c8083cbe0e1 86a3e240 86a3e300 00000044nt!KiCommitThreadWait+0x1df

8aed3cd8 83e826ed 00000201 00000000 8aed3cfcnt!KeDelayExecutionThread+0x2aa

8aed3d24 83c9442a 00000000 00f5f79000f5f7b4 nt!NtDelayExecution+0x8d

8aed3d24 771864f400000000 00f5f790 00f5f7b4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8aed3d34)

00f5f748 77184c1c 753f187600000000 00f5f790 ntdll!KiFastSystemCallRet (FPO: [0,0,0])

00f5f74c 753f187600000000 00f5f790 53ddb789 ntdll!ZwDelayExecution+0xc (FPO:[2,0,0])

00f5f7b4 753f1818 00000064 00000000 00f5f800KERNELBASE!SleepEx+0x65 (FPO: [Non-Fpo])

00f5f7c4 70586be7 00000064 52194086 00000000KERNELBASE!Sleep+0xf (FPO: [Non-Fpo])

00f5f800 70587824 00f5f81476971174 001cea40 MSDTCPRX!CConnectionManager::TimerProcForNonGuardedUser+0x72(FPO: [Non-Fpo])

00f5f808 76971174001cea40 00f5f854 7719b3f5MSDTCPRX!CConnectionManager::TimerProc+0x1e (FPO: [Non-Fpo])

00f5f814 7719b3f5 001cea40 77d42614 00000000kernel32!BaseThreadInitThunk+0xe (FPO: [Non-Fpo])

00f5f854 7719b3c8 70587806 001cea40 00000000ntdll!__RtlUserThreadStart+0x70 (FPO: [Non-Fpo])

00f5f86c 00000000 70587806 001cea40 00000000ntdll!_RtlUserThreadStart+0x1b (FPO: [Non-Fpo])

PKTHREAD CurrentThread;

PKTHREAD NewThread;

BOOLEAN Pending;

PKPRCB Prcb;

ASSERT(KeGetCurrentIrql() == SYNCH_LEVEL);

//

// Process the deferred ready list if the list is not empty.

//

Prcb = KeGetCurrentPrcb();

#if !defined(NT_UP)

if (Prcb->DeferredReadyListHead.Next != NULL) {

KiProcessDeferredReadyList(Prcb);

}

#endif

//

// If the old IRQL is less than dispatch level, then a new thread can

// be dispatcher immediately.

//

if (OldIrql < DISPATCH_LEVEL) {

//

// If there is a new thread selected for execution, then switch

// context to the new thread.

//

if (Prcb->NextThread != NULL) {

KiAcquirePrcbLock(Prcb);

NewThread = Prcb->NextThread;

CurrentThread =Prcb->CurrentThread;

KiSetContextSwapBusy(CurrentThread);

Prcb->NextThread = NULL;

Prcb->CurrentThread = NewThread;

NewThread->State = Running;

KxQueueReadyThread(CurrentThread,Prcb);

CurrentThread->WaitIrql =OldIrql;

Pending =KiSwapContext(CurrentThread, NewThread);

if (Pending != FALSE) {

KeLowerIrql(APC_LEVEL);

KiDeliverApc(KernelMode, NULL,NULL);

ASSERT(OldIrql == 0);

}

}

} else if ((Prcb->NextThread != NULL) &&

(Prcb->DpcRoutineActive ==FALSE)) {

KiRequestSoftwareInterrupt(DISPATCH_LEVEL);

}

//

// Lower IRQL to its previous level.

//

KeLowerIrql(OldIrql);

return;

HalpDispatchSoftwareInterrupt是调用那这么几种情况:hal!KfLowerIrql调用的时候,有INT3和其它一些中断发现的时候。所以这里有一个问题对HalpDispatchSoftwareInterrupt下一个断点的话,系统的栈溢出了。

可以看出软件中断,基本上是在空闲线程、KiExitDispatcher和HalpDispatchSoftwareInterrupt分被分发的。还有线程切换是DPC级别的,若在DPC级别长时间逗留,会影响线程的切换。

05-08 14:57