news 2026/5/29 23:10:08

nt!KiDispatchInterrupt函数中nt!KiQueueReadyThread和nt!SwapContext和KiQuantumEnd3个函数的关系

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
nt!KiDispatchInterrupt函数中nt!KiQueueReadyThread和nt!SwapContext和KiQuantumEnd3个函数的关系

nt!KiDispatchInterrupt函数中nt!KiQueueReadyThread和nt!SwapContext和KiQuantumEnd3个函数的关系

align 16
cPublicProc _KiDispatchInterrupt ,0
cPublicFpo 0, 0

mov ebx, PCR[PcSelfPcr] ; get address of PCR


。。。

;
; Check to determine if quantum end is requested.
;
; N.B. If a new thread is selected as a result of processing the quantum
; end request, then the new thread is returned with the dispatcher
; database locked. Otherwise, NULL is returned with the dispatcher
; database unlocked.
;

kdi40: sti ; enable interrupts
cmp byte ptr [ebx].PcPrcbData.PbQuantumEnd, 0 ; quantum end requested
jne kdi90 ; if neq, quantum end request

;
; Check to determine if a new thread has been selected for execution on this
; processor.
;

cmp dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; check if next thread
je kdi70 ; if eq, then no new thread

;
; 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, 3*4
mov [esp+8], esi ; save registers
mov [esp+4], edi ;
mov [esp+0], ebp ;
mov edi, [ebx].PcPrcbData.PbCurrentThread ; get current thread address (as old thread)

;
; Raise IRQL to SYNCH level, set context swap busy for the old thread, and
; acquire the current PRCB lock.
;

ifndef NT_UP

call dword ptr [__imp__KeRaiseIrqlToSynchLevel@0] ; raise IRQL to SYNCH
mov byte ptr [edi].ThSwapBusy, 1 ; set context swap busy
lea ecx, [ebx].PcPrcbData.PbPrcbLock ; get PRCB lock address
lock bts dword ptr [ecx], 0 ; try to acquire PRCB lock
jnc short kdi50 ; if nc, PRCB lock acquired
fstCall KefAcquireSpinLockAtDpcLevel ; acquire current PRCB lock

endif

;
; Get the next thread address, set the thread state to running, queue the old
; running thread, and swap context to the next thread.
;

kdi50: mov esi, [ebx].PcPrcbData.PbNextThread ; get next thread address
and dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; clear next thread address
mov [ebx].PcPrcbData.PbCurrentThread, esi ; set current thread address
mov byte ptr [esi]+ThState, Running ; set thread state to running
mov byte ptr [edi].ThWaitReason, WrDispatchInt ; set wait reason
mov ecx, edi ; set address of curent thread
lea edx, [ebx].PcPrcbData ; set address of PRCB
fstCall KiQueueReadyThread ; ready thread for execution
CAPSTART <_KiDispatchInterrupt,SwapContext>
mov cl, APC_LEVEL ; set APC interrupt bypass disable
call SwapContext ; swap context

。。。

;
; Process quantum end event.
;
; N.B. If the quantum end code returns a NULL value, then no next thread
; has been selected for execution. Otherwise, a next thread has been
; selected and the source thread lock has been acquired.
;

kdi90: mov byte ptr [ebx].PcPrcbData.PbQuantumEnd, 0 ; clear quantum end indicator
CAPSTART <_KiDispatchInterrupt,_KiQuantumEnd@0>
stdCall _KiQuantumEnd ; process quantum end
CAPEND <_KiDispatchInterrupt>
stdRET _KiDispatchInterrupt ; return

第二部分:

VOID
KiQuantumEnd (
VOID
)
Routine Description:

This function is called when a quantum end event occurs on the current
processor. Its function is to determine whether the thread priority should
be decremented and whether a redispatch of the processor should occur.
当当前处理器上发生量子结束事件时,会调用此函数。
它的功能是确定是否应该降低线程优先级,以及是否应该重新分配处理器。

VOID
FASTCALL
KiQueueReadyThread (
IN PKTHREAD Thread,
IN PKPRCB Prcb
)
{

KxQueueReadyThread(Thread, Prcb);
return;
}


