• 《深入理解linux内核》-1-绪论


    学习书籍:

    • 《深入理解linux内核》

    记录重点、还未掌握、个人理解以及有意思的

    书本对应linux版本的源码下载地址: http://ftp.sjtu.edu.cn/sites/ftp.kernel.org/pub/linux/kernel/v2.6/

    一、绪论

    本章多是一些基本概念的补全,在操作系统的基本知识层面,后面会探究其原理实现

    1. linux的设计上与其他类Unix的差异/竞争点在哪?

    主要差异见书: P9, 这里记一下重点:

    • 线程的实现方式: linux的设计中将LWP轻量级进程即线程当作基本的执行上下文,通过非标准的clone()系统调用处理(你敢想象clone命令居然不在POSIX标准内?),而其他类Unix都是基于内核线程(一个能够被内核独立调度的执行环境)

    2. 为什么会产生用户态内核态?

    类Unix操作系统不给用户程序直接访问物理硬件的权利,在其中加入了一层软件集合,也就是操作系统或者内核

    随之而来的就是对引入两种不同的执行模式:用户程序的非特权模式和内核的特权模式,也就是问题所述的两种状态

    3. 内核的体系结构?单块结构与微内核?优劣势?linux是如何设计的?

    两种体系结构:

    • 单块结构:每个内核层都集成到整个内核程序中,并代表当前进程在内核态下运行(大多数Unix系统)
      • 也就是每个内核程序都被植入了完善的内核层代码,当然此时的内核程序一定是内核态执行了
    • 微内核:只需要内核有一个很小的函数集(同步原语、调度程序、进程间通信机制等),几个在其上运行的系统进程代替操作系统的功能(大多数操作系统学术研究)
      • 是一种分层的结构,上层使用下层的服务,其中操作系统层是一个独立的服务程序

    微内核程序的优劣可以总结为:

    • 分层结构带来的优势:模块化、可移植性强、硬件适配强(与硬件相关的封装到操作系统层了)、更加充分的利用RAM
    • 劣势:上下层显示的消息传递有一定的消耗,这也是单块结构的优势所在

    Linux的设计:

    目标是达到微内核的许多优点并不影响效率(俗话说就是通吃)

    做法:

    • Linux提供了模块的概念,模块是一个目标文件,其可以在Linux内核运行时链接加载也可以解除链接(模块是块砖,哪用往哪搬)

    • 模块的目标代码是一组函数构成的,这些函数代码逻辑实现了内核上层的功能,例如文件系统、驱动程序等等

    • 注意,模块与微内核的上层实现操作系统功能的进程不同,其不是进程,相反其类似于其他静态链接的内核函数

    • 总结:就是替换了微内核的系统进程为一系列按需链接的模块静态代码

    优点:

    • 性能消耗小:不需要传递上下层传递消息,其与静态链接的代码完全等价,不需要传递消息
    • 拥有微内核的便利性:模块化、移植性、平台无关性
    • 按需使用节省内存

    4. Unix文件系统中,多个进程打开同一个文件,操作系统底层会实现同步机制吗?

    结论:并不会

    一个文件被打开后,系统调用会创建一个被打开文件的文件对象并返回文件描述符,一个文件对象可能由同一个进程的多个文件描述符描述

    多个进程打开同一个文件,Unix文件系统会给每个进程分配单独的文件对象和单独的文件描述符,并且不提供任何形式的同步机制

    但是当前会在上层提供文件被打开的提示(.swap),如果写入的话也会提示“在读取到现在此文件已经被修改是否覆盖写入“

    如果想要同步可以通过flock()系统调用实现进程在整个文件或者部分文件上的I/O操作实施同步

    5. 内核访问打开的文件的机制?

    不管是read还是write默认都是顺序访问,会用文件指针将本次的访问的结束位置保存用于下一次的继续顺序访问

    文件指针保存在哪?=> 放在打开的文件对象中

    6. 一个用户进程切换内核模式后还是那个进程吗?

    不会改变,只是特权模式的改变

    一个进程在某一个时刻只能处于内核模式和用户模式二者之一

    7. Unix内核是一系列内核进程吗?

    参考内核的体系结构

    内核本身不是一个进程而是进程的管理者,其可以包含一些内核进线程或特权进程,因为这些进程/线程始终在内核态运行伴随着系统关闭而关闭,所以其运行依赖的内核程序属于内核,所以其也属于内核

    简单来说就是:内核不单单是一个内核态进程,而是系统进程的管理者,其也包含了管理所需要的一些内核线程或特权进程

    8. 说说详细的进程上下文切换吧?

    以一个系统调用为例子:

    image-20220625174021525

    补充:

    • 进程描述符存储的上下文中寄存器包括哪些? P27
      • PC程序计数器、栈指针SP寄存器
      • 通用寄存器
      • 浮点寄存器
      • 包含CPU状态信息的处理器控制寄存器
      • 跟踪进程对RAM访问的内存管理寄存器

    9. 进程不在CPU执行的时候在干嘛?

    在等待,准确的说在不同事件的等待队列中(内核提供的),内核通过进程描述符的队列实现这些等待不同事件的idle进程

    10. 内核的可重入性是什么?怎样实现的?

    可重入性表示内核提供了多个进程同时进入内核态执行的条件,目前所有的Unix系统都是支持的

    保证可重入性的主要问题/挑战在哪?

    • 多个进程同时运行一段内核代码,如何保证安全性/同步?状态上下文不会收到影响?

    内核如何去实现这样的可重入性呢?=> 内核同步

    • 可重入函数:部分内核函数只会修改局部变量而不会修改全局数据结构
    • 非可重入函数:内核中也可以运行非可重入函数,这些函数段就需要通过锁这样的同步机制确保同一个时刻只有一个进程在运行

    11. 内核控制路径是什么?路径的改变会受到哪些影响呢?

    内核控制路径(kernel control path) 表示内核处理系统调用、异常、中断的指令序列(个人理解就是一段程序整个生命周期的执行路线,这个程序也包括内核程序)

    • 内核控制路径的交错:当用户态进程发生系统调用时,内核会通过控制路径证实执行下去无法立即完成要等待,所以此时就会发生进程切换,内核又开始执行其他的控制路径

    • 内核控制路径的嵌套:当一个进程(启用了中断内核路径)正在执行当前的内核控制路径时此时发生了中断,CPU会优先响应中断开始执行另一个指令序列,执行完毕后恢复第一个控制路径继续执行,这样嵌套的整体过程在同一个进程上下文,并且中断处理的时间会算在该进程的系统CPU运算总时间中(很神奇,这并不是这个进程该干的活)

    • 每个内核控制路径都引用它自己的私有内核栈

    所以,进程系统调用、CPU处理中断、异常、进程优先级抢占时内核都会切换到另一个的控制路径即另一个的一段指令序列

    可以将内核想象成为一个服务器,硬件中断、多个用户态进程的系统调用、异常都可以看作是对服务器的请求,都需要内核来处理,所以内核不是按顺序执行的而是交错运行的,并且要保证同步安全

    12. 内核的可重入性同步与进程公共数据同步有什么不同?

    几乎差不多,都是通过底层的原子性操作支持实现上层同步,方式包括锁、信号量等等,只不过在内核代码设计中可能要加上内核前缀 : ),例如内核信号量

    13. IPC进程间通信的方式在内核角度是如何实现的?

    内核将IPC看作一个资源来实现,类似于文件,IPC资源是不变的需要创建者手动释放

    14. fork的父子进程如何产生关联/识别到对方?

    fork的父子进程结构中有两个指针,分别指向本进程的父进程与子进程,如此产生联系

    15. SIGCHLD信号是什么时候发送的?

    我们都知道父进程不合适的处理子进程的SIGCHLD话会导致子进程一直占用资源导致僵尸进程,这个信号是子进程在调用_exit()系统调用时,内核会释放该进程的所有资源并发送此信号给其父进程(如果你想问怎么找到父进程的,请看上一个问题)

    说到僵尸进程,那么孤儿进程又是如何产生的呢?

    当一个进程调用_exit()系统调用的时候会除了通知父进程(如果有),还是将其所有现有自己子进程的进程描述符,改为指向init系统特殊进程,成为他的孩子,从而成为孤儿

    16. 什么是进程组呢?什么是登陆会话?

    如字面意思,其表示一系列进程的组合,可以抽象为“作业(Job)”,类似于数据库中理解的事务

    • 每个进程描述符中有一个进程组ID(PGID)的字段,对于一个进程组来说其ID就是领头进程的PID

    • 新创建的进程默认会被插入其父亲的进程组中

    登陆会话(login session)

    补充来自:

    • https://www.cnblogs.com/sparkdev/p/12146305.html

    一般在linux中就是shell session, 就是已经开始会话的那个终端进程以及其所有子进程

    • 一个进程组的进程必须在同一个会话中

    • 一个会话组的所有进程都有相同的SID, 该值就是领头进程的PID

      image-20220625211938213

    • 一个会话中可能会有多个进程组并且同时处于活跃状态,那么同一时刻只能有一个组在前台(意味着改组可以访问终端),其他组在后台,可以通过bg/fg内部命令切换

      前台后台的意义?

      • 一个进程组或者说Job在前台就代表着终端的所有输入(包括信号等)全部交给其处理,其输出也直接发送到控制终端上
      • 一般来说一个终端对应一个session,每新打开一个终端就是新开启了一个session

    进程、进程组、session之间的关系:

    image-20220625211434907

    可以说session是进程组的集合

    17. 内存分配的延迟处理

    Unix操作系统都采用了请求调页(demand paging)的内存分配策略,也就是在页还没有加载到内存时就先开始执行,随后导致异常,MMU内存管理单元开始处理加载内存

    类似的延迟处理也在调用malloc分配堆空间的时候,调用时只是修改了进程的堆内存区大小,等到真正使用的时候产生异常再分配页框

    同样的fork的CoW机制也是如此,被复制的子进程拥有同样于父进程的页映射(指向同一个物理页框),并且这些页框都标记为只读,一旦写入就会发生异常错误,随后初始化新的页框

  • 相关阅读:
    iptables学习
    老卫带你学---leetcode刷题(8. 字符串转换整数 (atoi))
    Java / Tensorflow - API 调用 pb 模型使用 GPU 推理
    Codeforces Round #835 (Div. 4) F. Quests
    python实例练习00001:打开文件输出文件内容
    2022“杭电杯” 中国大学生算法设计超级联赛(4)1 2 题解
    vscode中4个json的区别和联系
    修改YOLOV5的Backbone为shufflenetv2
    Java使用动态规划算法思想解决01背包问题
    鲜花销售管理系统,鲜花商城管理系统,鲜花网站毕业设计
  • 原文地址:https://blog.csdn.net/weixin_43988498/article/details/125464889