首先检查目标线程是不是当前线成 然后将切换的目标进程堆栈+1 之后保存当前线成apc到SavedApcState 初始化当前线程的apc链 其中包括内核链和用户链
InitializeListHead(&Thread->ApcState.ApcListHead[KernelMode]);
InitializeListHead(&Thread->ApcState.ApcListHead[UserMode]);
修改线成的apc的Process修改为目标线程 apc的progress,用户和内核的pending设置成false
Thread->ApcState.Process = Process;
Thread->ApcState.KernelApcInProgress = FALSE;
Thread->ApcState.KernelApcPending = FALSE;
Thread->ApcState.UserApcPending = FALSE;
检查线程保存的 APC 状态 也就是Thread->SavedApcState 是否与保存的SavedApcState APC装 态相等 如相等则:
&Thread->SavedApcState、&Thread->ApcState 分别赋与当前线程的 ApcStatePointer[0] 与 ApcStatePointer[1]
ApcStatePointer是KAPC_STATE 结构数组 并将当前apc所以设置成为1 这里是为了保存当前线程的apc 为了不交其影响到目标进程的apc也就是切换的进程 待推出后再恢复apc
在KeDetachProcess有这样一段代码用来恢复线成的apc
KiMoveApcState(&Thread->SavedApcState, &Thread->ApcState);
Thread->SavedApcState.Process = (PKPROCESS)NULL;
Thread->ApcStatePointer[0] = &Thread->ApcState;
Thread->ApcStatePointer[1] = &Thread->SavedApcState;
Thread->ApcStateIndex = 0;
这里apc才能够得以运行 接着 如果目标线成在内存中 就把目标线程的就绪队列中的线成逐一地分配 NextEntry = Process->ReadyListHead.Flink;
while (NextEntry != &Process->ReadyListHead){
OutThread = CONTAINING_RECORD(NextEntry, KTHREAD, WaitListEntry);
RemoveEntryList(NextEntry);
OutThread->ProcessReadyQueue = FALSE;
KiReadyThread(OutThread);
NextEntry = Process->ReadyListHead.Flink;
}
利用RemoveEntryList(NextEntry)将节点从就绪队列中移除 KiReadyThread 是为了叫线程抢占别的别的线程 尽可能优先执行
然后调用KiSwapProcess(Process, SavedApcState->Process)(把原进程切换到目标进程 这段代码没分析过 只是知道是切换进程 其中从新装载进程的cr3 建立tss的i/o位图 将选择子加载)如果进程不在内存之中 就将线程地等待连插入到 进程的就绪队列中
InsertTailList(&Process->ReadyListHead, &Thread->WaitListEntry)
然后检查Process->State == ProcessOutOfMemory 如果成立说明进程已经被切换出内存
将进程的交换连插入到进程交换连 也就是系统维护地交换连 并将进程设置为等待交换
Process->State = ProcessInTransition;
InsertTailList(&KiProcessInSwapListHead, &Process->SwapListEntry)
设置交换事件的状态量 说明有要交换的对象
KiSwapEvent.Header.SignalState = 1;
这里判断交换事件的等待对象是不是空 如果是 空那么就继续进行进一步判断 交换事件的剩余量
if (IsListEmpty(&KiSwapEvent.Header.WaitListHead) == FALSE) {
KiWaitTest(&KiSwapEvent, BALANCE_INCREMENT);
}
之后调用KiSwapThread 线程切换到另一个进程空间的整个过程