FORCEINLINE
VOID
KxQueueReadyThread (
IN PKTHREAD Thread,
IN PKPRCB Prcb
)

{

BOOLEAN Preempted;
KPRIORITY Priority;

ASSERT(Prcb == KeGetCurrentPrcb());
ASSERT(Thread->State == Running);
ASSERT(Thread->NextProcessor == Prcb->Number);

//
// If the thread can run on the specified processor, then insert the
// thread in the appropriate dispatcher ready queue for the specified
// processor and release the specified PRCB lock. Otherwise, release
// the specified PRCB lock and ready the thread for execution.
//

#if !defined(NT_UP)

if ((Thread->Affinity & Prcb->SetMember) != 0) {

#endif

Thread->State = Ready;
Preempted = Thread->Preempted;
Thread->Preempted = FALSE;
Thread->WaitTime = KiQueryLowTickCount();
Priority = Thread->Priority;

ASSERT((Priority >= 0) && (Priority <= HIGH_PRIORITY));

if (Preempted != FALSE) {
InsertHeadList(&Prcb->DispatcherReadyListHead[Priority],
&Thread->WaitListEntry);

} else {
InsertTailList(&Prcb->DispatcherReadyListHead[Priority],
&Thread->WaitListEntry);
}

Prcb->ReadySummary |= PRIORITY_MASK(Priority);

ASSERT(Priority == Thread->Priority);

KiReleasePrcbLock(Prcb);

#if !defined(NT_UP)

} else {
Thread->State = DeferredReady;
Thread->DeferredProcessor = Prcb->Number;
KiReleasePrcbLock(Prcb);
KiDeferredReadyThread(Thread);
}

#endif

return;
}

第三部分:

如果[ebx].PcPrcbData.PbNextThread=0则跳转到
kdi70: stdRET _KiDispatchInterrupt ; return
结束了,如果不为0则进行线程切换,
所以PcPrcbData.PbNextThread得真正含义是等待当前线程时间片用完就切换到NextThread

要切换到NextThread,需要两个条件,第一个是时间片用完,第二个是NextThread已经被选出来了。

;
; Check to determine if a new thread has been selected for execution on this
; processor.
;

cmp dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; check if next thread
je kdi70 ; if eq, then no new thread

;
; 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.
;

.fpo (0, 0, 0, 3, 1, 0)

sub esp, 3*4
mov [esp+8], esi ; save registers
mov [esp+4], edi ;
mov [esp+0], ebp ;
mov edi, [ebx].PcPrcbData.PbCurrentThread ; get current thread address (as old thread)

;
; Raise IRQL to SYNCH level, set context swap busy for the old thread, and
; acquire the current PRCB lock.
;

ifndef NT_UP

call dword ptr [__imp__KeRaiseIrqlToSynchLevel@0] ; raise IRQL to SYNCH
mov byte ptr [edi].ThSwapBusy, 1 ; set context swap busy
lea ecx, [ebx].PcPrcbData.PbPrcbLock ; get PRCB lock address
lock bts dword ptr [ecx], 0 ; try to acquire PRCB lock
jnc short kdi50 ; if nc, PRCB lock acquired
fstCall KefAcquireSpinLockAtDpcLevel ; acquire current PRCB lock

endif

;
; Get the next thread address, set the thread state to running, queue the old
; running thread, and swap context to the next thread.
;

kdi50: mov esi, [ebx].PcPrcbData.PbNextThread ; get next thread address
and dword ptr [ebx].PcPrcbData.PbNextThread, 0 ; clear next thread address
mov [ebx].PcPrcbData.PbCurrentThread, esi ; set current thread address
mov byte ptr [esi]+ThState, Running ; set thread state to running
mov byte ptr [edi].ThWaitReason, WrDispatchInt ; set wait reason
mov ecx, edi ; set address of curent thread
lea edx, [ebx].PcPrcbData ; set address of PRCB
fstCall KiQueueReadyThread ; ready thread for execution
CAPSTART <_KiDispatchInterrupt,SwapContext>
mov cl, APC_LEVEL ; set APC interrupt bypass disable
call SwapContext ; swap context
CAPEND <_KiDispatchInterrupt>
mov ebp, [esp+0] ; restore registers
mov edi, [esp+4] ;
mov esi, [esp+8] ;
add esp, 3*4
kdi70: stdRET _KiDispatchInterrupt ; return

