2017-2018-1 20179202《Linux内核原理与分析》第四周作业
一、跟踪分析内核的启动过程实验 :
1.启动Menuos:
qemu仿真kernel:
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img
知识补充:
(1)bzImage 是 vmlinux 经过 gzip 压缩后的文件,是压缩的内核映像,“b”代表的是“big”(bzImage 适用于大内核,zImage 适用于小内核)。vmlinux 是编译出来的最原始的内核ELF文件;
(2)根文件系统包括虚拟根文件系统和真实根文件系统。initrd 是“initial ramdisk”的简写,boot loader 将存储介质中的 initrd 文件加载到内存,内核启动时先访问 initrd 文件系统(虚拟的文件系统),然后再切换到真实的文件系统。
2.调试跟踪:
-S 开始处冻结CPU,方便调试
-s 使用tcp端口1234来进行通讯,将进程信息传过去(在后面的调试中会用到)。若不想使用1234端口,可以使用-gdb tcp:xxxx来取代-s选项
启动gdb,把内核加载进来,建立连接:
file linux-3.18.6/vmlinux
target remote:1234
实践过程中出现以下错误:
连接超时应该是没连接上冻结的系统,检查后发现进入gdb调试前讲QEMU窗口关闭了,打开后得以解决:
在 start_kernel 处设置断点,继续执行,停在断点处:
在 rest_init 处设置断点,继续执行,停在断点处:
3.内核启动分析(自己的大致理解):
(1)start_kernel()
main.c 中没有 main 函数,start_kernel() 相当于是C中的main函数。start_kernel是一切的起点,在此函数被调用之前内核代码是用汇编语言写的,完成系统的初始化工作,为c代码的运行设置环境。由调试可得 start_kernel 在500行:
(2)init_task()
start_kernel() 函数几乎涉及到了内核的所有模块,如:trap_init()(中断向量的初始化)、mm_init()(内存管理的初始化)sched_init()(调度模块的初始化)等,首先是510行的init_task():
struct task_struct init_task = INIT_TASK(init_task);
可以看出 init_task(0号进程)是 task_struct 类型,是进程描述符,使用宏INIT_TASK对其进行初始化。接下来就是对各种模块的初始化:
图片来源于分析Linux内核的启动过程
(3)rest_init()
通过rest_init()新建kernel_init、kthreadd内核线程:
403行代码 kernel_thread(kernel_init, NULL, CLONE_FS);
,由注释得调用 kernel_thread()创建1号内核线程(在 kernel_init 函数正式启动):
注:对比 init_task 和 kernel_thread()
kernel_thread()是 fork 出了一个新进程来执行kernel_init 函数,而 init_task 是使用宏进行初始化的。也就是说0进程不是系统通过 kernel_thread 的方式(也就是 fork)创建的(init_task 是唯一一个没有通过 fork()产生的进程)。
405行代码 pid = kernel_thread(kthreadd, NULL, CLONE_FS | CLONE_FILES);1
调用 kernel_thread()执行 kthreadd函数,创建 PID=2的内核线程:
此函数的任务是管理和调度其他内核线程 kernel_thread。for 循环中运行 kthread_create_list 全局链表中维护的 kthread, 在create_kthread()函数中,会调用 kernel_thread 来生成一个新的进程并被加入到此链表中,因此所有的内核线程都是直接或者间接的以 kthreadd 为父进程。
4.总结:
(1)init_task()(PID=0)在创建了init进程后,调用 cpu_idle() 演变成了idle进程,执行一次调度后,init进程运行;
(2)1号内核线程负责执行内核的部分初始化工作及进行系统配置,最后调用do_execve执行 init 函数,演变成 init 进程(用户态1号进程),init 进程是内核启动的第一个用户级进程;
(3)kthreadd(PID=2)进程由0号进程创建,始终运行在内核空间, 负责所有内核线程的调度和管理 。
注:Linux下的进程类别(内核线程、轻量级进程和用户进程)以及其创建方式
参考:
Linux下0号进程的前世(init_task进程)今生(idle进程)
Linux下1号进程的前世(kernel_init)今生(init进程)
二、课本笔记:
1.进程调度:
进程调度程序是在可运行态进程之间分配有限的处理器时间资源的内核子系统。Linux提供了抢占式的多任务模式,在此模式下,由调度程序决定一个进程的运行,以便其他进程能得到执行机会(抢占:抢占的挂起动作)。进程在被抢占前能运行的时间叫做进程的时间片,即分配给每个可运行进程的处理器时间段。
Linux内核将进程分成普通进程和实时进程。普通进程用nice值表示时间片的比例(CFS调度器将处理器的时间比划分给了进程,越大的nice值将被赋予低权重,丧失一小部分的处理器时间使用比);实时进程采用实时优先级,数值越高优先级越高(两种实时调度策略为SCHED_FIFO和SCHED_RR,SCHED_RR是带有时间片的SCHED_FIFO)。任何实时进程的优先级都高于普通进程。
CFS虽没有时间片的概念,但必须维护每个进程运行的时间记账,它会挑一个具有最小vruntime(存放进程的虚拟运行时间)的进程(利用红黑树迅速找到最小vruntime值的进程)进行调度。休眠(被阻塞)进程把自己标记成休眠状态,从可执行红黑树中移出,放入等待队列,然后调用schedule()选择和执行其他进程,唤醒时被置成可执行状态,然后再从等待队列中移到可执行红黑树中。
当内核即将返回用户空间时,内核会检查need_resched是否设置,如果设置,则调用schedule(),发生用户抢占。 内核抢占是指在内核态运行的进程在执行期间可能被另一个进程取代(没有读懂课本对内核抢占的解释,参照Linux用户抢占和内核抢占详解(概念, 实现和触发时机),如果内核处于相对耗时的操作中, 比如文件系统或者内存管理相关的任务, 其他进程无法执行, 无法调度, 这就造成了系统的延迟增加, 用户体验到”缓慢”的响应。比如如果多媒体应用长时间无法得到CPU, 则可能发生视频和音频漏失现象.启用内核抢占可解决此问题)。
2.内核数据结构:
(1)Linux内核链表不同于传统链表,它不是将数据结构塞入链表,而是将链表结点塞入数据结构:
(2)Linux内核通用队列实现成为kfifo,提供enqueue和dequeue,kfifo对象维护入口偏移和出口偏移两个偏移量;
(3)Linux映射一个唯一的标识数(UID)到一个指针(有点像字典类型,每个唯一的id对应一个自定义的数据结构);
(4)红黑树和平衡二叉树的区别在于它使用颜色来标识结点的高度,它所追求的是局部平衡而不是平衡二叉树中的非常严格的平衡。(课本上对红黑树的描述我也没有看明白,查阅资料数据结构之红黑树,了解了红黑树的性质(根是黑色;所有叶子都是黑色(叶子是NIL节点);如果一个节点是红的,则它的两个儿子都是黑的;从任一节点到其叶子的所有简单路径都包含相同数目的黑色节点)及红黑树的插入删除。虽然红黑树追求的是局部平衡,但我感觉和平衡二叉树的插入删除还是难了点,也有可能是刚接触的原因QAQ)。
三、小结:
本周学习中遇到了很多不明白的指令和术语,一边实践一边查阅资料,在阅读资料中又会由此引出新的问题(如在搜索init进程中看到先是内核线程又是用户进程,然后如果不理解二者区别,就没法弄明白1号进程的前世今生,只能继续搜索内核线程和用户进程的区别)过程辛苦,但好在问题大部分得以解决,还有小部分需要再强化理解。
2017-2018-1 20179202《Linux内核原理与分析》第四周作业的更多相关文章
- 2019-2020-1 20199303<Linux内核原理与分析>第二周作业
2019-2020-1 20199303第二周作业 1.汇编与寄存器的学习 寄存器是中央处理器内的组成部份.寄存器是有限存贮容量的高速存贮部件,它们可用来暂存指令.数据和位址.在中央处理器的控制部件中 ...
- 20169219 linux内核原理与分析第二周作业
"linux内核分析"的第一讲主要讲了计算机的体系结构,和各寄存器之间对数据的处理过程. 通用寄存器 AX:累加器 BX:基地址寄存器 CX:计数寄存器 DX:数据寄存器 BP:堆 ...
- 2019-2020-1 20199314 <Linux内核原理与分析>第二周作业
1.基础学习内容 1.1 冯诺依曼体系结构 计算机由控制器.运算器.存储器.输入设备.输出设备五部分组成. 1.1.1 冯诺依曼计算机特点 (1)采用存储程序方式,指令和数据不加区别混合存储在同一个存 ...
- Linux内核原理与分析-第一周作业
本科期间,学校开设过linux相关的课程,当时的学习方式主要以课堂听授为主.虽然老师也提供了相关的学习教材跟参考材料,但是整体学下来感觉收获并不是太大,现在回想起来,主要还是由于自己课下没有及时动手实 ...
- 2019-2020-1 20199314 <Linux内核原理与分析>第一周作业
前言 本周对实验楼的Linux基础入门进行了学习,目前学习到实验九完成到挑战二. 学习和实验内容 快速学习了Linux系统的发展历程及其简介,学习了下的变量.用户权限管理.文件打包及压缩.常用命令的和 ...
- Linux内核原理与分析-第二周作业
写之前回看了一遍秒速五厘米:如果
- 20169219linux 内核原理与分析第四周作业
系统调用 系统调用是用户空间访问内核的唯一手段:除异常和陷入外,它们是内核唯一的合法入口. 一般情况下,应用程序通过在用户空间实现的应用编程接口(API)而不是直接通过系统调用来编程. 要访问系统调用 ...
- 2018-2019-1 20189221《Linux内核原理与分析》第一周作业
Linux内核原理与分析 - 第一周作业 实验1 Linux系统简介 Linux历史 1991 年 10 月,Linus Torvalds想在自己的电脑上运行UNIX,可是 UNIX 的商业版本非常昂 ...
- 20169212《Linux内核原理与分析》课程总结
20169212<Linux内核原理与分析>课程总结 每周作业链接汇总 第一周作业:完成linux基础入门实验,了解一些基础的命令操作. 第二周作业:学习MOOC课程--计算机是如何工作的 ...
- 20169212《Linux内核原理与分析》第二周作业
<Linux内核原理与分析>第二周作业 这一周学习了MOOCLinux内核分析的第一讲,计算机是如何工作的?由于本科对相关知识的不熟悉,所以感觉有的知识理解起来了有一定的难度,不过多查查资 ...
随机推荐
- Hibernate学习(5)- session的get与load方法对比
1.共同点:get和load都是根据Id单条查询获取对象 org.hibernate.Session.load(Class<User> theClass, Serializable id) ...
- div 当高度较小时指定高度,当高度较大时自适应
在该元素或标签的样式中加入:{min-height:500px;height:auto;},其中min-height:是最小高度,auto是自适应内容.
- ACM-ICPC2018 青岛赛区网络预赛-B- Red Black Tree
题目描述 BaoBao has just found a rooted tree with n vertices and (n-1) weighted edges in his backyard. A ...
- Linux系统调用和库函数
#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unist ...
- [linux]ubuntu在线安装mysql
1. sudo apt-get install mysql-server 2. apt-get isntall mysql-client 3. sudo apt-get install li ...
- BestCoder Round #40 解题报告
这场是第一场没有米的BC... 大概也是想震一震那些一听说没米了就不打BC的人吧 这次的题目质量比以往高了许多 (然而我并没有打这一场BC 但是今天下午到现在做的过程中真的学到了不少知识呢 A题略水. ...
- JavaScript中innerText和innerHTML的区别
案例 <html> <head> <meta http-equiv="Content-Type" content="text/html;ch ...
- final关键字详解
java中,final关键字可以用来修饰类.方法和变量(包括成员变量和局部变量).下面就从这三个方面来了解一下final关键字的基本用法. 1.修饰类 当用final修饰一个类时,表明这个类不能被继承 ...
- Vue笔记之props验证
使用props 在Vue中父组件向子组件中传送数据是通过props实现的,一个简单的使用props的例子: <!DOCTYPE html> <html> <head> ...
- 配置kernel的log buf大小(如果kmsg log被覆盖)
如果在打印kmsg log时发现log被覆盖,log 的buf不够大可以使用默认配置调buf: defconfig CONFIG_LOG_BUF_SHIFT=20 (默认是17 2的17次方) ...