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。