APC是运行在APC_level irql 上的内核机制。win2k下APC当作object来管理,在内核中定义的相应数据结构是KAPC 如下:
typedef struct _KAPC {
CSHORT Type;//对象类型,这里应该是ApcObject
CSHORT Size;//KAPC结构的大小,应该为sizeof(KAPC)
ULONG Spare0;
struct _KTHREAD *Thread;--》这个thread是此APC的owner
LIST_ENTRY ApcListEntry//指向下一个apc object,all APC object list as one double linked list
PKKERNEL_ROUTINE KernelRoutine;//指向一个函数,在apc_level irql时在内核台运行
PKRUNDOWN_ROUTINE RundownRoutine;//指向一个例程,如果这个apc在某个线程的apc队列中,那么当这个线程终止时,该例程被执行(可选)
PKNORMAL_ROUTINE NormalRoutine;//指向一个例程,在passive_level irql且指定的处理器模式上运行该例程
PVOID NormalContext;//传递给NormalRoutine的参数1
//
// N.B. The following two members MUST be together.
//
PVOID SystemArgument1;//传递给NormalRoutine的参数2
PVOID SystemArgument2;//传递给NormalRoutine的参数3
CCHAR ApcStateIndex;//是它指向的thread 的ApcStatePointer[2]数组的index(0 or 1)
KPROCESSOR_MODE ApcMode;//该apc对象的处理器模式:kernel mode 或者user mode
BOOLEAN Inserted;//该apc是否插入线程的apc队列
} KAPC, *PKAPC, *RESTRICTED_POINTER PRKAPC;
thread object中有几个项是关于apc的,分别是:
typedef struct _KTHREAD {
.....................
KAPC_STATE ApcState;//该thread当前运行时候维持的apc对象queue,有两个列表kernel mode 和user mode。这就是ApcStatePointer[ApcStateIndex]指向的那个apc state
..............................
PKAPC_STATE ApcStatePointer[2];//对应于起始apc环境和attach一个新进程后的apc环境
.....................
KAPC_STATE SavedApcState;//当该thread attach到一个新process时候,保存原始的apc state,然后ApcStateIndex=1,创建一个新的apc state放在ApcStatePointe[1]中
..................................
UCHAR ApcStateIndex;//这个thread object中ApcStatePointer[2]的index
..................
}
这里KAPC_STATE ApcState是一个新的数据结构。定义为:
typedef struct _KAPC_STATE {
LIST_ENTRY ApcListHead[MaximumMode];//分成2个list,kernel mode和user mode。分别连接着一个douible linked list的APC对象
struct _KPROCESS *Process;//指向拥有这个apc的thread object的所属process
BOOLEAN KernelApcInProgress;//标志,kernel apc正在处理状态
BOOLEAN KernelApcPending;
BOOLEAN UserApcPending;
} KAPC_STATE, *PKAPC_STATE, *RESTRICTED_POINTER PRKAPC_STATE;
这
样win2k利用这3个数据结构管理apc对象。在创建thread的时候初始化thread object中的ApcStatePointer[0]=
threadobject的 ApcState,ApcStateIndex=0。当以后线程attach到别的process上的时候,则创建一个新的
apc对象并设置ApcStatePointer[0]=SaveedApcState, ApcStatePointer[1]=新创建的
apc object,ApcStateIndex=1;表示现在线程运行的apc环境是新attach的process.
任何时候thread object的ApcState都是当前线程管理的apc队列,而就是ApcStatePointer[apcstateIndex]指向的apc state.
apc state
利用里面的LIST_ENTRYApcListHead和apc object结构里的ApcListEntry,将当前运行在该apc state上的
apc对象连接起来。每个apc object的thread指针正好指向拥有这个apc对象的线程对象。这个关系很有点绕人,最好还是画个图才能表示清
楚。
可以调用KeInitializeApc来创建一个新的apc object,这个函数很简单。就是设置KAPC结构的一系列
element.KeInsertQueueApc将一个apc插入到线程的apc队列中。首先验证当前的irql小于dispatch_level,然
后得到thread=apc->thread,如果thread不允许排队apc(->ApcQueueable == FALSE) ,则
设置apc->Inserted=false推出并返回false,否则调用KiInsertQueueApc完成插入工作,最后返回TRUE .
KiInsertQueueApc
主要就是根据apc的apcmode将这个apc插入到指定thread的apcStatePointer[apc->
apcStateIndex]—>apcListHead[apc->apcMode]中去。并根据情况中断这个指定thread的运行或者
取消这个线程的等待状态。
当发生apc中断时,最终都将调用KiDeliverApc来deliver线程上排队的apc对象,执行apc对象上
指定的routines(包括KernelRoutine和NormalRoutine),KiDeliverApc首先
deliver kernel apc,然后再user apc。
文章评论(0条评论)
登录后参与讨论