第四部分:

1: kd> g
Breakpoint 14 hit
eax=00000041 ebx=f78e6d48 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b00720 esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt:
80b00720 648b1d1c000000 mov ebx,dword ptr fs:[1Ch] fs:0030:0000001c=f7737000
1: kd> x nt!KiQueueReadyThread
80a4412e nt!KiQueueReadyThread (struct _KTHREAD *, struct _KPRCB *)
1: kd> bp nt!KiQueueReadyThread
breakpoint 38 redefined
1: kd> dx -id 0,0,8954e020 -r1 ((ntkrnlmp!_KPRCB *)0xf7737120)
((ntkrnlmp!_KPRCB *)0xf7737120) : 0xf7737120 [Type: _KPRCB *]
[+0x000] MinorVersion : 0x1 [Type: unsigned short]
[+0x002] MajorVersion : 0x1 [Type: unsigned short]
[+0x004] CurrentThread : 0x8999d620 [Type: _KTHREAD *]
[+0x008] NextThread : 0x0 [Type: _KTHREAD *]

[+0x928] ReadySummary : 0x0 [Type: unsigned long]
[+0x92c] SelectNextLast : 0x0 [Type: unsigned long]
[+0x930] DispatcherReadyListHead [Type: _LIST_ENTRY [32]]
[+0xa30] DeferredReadyListHead [Type: _SINGLE_LIST_ENTRY]

1: kd> dx -id 0,0,8954e020 -r1 (*((ntkrnlmp!_KDPC_DATA (*)[2])0xf7737980))
(*((ntkrnlmp!_KDPC_DATA (*)[2])0xf7737980)) [Type: _KDPC_DATA [2]]
[0] [Type: _KDPC_DATA]
[1] [Type: _KDPC_DATA]
1: kd> dx -id 0,0,8954e020 -r1 (*((ntkrnlmp!_KDPC_DATA *)0xf7737980))
(*((ntkrnlmp!_KDPC_DATA *)0xf7737980)) [Type: _KDPC_DATA]
[+0x000] DpcListHead [Type: _LIST_ENTRY]
[+0x008] DpcLock : 0x0 [Type: unsigned long]
[+0x00c] DpcQueueDepth : 0x0 [Type: unsigned long]
[+0x010] DpcCount : 0xbb6 [Type: unsigned long]
1: kd> dx -id 0,0,8954e020 -r1 (*((ntkrnlmp!_SINGLE_LIST_ENTRY *)0xf7737b50))
(*((ntkrnlmp!_SINGLE_LIST_ENTRY *)0xf7737b50)) [Type: _SINGLE_LIST_ENTRY]
[+0x000] Next : 0x0 [Type: _SINGLE_LIST_ENTRY *]

