哈工大os学习笔记五(内核级线程实现)


文章目录

  • 哈工大os学习笔记五(内核级线程实现)
  • 一、 中断入口、中断出口(前后两段)
    • 1. 从int中断进入内核(中断入口第一段)
    • 2.中断出口(最后一段)
  • 二、 其他三段
    • 1.schedule()
    • 2.switch_to()
    • 3.ThreadCreate(创建好TSS)
    • 4.小结
  • 小结

某个中断开始(fork)
内核级线程要在代码层面实现
fork()是系统调用,会引起中断,fork()创建进程(所以会有资源分配和线程的创建),所以fork()是一个非常好的切入点。能够非常清晰地看清
1.线程是怎么切换的
2.切换的五段论代码具体怎么实现的
3.核心级线程切换要具体做哪些事

一、 中断入口、中断出口(前后两段)

首先还是要从上次我画的那个图说起,从那个图中的中断开始。

1. 从int中断进入内核(中断入口第一段)

int 0x80执行的时候没进入内核,执行完毕后,才进入内核。
由于int 0x80没有执行完毕,所以当前的PC指向的是当前的(int 0x80的下一条)

_NR_fork 是系统调用号,存入%eax寄存器,后面会算出调用哪个函数

压入EFLAGS标志寄存器的状态,保存寄存器的状态,在保存寄存器里的内容
int 0x80中断,之后就是OS为我们打开的系统调用system _call,system_call还要压栈,因为我们刚进入内核,CPU这些寄存器仍然是用户态的,要保存寄存器的内容,将一些内容压栈,保护用户态执行的现场。

调用system_call 这个表,具体处理sys_fork,实现sys_fork真正的效果,执行sys_fork 的时候会引起切换。I/O阻塞,发生调度

执行完sys_fork 后,不停,又往下执行。
call 下面的代码就是判断是否引发中断的代码

_systemZ_call:push %d...%fspush %edx...call sys_fork //push1 %eax
————————————————————————————————
mov1 _current,%eax  //将当前的线程(当前线程一直是sys_fork)置给 eax
cmp1 $0,state(%eax) // state(%eax)是一段汇编代码,实际上是state加上eax//current是PCB,就是看PCB中的state是不是0//0是运行,非0表示阻塞//如果不是0就要调度,也就是判断PCB队列的状态
jne reschedule      //跳转调度,跳到schedule完成内核 栈的切换//schedule五段论中间三段
——————————————————————————
cmp1 $0, counter(%eax) //第五段判断current的counter是不是等于0
je reschedule          //等于0也进行调度,时间片是否为0//时间片为0,时间片用完了为0,也要进行切换
ret_from_sys_call:     //跳出去后,还要回来,这里是系统调用返回//接下来就要执行中断返回的代码——————————————————————
reschedule:               //汇编的编号,实际上就是地址//ret_from_sys_call的地址push1 $ret_from_sys_call //将地址压栈jmp _schedule           /*调用_schedule,这个是C函数,他执行的时候必然会遇到右大括号},执行}的时候就将弹栈,返回的就上刚才压入的地址,就会去ret_from_sys_call:执行*/

2.中断出口(最后一段)


会一个一个的弹栈,最后将iret一起pop弹出。
切换出去后,他的下一个核心线程,也就是下一个进程的执行起来的用户栈,完成切换了。
这里保存的都是用户态的内容

二、 其他三段

1.schedule()

schedule
next就是找下一个 线程,至于怎么找,后面会详细的讲。
next i进行调度,switch_to(next),next是下一个进程的TCB,
如果是线程那就是下一个核心级线程的TCB,switch_to 进行TCB切换就很简单,只要修改一下就ok

核心是根据TCB完成核心栈的切换

2.switch_to()

TCB切换图

switch_to 具体代码实现:
下面李老师讲的这个代码(Linux0.11)是TSS实现切换的,而真正的用内核栈切完成切换的是实验四。TSS的介绍实验四有,是基于TSS来实现Kernel stack

TSS:task struct segment 任务结构段,英特尔给做出来了只用一句常跳转指令(ljmp %0\n\t)就可以做到,但是效率特别低,所以进行了改造


TR是CPU的寄存器,相当于GDT表
相当于一个快照,保存恢复。
next就是要进行改变的TR,新的TR找到新TSS描述符,在指向新的段,新的段保存了现场。
这种方式慢,由于快照要扣好多东西,而且由于是一条常指令,不能进行指令流水,是硬件设计效果不好,不能充分利用向现代CPU硬件的加速方法。而用栈,不用照好多东西只要压栈弹栈,而且可以进行流水。

3.ThreadCreate(创建好TSS)

