APC插入:KeInsertQueueApc(位于:ntoskrnl/ke/apc.c
):
- 判断Apc是否可插入:线程是否可插入,Apc是否已插入
- 如果可插入,就把参数设置给Apc,修改Apc插入标识,调用KiInsertQueueApc
- 如果不可插入,设置返回值为FALSE
APC插入:KiInsertQueueApc(位于:ntoskrnl/ke/apc.c
):
- 如果有NormalRoutine,说明是普通APC
- 如果是用户模式的退出线程APC,就插入到APC链表首位
- 如果是普通APC(用户模式或内核模式),就插入到对应APC链表最后
- 如果没NormalRoutine,说明是特殊内核APC
- 找到内核APC链表中特殊APC部分的最后一个成员,插入(插入到特殊APC队列的最后)
- 检查APC状态索引是否和线程匹配,一般是匹配的
- 如果APC归属线程是当前线程,且线程正在运行
- 如果是内核模式APC,就设置线程APC状态内核APC挂起标识
- 如果线程没有禁用特殊APC,就调用HalRequestSoftwareInterrupt请求软中断间接调用KiDeliverApc,来执行APC。
- 如果是内核模式APC,就设置线程APC状态内核APC挂起标识
- 如果不是当前线程
- 获取程序调度锁
- 如果APC是内核模式
- 设置内核APC挂起标识为1
- 如果线程正在运行
- 设置请求中断标识为1
- 如果线程为等待状态
- 设置状态为STATUS_KERNEL_APC,然后唤醒线程
- 如果线程为门等待
- 从等待链表中摘链,设置线程等待状态为STATUS_KERNEL_APC,然后调用KiInsertDeferredReadyList把线程设置为延时的就绪状态
- 如果APC是用户模式,线程为等待状态
- 设置用户APC挂起标识为1
- 设置状态为STATUS_USER_APC
- 唤醒线程
- 释放程序调度锁
- 请求APC中断(参数是请求中断标识)
简单来说:
如果可插入,则根据APC类型插入到对应的APC队列里,然后判断线程状态:
- 如果当前的线程就是APC归属线程,如果是内核模式就设置标识然后请求中断,执行APC
- 如果当前的线程不是APC归属线程
- 如果是内核模式,线程正在运行就设置请求中断标识,最后请求APC中断,线程正在等待就设置内核APC状态并唤醒线程
- 如果是用户模式,线程正在等待就设置用户APC状态并唤醒线程
这也说明了一点,用户APC插入后得不到立即执行,内核APC插入后会被中断执行APC
KeInsertQueueApc
/*++
* @name KeInsertQueueApc
* @implemented NT4
*
* The KeInsertQueueApc routine queues a APC for execution when the right
* scheduler environment exists.
*
* @param Apc
* Pointer to an initialized control object of type APC for which the
* caller provides the storage.
*
* @param SystemArgument[1,2]
* Pointer to a set of two parameters that contain untyped data.
*
* @param PriorityBoost
* Priority Boost to apply to the Thread.
*
* @return If the APC is already inserted or APC queueing is disabled, FALSE.
* Otherwise, TRUE.
*
* @remarks The APC will execute at APC_LEVEL for the KernelRoutine registered,
* and at PASSIVE_LEVEL for the NormalRoutine registered.
*
* Callers of this routine must be running at IRQL <= DISPATCH_LEVEL.
*
*--*/
// 判断能不能插入,然后调入内部函数
BOOLEAN
NTAPI
KeInsertQueueApc(IN PKAPC Apc,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2,
IN KPRIORITY PriorityBoost)
{
PKTHREAD Thread = Apc->Thread;
KLOCK_QUEUE_HANDLE ApcLock; // APC锁
BOOLEAN State = TRUE;
ASSERT_APC(Apc); // 测试APC是否有效
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); // 断言IRQL
/* Get the APC lock */
// 获取APC 锁
KiAcquireApcLock(Thread, &ApcLock); // ree
/* Make sure we can Queue APCs and that this one isn't already inserted */
// 判断APC是否可以插入,如果线程可插入标识为0,或者Apc插入标识为1,就设置返回值为FALSE
if (!(Thread->ApcQueueable) || (Apc->Inserted))
{
/* Fail */
// 插入不了
State = FALSE;
}
else
{
// 可以插入
/* Set the System Arguments and set it as inserted */
// 获取两个参数给Apc,Apc插入状态设置为已插入
Apc->SystemArgument1 = SystemArgument1;
Apc->SystemArgument2 = SystemArgument2;
Apc->Inserted = TRUE;
/* Call the Internal Function */
// 调用内部函数
KiInsertQueueApc(Apc, PriorityBoost);
}
/* Release the APC lock and return success */
// 释放APC锁,返回
KiReleaseApcLockFromDpcLevel(&ApcLock); // ree
KiExitDispatcher(ApcLock.OldIrql);
return State;
}
KiInsertQueueApc
/*++
* @name KiInsertQueueApc
*
* The KiInsertQueueApc routine queues a APC for execution when the right
* scheduler environment exists.
*
* @param Apc
* Pointer to an initialized control object of type APC for which the
* caller provides the storage.
*
* @param PriorityBoost
* Priority Boost to apply to the Thread.
*
* @return None
*
* @remarks The APC will execute at APC_LEVEL for the KernelRoutine registered,
* and at PASSIVE_LEVEL for the NormalRoutine registered.
*
* Callers of this routine must have locked the dipatcher database.
*
*--*/
VOID
FASTCALL
KiInsertQueueApc(IN PKAPC Apc,
IN KPRIORITY PriorityBoost)
{
PKTHREAD Thread = Apc->Thread; // 获取线程
PKAPC_STATE ApcState;
KPROCESSOR_MODE ApcMode;
PLIST_ENTRY ListHead, NextEntry;
PKAPC QueuedApc;
PKGATE Gate;
NTSTATUS Status;
BOOLEAN RequestInterrupt = FALSE;
/*
* Check if the caller wanted this APC to use the thread's environment at
* insertion time.
*/
// 判断Apc状态索引是不是等于InsertApcEnvironment,_KAPC_ENVIRONMENT枚举类型的最后一个
if (Apc->ApcStateIndex == InsertApcEnvironment)
{
/* Copy it over */
// 线程的APC索引设置给Apc的索引
// 如果说Apc = insert,索引值(3)跟需求不一样,就需要从线程里把线程的索引拿来
Apc->ApcStateIndex = Thread->ApcStateIndex;
}
/* Get the APC State for this Index, and the mode too */
// 获取线程的APC状态
ApcState = Thread->ApcStatePointer[(UCHAR)Apc->ApcStateIndex];
// 获取Apc的Apc模式
ApcMode = Apc->ApcMode;
/* The APC must be "inserted" already */
// 到这里APC必须是这个标志
ASSERT(Apc->Inserted == TRUE);
/* Three scenarios:
* 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List
带有 NormalRoutine 回调的APC,属于正常APC,放到链表最后
* 2) User APC which is PsExitSpecialApc = Put it at the front of the List
如果用户APC是退出线程的APC,放在最前面,加急处理
* 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list
没有NormalRoutine回调的内核APC,也是特殊加急APC,放在加急APC链表最后
*/
// 这个if-else处理逻辑是进行插入操作的,普通APC插入链表尾部,特殊APC插入特殊APC链表尾部,退出线程APC插入链表头部
// Apc 有无 NormalRoutine
if (Apc->NormalRoutine) // 如果有 NormalRoutine,说明是非特殊APC
{
/* Normal APC; is it the Thread Termination APC? */
// 判断是用户模式,且是退出线程APC,这是个特例
if ((ApcMode != KernelMode) &&
(Apc->KernelRoutine == PsExitSpecialApc))
{
/* Set User APC pending to true */
// 设置状态
Thread->ApcState.UserApcPending = TRUE;
/* Insert it at the top of the list */
// 头插链表
InsertHeadList(&ApcState->ApcListHead[ApcMode],
&Apc->ApcListEntry);
}
else
{
/* Regular user or kernel Normal APC */
// 普通APC,插入到链表最后
InsertTailList(&ApcState->ApcListHead[ApcMode],
&Apc->ApcListEntry);
}
}
else // 如果无 NormalRoutine,说明是特殊APC
{
/* Special APC, find the last one in the list */
ListHead = &ApcState->ApcListHead[ApcMode]; // 链表首成员
NextEntry = ListHead->Blink; // 链表最后一个成员
while (NextEntry != ListHead)
{
/* Get the APC */
// 获取APC
QueuedApc = CONTAINING_RECORD(NextEntry, KAPC, ApcListEntry);
/* Is this a No-Normal APC? If so, break */
// 没有这个回调函数就跳出,如果有就指向上一个
// 找到加急链表最后一个
// 正常APC有NormalRoutine这个,找到一个没的,就是加急APC的尾部
if (!QueuedApc->NormalRoutine)
break;
/* Move to the previous APC in the Queue */
// 链表从后往前遍历
NextEntry = NextEntry->Blink;
}
/* Insert us here */
InsertHeadList(NextEntry, &Apc->ApcListEntry);
}
// 检查Apc状态索引是否匹配
/* Now check if the Apc State Indexes match */
if (Thread->ApcStateIndex == Apc->ApcStateIndex)
{
/* Check that the thread matches */
// 如果线程是当前线程
if (Thread == KeGetCurrentThread())
{
/* Sanity check */
// 并且线程在运行状态
ASSERT(Thread->State == Running);
/* Check if this is kernel mode */
// 判断APC是不是内核模式
if (ApcMode == KernelMode)
{
/* All valid, a Kernel APC is pending now */
// 设置标志
Thread->ApcState.KernelApcPending = TRUE;
/* Check if Special APCs are disabled */
// 检查是否禁用特殊APC
if (!Thread->SpecialApcDisable)
{
// 如果没有就中断
/* They're not, so request the interrupt */
// 则调用HalRequestSoftwareInterrupt请求软中断间接调用KiDeliverApc,来执行APC。
HalRequestSoftwareInterrupt(APC_LEVEL);
}
}
}
else //如果不是当前线程
{
// 获取程序调度锁
/* Acquire the dispatcher lock */
KiAcquireDispatcherLock();
// 判断内核模式
/* Check if this is a kernel-mode APC */
if (ApcMode == KernelMode)
{
/* Kernel-mode APC, set us pending */
Thread->ApcState.KernelApcPending = TRUE;
/* Are we currently running? */
if (Thread->State == Running)
{
/* The thread is running, so remember to send a request */
// 请求中断标志设置为True
RequestInterrupt = TRUE;
}
// 等待状态
else if ((Thread->State == Waiting) && // 线程为等待状态
(Thread->WaitIrql == PASSIVE_LEVEL) && // 等待IRQL = PASSIVE_LEVEL
!(Thread->SpecialApcDisable) && // 特殊APC禁用标识没有设置
(!(Apc->NormalRoutine) || // 无NormalRoutine
(!(Thread->KernelApcDisable) && // 线程内核APC禁用标识没有设置
!(Thread->ApcState.KernelApcInProgress)))) // 线程APC状态内核APC执行标志没有设置
{
/* We'll unwait with this status */
// 在这个状态下不等待
Status = STATUS_KERNEL_APC;
/* Wake up the thread */
// 唤醒线程
KiUnwaitThread(Thread, Status, PriorityBoost);
}
else if (Thread->State == GateWait) // 线程如果是门等待状态
{
/* Lock the thread */
// 锁线程
KiAcquireThreadLock(Thread);
// 门等待状态
/* Essentially do the same check as above */
if ((Thread->State == GateWait) && // 线程为门等待状态
(Thread->WaitIrql == PASSIVE_LEVEL) && // 线程等待IRQL为PASSIVE_LEVEL
!(Thread->SpecialApcDisable) && // 线程特殊APC禁用标识没设置
(!(Apc->NormalRoutine) || // APC没有NormalRoutine
(!(Thread->KernelApcDisable) && // 线程内核APC禁用标识没设置
!(Thread->ApcState.KernelApcInProgress)))) // 线程APC状态内核APC执行标识没设置
{
/* We were in a gate wait. Handle this. */
DPRINT1("A thread was in a gate wait\n");
// 设置门
/* Get the gate */
Gate = Thread->GateObject;
// 锁门
/* Lock the gate */
KiAcquireDispatcherObject(&Gate->Header);
// 删除当前结点
/* Remove it from the waiters list */
RemoveEntryList(&Thread->WaitBlock[0].WaitListEntry);
// 解锁
/* Unlock the gate */
KiReleaseDispatcherObject(&Gate->Header);
// 线程队列有效就自增
/* Increase the queue counter if needed */
if (Thread->Queue)
Thread->Queue->CurrentCount++;
// 设置线程等待状态
/* Put into deferred ready list with this status */
Thread->WaitStatus = STATUS_KERNEL_APC;
KiInsertDeferredReadyList(Thread);
}
/* Release the thread lock */
KiReleaseThreadLock(Thread);
}
}
// 用户等待模式
else if ((Thread->State == Waiting) && // 线程在等待状态
(Thread->WaitMode == UserMode) && // 线程等待模式为用户模式
((Thread->Alertable) || // 线程状态为Alertable
(Thread->ApcState.UserApcPending))) // 或 线程APC状态为用户APC挂起
{
/* Set user-mode APC pending */
// 设置用户APC挂起标记
Thread->ApcState.UserApcPending = TRUE;
// 状态设置为用户APC
Status = STATUS_USER_APC;
/* Wake up the thread */
// 唤醒线程
KiUnwaitThread(Thread, Status, PriorityBoost);
}
/* Release dispatcher lock */
// 释放调度锁
KiReleaseDispatcherLockFromDpcLevel();
/* Check if an interrupt was requested */
// 请求APC中断
KiRequestApcInterrupt(RequestInterrupt, Thread->NextProcessor);
}
}
}