![9d298be16692a95e3617158acb788813.png](https://i-blog.csdnimg.cn/blog_migrate/6c9d91966829630d0c6e4d2a624f3e75.jpeg)
这篇文章是我之前在内核中的一些问题的总结,希望能对有同样疑惑的小伙伴能有些帮助。同样如果有小伙伴对于我的理解有不同的想法也请大家能积极发言,互相学习。
1. 开机启动时间是否和内核相关的配置有关?或者说内核对于开机的启动时间是否会有很大的影响?
答:实际上并不会有很大的影响,开机的过程第一步是启动bootloader,然后是启动内核,最后是启动应用程序。主要的耗时是在启动内核之后,需要启动一系列的服务来支持后续应用程序的加载。因此内核对于开机时间的影响并不大,主要是需要减少服务启动的数量。
2. 请大致描述下系统调用的详细过程。
答:以linux-0.11内核代码的open函数为例,大家可以去官网下载,为什么选用0.11呢?个人觉得读源码的话,尤其是摸透系统调用过程这种比较重要的调用,开发者不会再以后的版本有很大的变更的,因此越原始的代码,结构越清晰,不会像后面的版本添加很多其他的功能特性之后,代码结构变的比较复杂,看起来会比较耗时。
第一步,客户端调用open系统调用函数,传入打开的文件以及打开的方式;
![eac0d9335149956ffb3f9486222fefd3.png](https://i-blog.csdnimg.cn/blog_migrate/351d3664906c52b98d2558b3aa2fdb44.png)
第二步,调用系统函数之后,系统函数触发0x80中断
![443c528952760bb269eb4bcc8dcdd2c7.png](https://i-blog.csdnimg.cn/blog_migrate/ea53d5f708a52f7eaf870241edc2d8fc.jpeg)
第三步,通过__NR_open这个偏移量找到对应的内核中的调用sys_open函数。说到这个偏移量我们有需要展开说一下这个内部的sys_open是如何与偏移量对应的。
以下这个sys_call_table就可以揭晓答案:
![ab7f5046583a80c98163e3443a2821b8.png](https://i-blog.csdnimg.cn/blog_migrate/bcc97a389ae5ab757186d8c0c5e55227.png)
![1d76d39a655c8e053dabdc0dee53e349.png](https://i-blog.csdnimg.cn/blog_migrate/2c8520a49482578c46f0fa3d81704cc1.jpeg)
这个table对应的是将一个一个的系统调用放在一个数组中,然后调用时通过偏移量调用具体的系统函数。open对应的__NR_open是5就会调用sys_open。这个表我们搜一下源码是在_system_call这个函数中调用的。这个函数是在sched_init初始化时将0x80和system_call绑定,因此触发0x80中断的时候就直接调用到了system_call函数。
![4cfeae34b1d29edab524f1ea1ac02735.png](https://i-blog.csdnimg.cn/blog_migrate/3838e6016587e4d1044d0b8483cf8848.jpeg)
下面的是汇编的代码,就是system_call系统调用调用到system_call_table的地方。systemcall调用的话就相当于open调用到80中断之后,通过systemcalltable来找sys_open函数。
![642d4c05f54c862bddf0d9098eaa72b9.png](https://i-blog.csdnimg.cn/blog_migrate/cbd575f431d75d766ec0ebc24c2b207d.jpeg)
3. 内核中的系统调用为何采用中断而不是采用函数的形式?发生中断嵌套时,内部是怎样解决的?
答:采用中断主要的原因就是用于完全隔离内核空间和用户空间,通过系统调用隔离内核空间和用户空间。
中断嵌套的话也是一样的保护现场,比如一个中断在执行的过程中来了另一个中断,此时就会保护现场等待中断执行结束再回到第一个中断执行。
4. 当初linux0.11主要完成的工作是什么?
答:核心是实现了一组系统调用,移植gcc,编译了一版可执行的程序。
5. fork函数的具体实现
答:用户层调用到内核层和open是类似的。最后是调用到__sys_fork函数。sys_fork函数调用find_empty_process寻找到一个空闲的进程返回该进程的ID。然后将父进程的内容通过task_struct结构体中的内容复制给返回的子进程。父进程正在运行时写内存的话需要同时复制给子进程一份,这种机制叫写时复制。创建的新的子进程实际只是找到一个空闲的进程返回。
7. CFS调度器,完全平衡调度器 task_struct中的sched_entity进行相关的平衡操作。红黑树和内核调度是什么关系?
答:CFS内部通过虚拟运行时间vruntime来进行平衡。vruntime其实是实际运行时间相对于权重为0的进程的比例值。linux内核内部每一个任务都有一个task_struct结构,里面存储的该Task的上下文,进程状态等信息。但是需要调度任意状态的进程的话,使用sched_entity这个结构操作。这个结构内部是就是一颗红黑树,每次虚拟运行时间到了之后取出当前最左边的子树运行。