创建线程,就是要创建出能够切换的样子,能够切换了,线程也就创建好了。所以下面的核心就是把TSS做好。当然TSS要做好首先要有PCB,TCB,内核栈,然后就可以做TSS。

下面 是代码实现:

继续执行fork()
_copy_process 拷贝父进程

下面是一段汇编


上面什么参数也没写,是因为都在内核栈里面。
因为父进程执行fork的时候,压了一堆东西,这些东西主要就是父进程在用户态执行时候的样子。这些样子(参数)需要传递给_copy_process,C语言执行的时候他的参数都从栈中弹出,当然这里已经进入内核执行了所以这里是内核栈。所以内核栈里面的内容全都作为参数,有了这些参数就能知道父进程长什么样子了。在_copy_process 基本能做出和父进程一样的叉子(进程)父进程和子进程只有一个地方的小差别。
这些参数包括esp等。在C函数中,越在后面的参数就越早压入栈中,所以位置越靠前的参数,越靠近栈顶。参数最长的函数。
esp>ss:sp esp j就是标记栈的
eip>ret=??1 int 0x80 要执行的下一句代码

要知道这些参数和栈的序列是怎么对应的

看下图:内核态代码get_free_page();获得一页内存,不能用malloc,因为malloc 是用户态的代码,在系统初始化的时候涉及到mem_map,mem_map将内存打成4K,4K,4K的一段一段,那个就叫一页一页 ,从那里找空闲页
就是mem_map等于0的那一页,找到mem_map等于0的那一页,把地址返回给p,并进行强制转换,这一页内存就用来做PCB。
PCB就有了

下面四行代码就是设置TSS,esp0就是内核栈,esp就是用户栈,这都是硬性规定好的。PAGE_SIZE(4k)p申请好的地址。
0x10 是内核数据段 ,这里也是用的内核堆栈段是一个段。
内核段有了,段偏移4k+p,下面是PCB,上面是内核栈。(PCB内核栈都做好了)


设置用户栈(copy_process那个贼多参数那个)
父进程传递下来的东西,父进程正在执行int0x80那个时候用到的用户栈,所以用了和父进程一样的栈。用户级可以用一样的,但是在内核级是两个不同的东西

在把TSS初始化就OK了,eip int 指令完成后的下一句话

4.小结

fork()子进程已经做好了


  1. 父进程阻塞,然后进入schedule调度

  2. schedule就要执行switch_to

  3. switch_to就切换到子进程

  4. 子进程就会把刚才初始化好的TSS,直接扣到CPU。

5. 其中包括eip等于int 0x80,eax等于0
父进程进去int创建一个子进程,返回的时候执行int的下一条,所以父进程也执行这条指令,父进程执行的时候eax≠0,所以父进程执行下面的




exec怎么进去的,从exec系统调用开始,进去后会执行实sys_execve这个函数,
老师提出的问题:在进入子进程之前,父进程子进程执行同样的代码。
好了现在调用exec,进入到内核态,一顿折腾后,再返回的时候执行的就不再是和父进程一样的代码,而是ls。
那么以上这些东西是怎么做的???
怎么做的:

中断返回的时候要做iret,iret 找到ss sp ret 一些的东西,将这些栈存储的东西赋给真正的寄存器,然后让PC执行。

接下来执行 call_do_execve这个函数,压栈,压栈是因为exec也是要有参数的,实际上压进去的实际是参数,参数是esp,eip。
如果能把ls的地址找到并且赋给ret,将来在执行iret的时候弹栈。EIP也就是一个偏移

esp,eip加起来赋给eax,eax进行压栈,EIP=0x1c 十进制是28,正好跳到28,也就是ret=???(eip)最后会指向PC。

eip[0]=ex.a_entry入口地址置给eip,就okl了。
而eip[3] 指向SS:SP
ls有自己的执行代码了有自己的栈了。
ex.a_entry哪里来的?可以读文件 ls是一个可执行命令 ls hello ,hello 是一个可执行程序,这个程序在磁盘上有,从磁盘上把这个程序读进来,就有一个文件头,这个文件头就有a_entry,a_entry是编译的是时候作为可执行文件写进去的。实际上是连接做为可执行文件程序写入的,写进去就放给ex.a_entry。在读文件读出来置给内核栈中,置好内核栈后,在中断返回iret时候就弹回去了,就执行hello的第一句话。

小结

做一个操作系统要知道好多内容:读写文件,链接,文件的格式,内核栈结构,内核栈位置,文件头赋给内核栈的相应位置,iret等等。

