一、KeInsertQueueApc(调用 KiInsertQueueApc)
BOOLEAN
KeInsertQueueApc (
IN PRKAPC Apc,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2,
IN KPRIORITY Increment
)
/*++
Routine Description:
This function inserts an APC object into the APC queue specifed by the
thread and processor mode fields of the APC object. If the APC object
is already in an APC queue or APC queuing is disabled, then no operation
is performed. Otherwise the APC object is inserted in the specified queue
and appropriate scheduling decisions are made.
插入 APC 到指定线程的APC队列,用户态和内核态分别插入对应的 APC 队列。
如果 APC 对象已经在 APC 队列或者 APC 队列被禁用(例如线程正在退出),
则不执行操作。否则插入 APC 对象并调用相应的函数。
Arguments:
Apc - Supplies a pointer to a control object of type APC.
APC 结构
SystemArgument1, SystemArgument2 - Supply a set of two arguments that
contain untyped data provided by the executive.
传给 APC 函数的参数。
Increment - Supplies the priority increment that is to be applied if
queuing the APC causes a thread wait to be satisfied.
线程优先级增量
Return Value:
If the APC object is already in an APC queue or APC queuing is disabled,
then a value of FALSE is returned. Otherwise a value of TRUE is returned.
--*/
{
BOOLEAN Inserted;
KLOCK_QUEUE_HANDLE LockHandle;
KIRQL OldIrql;
PRKTHREAD Thread;
ASSERT_APC(Apc);
ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
//
// Raise IRQL to SYNCH_LEVEL, acquire the thread APC queue lock, and lock
// the dispatcher database.
// 提升 IRQL 等级,申请 APC 锁,锁 dispatcher database
Thread = Apc->Thread;
KeAcquireInStackQueuedSpinLockRaiseToSynch(&Thread->ApcQueueLock, &LockHandle);
KiLockDispatcherDatabaseAtSynchLevel();
//
// If APC queuing is disabled, then set inserted to FALSE. Else save
// system parameter values in APC object, and attempt to queue APC.
// 调用 KiInsertQueueApc
if (Thread->ApcQueueable == FALSE) {
Inserted = FALSE;
} else {
Apc->SystemArgument1 = SystemArgument1;
Apc->SystemArgument2 = SystemArgument2;
Inserted = KiInsertQueueApc(Apc, Increment);
}
//
// Unlock the dispatcher database from SYNCH_LEVEL, unlock the thread APC
// queue lock and lower IRQL to its previous value, and return whether the
// APC was inserted.
//
KiUnlockDispatcherDatabaseFromSynchLevel();
KeReleaseInStackQueuedSpinLock(&LockHandle);
return Inserted;
}
二、KiInsertQueueApc
BOOLEAN
FASTCALL
KiInsertQueueApc (
IN PKAPC Apc,
IN KPRIORITY Increment
)
/*++
Routine Description:
This function inserts an APC object into a thread's APC queue. The address
of the thread object, the APC queue, and the type of APC are all derived
from the APC object. If the APC object is already in an APC queue, then
no opertion is performed and a function value of FALSE is returned. Else
the APC is inserted in the specified APC queue, its inserted state is set
to TRUE, and a function value of TRUE is returned. The APC will actually
be delivered when proper enabling conditions exist.
N.B. The thread APC queue lock and the dispatcher database lock must both
be held when this routine is called.
Arguments:
Apc - Supplies a pointer to a control object of type APC.
Increment - Supplies the priority increment that is to be applied if
queuing the APC causes a thread wait to be satisfied.
Return Value:
If the APC object is already in an APC queue, then a value of FALSE is
returned. Else a value of TRUE is returned.
--*/
{
KPROCESSOR_MODE ApcMode;
PKAPC ApcEntry;
PKAPC_STATE ApcState;
BOOLEAN Inserted;
PLIST_ENTRY ListEntry;
PKTHREAD Thread;
//
// If the APC object is already in an APC queue, then set inserted to
// FALSE. Else insert the APC object in the proper queue, set the APC
// inserted state to TRUE, check to determine if the APC should be delivered
// immediately, and set inserted to TRUE.
//
// For multiprocessor performance, the following code utilizes the fact
// that kernel APC disable count is incremented before checking whether
// the kernel APC queue is nonempty.
//
// See KeLeaveCriticalRegion().
//
Thread = Apc->Thread;
if (Apc->Inserted) {
Inserted = FALSE;
} else {
//typedef enum _KAPC_ENVIRONMENT {
// OriginalApcEnvironment, // 所属进程(创建线程的进程,父进程)
// AttachedApcEnvironment, // 挂靠进程
// CurrentApcEnvironment, // 当前环境,提供CR3的进程(正常状态是所属进程,挂靠状态是挂靠进程)
// InsertApcEnvironment // 插入APC时的环境
//} KAPC_ENVIRONMENT;
// Apc->ApcStateIndex 是在 KeInitializeApc 函数内初始化的,它的值决定了插入到哪个进程的APC队列(所属进程 还是 挂靠进程)
//
// 终止线程的 PspTerminateThreadByPointer 和3环 QueueUserApc , Apc->ApcStateIndex 都是 0
// 0意味着选择所属进程,因为不挂靠时 ApcStatePointer[0] 是所属线程;挂靠时 ApcStatePointer[0] 还是所属线程的备份
if (Apc->ApcStateIndex == InsertApcEnvironment) {
// 插入前实时地从 Thread 里取
//设计 InsertApcEnvironment 也许是考虑到初始化时和插入前线程的状态可以发生改变
Apc->ApcStateIndex = Thread->ApcStateIndex;
}
ApcState = Thread->ApcStatePointer[Apc->ApcStateIndex];
//
// Insert the APC after all other special APC entries selected by
// the processor mode if the normal routine value is NULL. Else
// insert the APC object at the tail of the APC queue selected by
// the processor mode unless the APC mode is user and the address
// of the special APC routine is exit thread, in which case insert
// the APC at the front of the list and set user APC pending.
//
ApcMode = Apc->ApcMode; // 内核APC or 用户APC
if (Apc->NormalRoutine != NULL) {
// NormalRoutine 非空,就在这里插入
// NormalRoutine 是 所有用户APC函数的入口 或者 内核APC函数,取决于APC是用户模式还是内核模式
if ((ApcMode != KernelMode) && (Apc->KernelRoutine == PsExitSpecialApc)) {
// 是用户APC,并且 KernelRoutine == PsExitSpecialApc ,3环调用 QueueUserApc 就是这种情况
// 标记已插入
Thread->ApcState.UserApcPending = TRUE;
// 插入到队列头部
InsertHeadList(&ApcState->ApcListHead[ApcMode],
&Apc->ApcListEntry);
} else {
// 内核APC,比较简单,直接插入队列尾部
InsertTailList(&ApcState->ApcListHead[ApcMode],
&Apc->ApcListEntry);
}
} else {
// NormalRoutine 是 NULL ,走这里
// 从队尾开始遍历 APC 队列
// 直到找到下一个 NormalRoutine 为空的APC
ListEntry = ApcState->ApcListHead[ApcMode].Blink;
while (ListEntry != &ApcState->ApcListHead[ApcMode]) {
ApcEntry = CONTAINING_RECORD(ListEntry, KAPC, ApcListEntry);
if (ApcEntry->NormalRoutine == NULL) {
break;
}
ListEntry = ListEntry->Blink;
}
// 插入到队列头部
InsertHeadList(ListEntry, &Apc->ApcListEntry);
}
// 插入成功
Apc->Inserted = TRUE;
//
// If the APC index from the APC object matches the APC Index of
// the thread, then check to determine if the APC should interrupt
// thread execution or sequence the thread out of a wait state.
//
// 条件成立,APC 和当前线程使用同一个进程
// 要么没有attach,APC插入了所属进程
// 要么attach了,APC插入的也是挂靠的进程
if (Apc->ApcStateIndex == Thread->ApcStateIndex) {
//
// If the processor mode of the APC is kernel, then check if
// the APC should either interrupt the thread or sequence the
// thread out of a Waiting state. Else check if the APC should
// sequence the thread out of an alertable Waiting state.
//
if (ApcMode == KernelMode) {
// 标记已插入内核APC
Thread->ApcState.KernelApcPending = TRUE;
if (Thread->State == Running) {
// 如果线程正在运行,则 APC 中断
KiRequestApcInterrupt(Thread->NextProcessor);
} else if ((Thread->State == Waiting) && // 线程阻塞(等待)
(Thread->WaitIrql == 0) &&
((Apc->NormalRoutine == NULL) ||
((Thread->KernelApcDisable == 0) &&
(Thread->ApcState.KernelApcInProgress == FALSE)))) // 没有正在执行的 APC
{
// 修改线程状态为就绪,提升优先级
KiUnwaitThread(Thread, STATUS_KERNEL_APC, Increment, NULL);
}
} else if ((Thread->State == Waiting) && // 线程处于阻塞状态
(Thread->WaitMode == UserMode) && // 用户导致的阻塞
(Thread->Alertable || Thread->ApcState.UserApcPending)) // 是否可以被APC唤醒或者已经插入,SleepEx 可以设置 Alertable
{
Thread->ApcState.UserApcPending = TRUE;
// 修改线程状态为就绪,提升优先级
KiUnwaitThread(Thread, STATUS_USER_APC, Increment, NULL);
}
}
Inserted = TRUE;
}
//
// Return whether the APC object was inserted in an APC queue.
//
return Inserted;
}
---------------------
作者:hambaga
来源:CSDN
原文:https://blog.csdn.net/Kwansy/article/details/110285374
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件