欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

操作系统(李治军) L12内核级线程的实现

程序员文章站 2022-04-24 12:29:52
...

只有支持了进程才可以管理CPU
图:五段论
操作系统(李治军) L12内核级线程的实现
整个过程:从用户栈->内核栈->TCB->TCB完成切换(TCB用switch_to完成TCB的切换完成内核栈的切换)->内核栈切换->再通过iret实现用户栈的切换
从用户角度看,就是为了完成从线程1到线程2的切换,内核对于他是隐藏的

用户进入内核靠的是中断,靠的是系统调用
某个中断指的是:fork

fork()创建进程的系统调用,会引起切换,进入内核

操作系统(李治军) L12内核级线程的实现
进程:资源+执行序列(创建线程):利用fork()
资源+执行序列,都要创建

mov %eax,_NR_fork 系统调用号置给了eax
INT 0x80 调用0x80

执行过程:

A会开始执行B函数
一旦执行INT指令,CPU找到当前内核栈,在内核栈压入当前的SS和SP
INT执行的时候没有进入内核,执行完了才进入内核
执行的时候指向的是用户态栈,并且压入当前的CS和IP

下一步干什么?

执行INT Ox80,即中断
_ststem_call干什么? 压栈
记录用户态的样子东西在内核栈保存下来
切换5段论
1.中断入口即建立用户栈和内核栈的关联
2.进入内核,执行时发现进程可以不执行引发切换

执行sys_fork可能会引起切换(中间的三段论)
操作系统(李治军) L12内核级线程的实现

怎么切换的?

代码解释1-6行:

1.当前线程置给eax
2.判断eax,这句话是汇编,其实是state+eax其实等于state+current,即判断current中的state
current实际上是PCB,接下来看PCB中的state是否等于0,非0表示阻塞
3.如果非0,表示阻塞,则进行内核级线程的中间三段的切换,切换完成后-》第5段中断出口
4.current的counter(时间片)是否等于0,
5.如果时间片也用光了(0),则也会调度
6.从中断返回,从内核栈到用户栈的切换

代码解释1-2行:

放进来$ret_from_sys_call
调用schedule

操作系统(李治军) L12内核级线程的实现
过程
INT自动有,然后push一大堆,要记住push哪些,然后中间调了一些东西,仿照套路做,
调完后再调用schedule,schedule返回时一定要让schedule返回执行ret_from_sys_call(5段论的最后一段:里面是一堆pop,与push相对应,然后再iread)

1.调度:找下一个进程,next=i;即调度(以后讲)
2.切换:next(下一个进程的PCB),接下来switch_to()
操作系统(李治军) L12内核级线程的实现
TSS:任务结构段Task status segment
基于TSS的变换->kernelstack的切换
TSS代码简单,但是效率低,所以改成kernelstack
TSS长跳转(段与段之间的跳转)指令
段segment都要有段描述符(指向段的指针),有描述符就有选择子TR,TR找到描述符,根据描述符找到TSS段
_TSS(n)是指向新的TSS段,即把选择符置给TR,TR发生变化后,找到新的段(即段内容变化),任务的内容发生变化:EAX,esp…,载入寄存器

长跳转指令:把当前CPU的所有寄存器放在当前TR的段中(原来当前TR是空白的)相当于拍了照片存入在当前TR段中
TSS(n)置给dx,dx置给1%(tmp.b的那一行)
要跳转的时候把选择符置给TR,找到新段,扣给寄存器
当前CPU的样子拍下来,然后用下一个想要执行的任务的线程扣在CPU里面,那么现在CPU执行的时候就是用新的东西了
操作系统(李治军) L12内核级线程的实现
核心三步:
INT
switch中的ljmp
iret(interrupt return)中断返回,
操作系统(李治军) L12内核级线程的实现
参数自动取于栈中
栈顶的取出放在参数的最后面,再往下取
栈是先进后出操作系统(李治军) L12内核级线程的实现
代码解释:
此时不能使用malloc因为它是用户态的代码,此时内核态的要使用get_free_page():获取一页内存,
1.memmap把内存打成4KB即一页,memmap=0的哪一页,把地址返回给P,并使用了强制转换,此时PCB有了
2345设置tss
2 esp0内核栈,地址偏移是4KB+P即指针指向了开头
下面是PCB上面是内核栈
esp是用户栈
P是这一页的初试地址
10是内核数据段
ss和esp从哪里来?用的父进程传递下来的东西,父进程正坐在执行INT 0x80那时用到的用户栈,用了父进程一样的栈
操作系统(李治军) L12内核级线程的实现
核心三句
创建核心级线程工作:
1.创建PCB用户栈内核栈,
2.关联栈和TCB
3.初始化两个栈(用户+内核)

操作系统(李治军) L12内核级线程的实现
TCB用switch_to完成TCB的切换完成内核栈的切换再用iret完成用户栈的切换