L12 内核级线程的代码实现(linux 0.11)

理论上:

理论上如下图所示,从一个用户栈到另一个的切换过程:
线程1用户栈通过int陷入内核栈
内核通过线程控制块寻找到(调度之后的)线程2线程控制块TCB
TCB2中有内核栈的指针,代表着内核栈切换成功
通过iret指令从内核栈回到用户空间;在这里插入图片描述

以fork()为例看看实现:

首先大致梳理一下:
① int0x80(进入sys_call之前硬件自动push一堆东西到内核栈)
②之后在sys_call中(push一堆用户态信息的寄存器到内核栈)调用sys_fork完成fork工作
③fork之后进行schedule工作(如果切换进程则swith_to)
④最后ret_form_sys_call pop内核栈中一堆数据,调用iret回到用户态;

下面根据这个流程,仔细看看其中发生了什么;

  1. fork系统调用陷入内核之前的过程:
    ①记录中断号NR_fork;②产生中断int,中断指令集完成内核栈初始化;③内核栈与用户栈相连,且存有int后面指令地址(PC指针);
    在这里插入图片描述在这里插入图片描述

  2. system_call中(中断的入口和出口:相当于忽略sys_fork的头和尾巴)
    ①将当前用户态的寄存器中的内容全部压入内核栈中
    ②调用sys_fork()完成创建进程的过程;
    ③在sys_fork结束之后,把当前执行进程的current.PCB给 %eax,如果阻塞就调用schedule如果时间片用光,也调用schedule;
    ④schedule结束后,调用ret_from_sys_call从内核中返回(此时如果调度,已完成切换内核栈过程);
    ⑤注意,右侧的*??2*是pushl %eax的入栈;
    在这里插入图片描述

  3. 详解2中的尾巴ret_from_sys_call
    将内核栈中的数据都pop出去,并且跳回到中断发生的代码后面继续执行;
    在这里插入图片描述

  4. 详解③中schedule结束后,switch_to的内核栈切换(线程切换)过程
    linux 0.11中并未使用我们之前说的这种内存栈互相复制的方法;而是使用的tss段的整段复制;(TSS:task structure segment任务结构段,保存在PCB/TCB中)(TR寄存器是指向GDT表中tss段的指定寄存器;)
    过程如下:(一条指令…)
    ①当前TR指向的原来的tss段保存当前cpu中的全部寄存器数据(快照);
    ②TR指向(入参next的PCB结构体)n中的tss段;
    ③将新的tss段全部复制(扣到)到cpu中!
    注意:这样很慢,因此实验中要修改这里,完成内核栈的复制,弃用这种0.11方法
    在这里插入图片描述

  5. 详解sys_fork()中的copy_process过程(不包含内存)
    首先sys_fork中将需要传入给copy_process的参数,全部压入栈中!
    接着就是调用copy_process的过程了:
    ①:申请内存空间—>给TCB/PCB
    ②:创建内核栈与PCB/TCB关联:将tss里面的内核栈变量与这段空间关联(tss在PCB中)
    ③:创建用户栈(与父进程使用同一个用户栈,这里面涉及内存管理,修改是创建)
    ④:修改新的tss,将cs:eip接下来的执行位置以及其他的寄存器放进去;(内核中的哦)
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    这里的tss就是承担的内核栈的作用;将两个进程在内核态分裂开来;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值