1: kd> p
eax=00000041 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b00727 esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x7:
80b00727 fa cli
1: kd> !irql
Debugger saved IRQL for processor 0x1 -- 2 (DISPATCH_LEVEL)
1: kd> p
eax=00000041 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b00728 esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0x8:
80b00728 8b838c090000 mov eax,dword ptr [ebx+98Ch] ds:0023:f773798c=00000000
1: kd> p
eax=00000000 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b0072e esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0xe:
80b0072e 0b83c8090000 or eax,dword ptr [ebx+9C8h] ds:0023:f77379c8=00000000
1: kd> p
eax=00000000 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b00734 esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0x14:
80b00734 0b83500b0000 or eax,dword ptr [ebx+0B50h] ds:0023:f7737b50=00000000
1: kd> p
eax=00000000 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b0073a esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0x1a:
80b0073a 741e je nt!KiDispatchInterrupt+0x3a (80b0075a) [br=1]
1: kd> p
eax=00000000 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b0075a esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up di pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000046
nt!KiDispatchInterrupt+0x3a:
80b0075a fb sti
1: kd> p
eax=00000000 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b0075b esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x3b:
80b0075b 80bbe109000000 cmp byte ptr [ebx+9E1h],0 ds:0023:f77379e1=00
1: kd> bp 80b0075b
1: kd> p
eax=00000000 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b00762 esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x42:
80b00762 7577 jne nt!KiDispatchInterrupt+0xbb (80b007db) [br=0]
1: kd> p
eax=00000000 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b00764 esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x44:
80b00764 83bb2801000000 cmp dword ptr [ebx+128h],0 ds:0023:f7737128=00000000
1: kd> p
eax=00000000 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b0076b esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0x4b:
80b0076b 746d je nt!KiDispatchInterrupt+0xba (80b007da) [br=1]
1: kd> p
eax=00000000 ebx=f7737000 ecx=8999d620 edx=80010031 esi=00000000 edi=804edc60
eip=80b007da esp=f78e6c9c ebp=f78e6ca0 iopl=0 nv up ei pl zr na pe nc
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00000246
nt!KiDispatchInterrupt+0xba:
80b007da c3 ret

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/25 8:19:03

33、文本处理与脚本编程的全面指南

文本处理与脚本编程的全面指南 1. 符号与运算符 在文本处理和脚本编程中,各种符号和运算符起着关键作用。以下是一些常见符号及其用途: | 符号 | 用途 | | — | — | | & | 逻辑与运算符 && 用于逻辑判断,在替换文本中也有特定作用 | | * | 作为元字…

作者头像 李华
网站建设 2026/5/27 19:10:36

如何通过Kotaemon降低人工客服工作量30%?

如何通过Kotaemon降低人工客服工作量30%&#xff1f; 在客户期望“秒回”的今天&#xff0c;企业客服系统正面临前所未有的压力。一边是不断攀升的咨询量&#xff0c;一边是人力成本和响应延迟的双重挤压——尤其是在电商大促、金融产品上线或电信资费调整这类高峰期&#xff0…

作者头像 李华
网站建设 2026/5/29 13:01:13

不只是检索增强——Kotaemon智能代理的多维能力

不只是检索增强——Kotaemon智能代理的多维能力 在企业级AI应用日益深入的今天&#xff0c;一个简单的“你问我答”式聊天机器人早已无法满足业务需求。用户不再满足于模糊的回答&#xff0c;而是期望系统能准确调取内部知识、理解复杂意图、执行具体操作&#xff0c;甚至主动引…

作者头像 李华
网站建设 2026/5/29 3:54:12

用Kotaemon训练专属行业Agent:操作步骤详解

用Kotaemon训练专属行业Agent&#xff1a;操作步骤详解 在金融、医疗、法律等专业领域&#xff0c;一个能准确回答“上季度财报中毛利率变动原因”或“某药品最新适应症是否纳入医保”的智能助手&#xff0c;远比只会讲冷笑话的通用聊天机器人更有价值。然而现实是&#xff0c;…

作者头像 李华
网站建设 2026/5/26 13:22:04

Kotaemon能否提取专利创新点?技术研发情报挖掘

Kotaemon能否提取专利创新点&#xff1f;技术研发情报挖掘 在半导体、新能源、生物医药等高技术领域&#xff0c;一项关键专利的出现往往能重塑整个行业格局。然而&#xff0c;面对全球每年数百万件新增专利&#xff0c;研发团队如何快速识别真正具有突破性的技术创新&#xff…

作者头像 李华
网站建设 2026/5/26 16:26:06

如何通过Kotaemon优化大模型token使用效率?

如何通过Kotaemon优化大模型token使用效率&#xff1f; 在当前的大模型应用开发中&#xff0c;一个看似不起眼却直接影响系统成本与响应速度的问题正日益凸显&#xff1a;token的浪费。尤其是在构建智能客服、知识问答或企业级AI助手时&#xff0c;开发者常常面临这样的尴尬—…

作者头像 李华