哈工大操作系统学习笔记五——内核级线程实现相关推荐

  1. 哈工大操作系统学习笔记十——信号量与死锁

    哈工大os学习笔记十(信号量与死锁) 文章目录 哈工大os学习笔记十(信号量与死锁) 一. 信号量临界区保护 1.为什么要保护信号量 2.临界区 3.保护信号量的方法 3.1 轮换法 3.2 标记法 ...

  2. 操作系统学习笔记-2.1.5线程概念和多线程模型

    操作系统学习笔记-2019 王道考研 操作系统-2.1.5线程概念和多线程模型 文章目录 5线程概念和多线程模型 5.1知识概览 5.2 什么是线程?为什么要引入线程? 5.3引入线程及之后,有什么变 ...

  3. 计算机操作系统学习笔记 第二章、进程与线程

    文章目录 1 进程和线程 1.1 进程的概念和特征 1.1.1 进程的概念 1.1.2 进程的特征 1.2 进程的状态与转换 1.3 进程的组织 1.4 进程控制 1.5 进程通信 1.5.1 共享存 ...

  4. 应用退出前不让线程切换_用户级线程和内核级线程,你分清楚了吗?

    前天晚上有个伙伴私信我说在学进程和线程,问我有没有好的方法和学习教程,刚好我最近也在备相关的课. 班上不少学生学的还是很不错的.拿班上小白和小明的例子吧(艺名哈).小明接受能力很强,小白则稍差些. 关 ...

  5. 哈工大李治军老师操作系统笔记【10】:内核级线程实现(Learning OS Concepts By Coding Them !)

    文章目录 0 回顾 1 实现 1.1 int 0x80 fork(中断入口) 1.2 进入核心态 1.3 system_call(中断切换中间三段) 1.4 中断出口 1.3 switch_to 1. ...

  6. 哈工大李治军老师的操作系统学习笔记

    文章目录 1 什么是操作系统 2 操作系统启动 3 操作系统接口 命令行发生了什么? 图形按钮怎么回事? 操作系统接口(系统调用) 4 操作系统调用 不应该随意访问内核 怎么不让你访问内核 不让我访问 ...

  7. 操作系统学习笔记(1.计算机系统概述 2.进程与线程)

    文章目录 第一章 计算机系统概述 操作系统的概念.功能 操作系统的特征 操作系统的发展与分类 操作系统的运行机制 中断和异常 系统调用 操作系统体系结构(上) 操作系统体系结构(下) 操作系统引导 虚 ...

  8. 操作系统--用户级线程与内核级线程

    一.多进程是操作系统基本图像 进程都是在内核进行 二.用户级线程 2.1线程引入 可以切指令不切表,也就是资源不动,指令执行分开,更加轻量化,从而提高效率,保留并发优点,避免进程切换代价,也就引入了线 ...

  9. 操作系统--用户级线程和内核级线程

    在多线程操作系统中,各个系统的实现方式并不相同.在有的系统中实现了用户级线程,有的系统中实现了内核级线程 1.内核级线程: (1)线程的创建.撤销和切换等,都需要内核直接实现,即内核了解每一个作为可调 ...

最新文章

  1. 图片的略小图图片不显示的处理方法
  2. 父域与子域之的信任关系
  3. 变形金刚2_变形金刚(
  4. mysql left join第一个_MySQL 之 LEFT JOIN 避坑指南
  5. MySQL字符集详解
  6. centos7 安装openocd
  7. 团队-象棋游戏-代码设计规范
  8. hdu4521 线段树+dp
  9. 基于STM32数码相册
  10. Word标题样式设置多级自动编号
  11. Factory reset会黑屏一段时间进入Provision首页
  12. 「13」朴素贝叶斯Python实战:计算打喷嚏的工人患病的概率
  13. 微信公众号自定义菜单创建接口
  14. minecraft兑换码领取!
  15. ora-01031解决方法
  16. 洛谷-P1228-地毯填补问题-普及/提高--分治+递归
  17. Google map获取手机屏幕当前显示地图的范围
  18. 基于单片机的温湿度串口监控系统设计(#0429)
  19. 2019年8月8日星期四(系统编程)
  20. 《量化炼金术-中低频量化交易策略研发》读书笔记-序言,引言

热门文章

  1. 前端面试官会问的问题
  2. 用vfloppy安装CDLinux到硬盘,并修改缺省extra路径参数
  3. JavaScript — 基础语法
  4. 瞳距自测软件app 测试准确吗,瞳孔距离检测手机app-瞳孔距离检测最新版手机软件预约 v1.0-友情手机站...
  5. zeppelin使用中的问题汇总
  6. 常用API类方法笔记整理1
  7. uniapp 打包成H5
  8. linux系统查看主板cpu,Linux下使用lm_sensors查看主板和CPU温度
  9. 一键分享怎么可以找回删除的照片小技巧
  10. Spark数据清洗案例