3.讲完了进程和线程之后,我们的核心问题块来临了,操作系统到底是采用什么策略进行进程或线程调度的,也就是决定让哪个线程或者进程进入到CPU里面去执行。在讲这个问题之前我们还有一个很重要的上课讲的内容,进程或者线程切换的时候,我们如何保存其运行信息?
3.1线程的切换
我花费好几个小时去找这个的内容,因为我借的两本书上都没讲代码,而是直接给出了原理和答案,好在我还是找到了线程切换的一部分代码,但是我看了之后真的是发现好痛苦,不同的处理器体系结构代码是不同的,下面我以简单i386体系结构为例,来简单的描述一下操作系统是如何进程线程切换的,这里涉及到了很多的概念和内容,是需要对前面的内容进程拓展才能理解清楚的,相关方面的内容只能是自己去看书了。在WRK-v1.2\base\ntos\ke\amd64\Ctxswap.asm里面我们终于看到了代码:
includeksamd64.inc
......
;BOOLEAN
;KiSwapContext (
; IN PKTHREAD OldThread,
; IN PKTHREAD NewThread
; )
NESTED_ENTRY KiSwapContext, _TEXT$00
GENERATE_EXCEPTION_FRAME ; 生成异常页
mov rbx, gs:[PcCurrentPrcb] ; 获得当前PRCB地址
mov rdi, rcx ; 旧线程地址换到rdi中
mov rsi, rdx ; 新线程地址换到rsi总
movzx ecx, byte ptr ThWaitIrql[rdi] ; 禁止APC机制的中断影响
call SwapContext ; //调用SwapContext
RESTORE_EXCEPTION_STATE ;
ret ; 返回
NESTED_END KiSwapContext, _TEXT$00
subttl "Dispatch Interrupt"
/*这段程序是作为一个发生在 DISPATCH_LEVEL上的软中断的结果的输入,它的功能是处理DPC链表,当一个新的线程已经准备好到一个处理器上运行时,这个程序将进行新旧线程的上下文切换*/
DiFrame struct
P1Home dq ? ; PRCB地址段
P2Home dq ? ;
P3Home dq ? ;
P4Home dq ? ;
SavedRbx dq ? ; 保存RBX
DiFrame ends
NESTED_ENTRYKiDispatchInterrupt, _TEXT$00
alloc_stack (sizeofDiFrame) ; 进行堆的分配
save_reg rbx, DiFrame.SavedRbx ; 保存非易失性寄存器的内容
END_PROLOGUE
lea rcx, (-128)[rbp] ; 设置trap地址
call KiCheckForSListAddress ; 检查SLIST地址
mov rbx, gs:[PcCurrentPrcb] ; 获得当前 PRCB地址
and byte ptr PbDpcInterruptRequested[rbx], 0;//清除请求
KiDI10: cli //上下文切换不能被中断,此处即禁止中断 ;
mov eax, PbDpcQueueDepth[rbx] ; 获取DPC 队列深度 or rax, PbTimerRequest[rbx] ; 合并计时器的值
ifndef NT_UP
or rax, PbDeferredReadyListHead[rbx] ; 合并延期准备表
endif
jz short KiDI20 ; if z, no DPCs to process
mov PbSavedRsp[rbx], rsp ; save current stack pointer
mov rsp, PbDpcStack[rbx] ; set DPC stack pointer
mov rcx, rbx ; set PRCB address parameter
call KiRetireDpcList ; process the DPC list
mov rsp, PbSavedRsp[rbx] ; restore current stack pointer
KiDI20: sti ; enable interrupts
cmp byte ptr PbQuantumEnd[rbx], 0 ; check ifquantum end request
je short KiDI40 ; if e, quantum end not requested
and byte ptr PbQuantumEnd[rbx], 0 ; clearquantum end indicator
call KiQuantumEnd ; process quantum end
KiDI30: mov rbx,DiFrame.SavedRbx[rsp] ; restore nonvolatile register
add rsp, (sizeof DiFrame) ; deallocate stack frame
ret ; return
mov rbx, DiFrame.SavedRbx[rsp] ; restorenonvolatile register
add rsp, (sizeof DiFrame) ; deallocate stack frame
jmp short KxDispatchInterrupt ;
NESTED_ENDKiDispatchInterrupt, _TEXT$00
NESTED_ENTRYKxDispatchInterrupt, _TE