深入理解Linux内核 读书笔记

一、概论

操作系统基本概念

  • 多用户系统

    • 允许多个用户登录系统,不同用户之间的有私有的空间
  • 用户和组
    • 每个用于属于一个组,组的权限和其他人的权限,和拥有者的权限不一样。对应的是Linux的文件权限系统
  • 进程
    • 和程序的区别。几个进程能并发执行同一个程序,一个进程能顺序执行几个程序
    • 程序更像是代码片段,进程是执行代码的容器
    • linux是抢占式操作系统,也就是一个进程只能占用CPU一段时间。非抢占式系统中,进程如果不释放CPU,可以一直占用
  • 内核体系结构
    • Linux是单块内核,同时提供模块(module)功能
    • 模块是指:例如一个程序,引用了一个系统模块,这个系统模块不会是这个进程单独拥有,当其他程序也需要这个模块时,内核会把这个模块链接到其他程序。这样可以节省内存,也就是这个模块只会在内存中存在一份。模块就是一组函数,或者一段代码。

文件系统

  • 文件

    • 文件是以字节序列组成的信息载体(container)
    • 文件目录是树结构
    • 每个进程都有一个工作目录,通过pwdx 进程ID 命令可以查看
  • 硬链接和软连接
    • 链接类似window的快捷方式,创建一个文件,指向另一个文件
    • ln p1 p2 就是创建一个文件p2,指向p1
    • 硬链接只能指向文件,不能指向目录,因为会导致循环指向
    • 硬链接只能指向同一个文件系统的文件(文件系统是物理划分,例如不同硬盘)
    • 软链接没有硬链接这些限制,创建方法是加-s参数
  • 文件类型
    • 普通文件
    • 目录
    • 符号链接
    • 面向块的设备文件
    • 面向字符的设备文件
    • 管道和命名管道(pipe named pipe)
    • 套接字(socket)
  • 文件描述符与索引节点
    • 每个文件都有一个索引节点(inode)的数据结构,用来存储文件的描述信息,和文件的内容是区分开的。

      • inode有(通过ll命令看到的):

        • 文件类型
        • 硬链接个数
        • 文件长度
        • 文件拥有者的uid
        • 用户组的id
        • 修改时间等
        • 访问权限
  • 访问权限和文件模式
    • 拥有者,组,其他人,各有读写执行3种权限
  • 文件操作
    • 打开文件
    • 移动光标
    • 关闭

Unix内核概述

  • 进程/内核模式

    • 进程有用户态和内核态
    • 用户态不能访问内核的数据结构和内核程序
    • 两种态会经常切换,例如在时刻A,进程在用户态,在时刻B,进程在内核态
    • 从用户态切换到内核态的情况:
      • 调用系统调用
      • 执行进程的CPU发送异常
      • 外围设备向CPU发出中断
      • 内核线程被执行
  • 进程
    • 每个进程有一个进程ID,pid
    • 内核切换执行的进程时,会保存旧进程的信息,包括:
      • 程序计数器和栈指针寄存器
      • 通用寄存器
      • 浮点寄存器
      • CPU状态
      • 内存管理寄存器
  • 可重入内核
    • unix内核都是可重入的
    • 可重入是指,可以被重复进入,也就是可以同时有多个进程处于内核态
  • 进程地址空间
    • 每个进程有自己私有的地址空间
  • 同步和临界区
    • 类似锁
    • linux是抢占式内核,所以需要同步
    • 信号量
      • 每个资源都有一个信号量,类似int类型,初始值是1
      • 每个进程访问资源,调用down方法,信号量减1,如果减1后,信号量小于0,进程被加入到访问队列中。如果大于等于0,进程可以访问资源
      • 每个进程访问完资源,调用up方法,信号量加1,如果信号量大于等于0,激活访问队列的第一个进程
      • 进程锁,线程锁的机制,应该都是这样的
      • 这里要保证down和up的操作都是原子性的,不能并发
      • 要防止死锁
      • 锁里面的区域就是临界区,也就是acquire和release之间的代码
  • 信号和进程间通信
    • 信号和信号量是不一样的
    • linux有20多种不同的信号,例如kill -9 中的 9就是一种信号
    • 进程收到信号后,可以
      • 忽略
      • 异步执行指定程序(新开一个线程?),这种需要事先定义信号处理函数。
    • 内核收到信号后,可以
      • 终止进程(例如kill - 9)
      • 忽略信号
      • 挂起进程
      • 恢复进程
    • 进程间通信(IPC)
      • 信号
      • 消息(msgget(),msgsnd())两个系统调用,发信息和收信息,Python里面的进程间Queue应该就是用这个实现的
      • 共享内存(shmget shmdt)两个系统调用
  • 进程管理
    • fork来启动一个子进程,一般在启动的时候复制父进程的数据和代码,但是这样效率较低,所以会使用写时复制,也就是一开始父子进程共享内存,当其中一个进程需要修改数据时,才执行复制操作
    • exec用于启动子进程
    • exit用于结束子进程
    • wait4用于父进程等待子进程结束
  • 内存管理
    • 虚拟内存,在物理内存(MMU)和程序之间的抽象,相当于访问内存的代理。
    • 内核内存分配器,KMA,用于管理内存
    • 高速缓存 由于内存比硬盘快很多,所以从硬盘读取得数据会缓存在内存,使下次可以快速访问
    • 二、内存寻址

  • 内存地址
    • 内存地址有3种

      • 逻辑地址,由一个段(segment)和偏移量(offset)组成,用来指明一个操作数,或者一条指令的地址
      • 线性地址。是一个32位无符号整数(在32位系统中是这样),从0x00000000到0xffffffff。内存相当于一个超大的列表,下标(地址)是一个32位整数,值就是内存的内容,值得大小是1字节
      • 物理地址。内存芯片级的地址
    • 逻辑地址,经过分段单元,转换为线性地址,线性地址,经过分页单元,转换为物理地址
  • 分段单元(用于把逻辑地址,转换为线性地址)
    • 概念

      • 段选择符,也叫段标识符,也就是上面说的段,程序传入给分段单元。有字段:

        • index,表示段描述符在GDT或者LDT中下标
        • TI,表示段描述符在GDT中还是LDT中
        • RPL,特权级
      • 段描述符,8字节,存放在GDT或者LDT中,有字段
        • Base表示段在内存中首字节的线性地址
        • S,0表示系统段,1表示普通段
        • DPL,特权级,0表示只有内核态才能访问,3表示内核态和用户态都能访问。(cs寄存器中,有一个两位的字段,指明CPU的当前特权级,0表示内核级,3表示用户级。所以通过这个机制,可以限制用户态的进程不能访问内核态的内存数据
        • D或者B,表示这是代码段,还是数据段
      • GDT,是全局段列表,item是段描述符
      • LDT,是局部段列表,item是段描述符
    • 转换流程
      1. 传入逻辑地址给分段单元,逻辑地址包含段选择符和偏移量
      2. 查看段选择符的TI字段,决定是从GDT中还是LDT中获取段描述符,假如是GDT
      3. 查看段选择符的index字段,假如是2,从gdtr寄存器中获取GDT列表的首字节地址,假如是0x00002000,计算段描述符的位置=0x00002000+2*8,=0x00002016 (每个段描述符8字节),所以段描述符在内存的0x00002016-0x00002024位置
      4. 查看段描述符的Base字段,假如是0x00003000,加上偏移量,假如是100,得到线性地址是0x00003100

三、进程

进程,轻量级进程(LWP)和线程

  • 进程是程序执行时的一个实例
  • 线程 是进程里面的一个执行流,线程的切换时在用户态进行的。但是这样就不能做到并发了
  • 轻量级进程,类似线程,但是切换时在内核态进行

所以Linux的做法是(TODO 这一块还不是很明白)

  • 把线程和轻量级进程关联起来,所以线程和轻量级进程是等价的
  • 对内核来说,进程和LWP是一样的,使用同样的调度方法
  • LWP之间可以共享部分数据

进程描述符

  1. 进程描述符是一个数据结构(c的struct,类似Python的字典)

  2. 进程描述符有字段:
    1. state 状态

      1. 可运行状态(TASK_RUNNING),要么在运行,要么准备运行
      2. 可中断的等待状态(TASK_INTERRUPTIBLE)进程被挂起(睡眠),表示它在等待一个事件的发生,例如等待某个系统资源。当这个系统资源可用,内核会产生一个硬件中断,来唤醒进程
      3. 不可中断的等待状态(TASK_UNINTERRUPTIBLE),和可中断的等待状态类似,这个状态较少用到
      4. 暂停状态(TASK_TOPPED)进程被暂停执行,当进程收到信号SIGSTOP,SIGSTP,SIGTTIN SIGTTOU信号后,会进入暂停状态
      5. 跟踪状态(TASK_TRACED)当进程被另一个进程跟踪,例如执行ptrace命令,
      6. 僵死状态(EXIT_ZOMBIE)进程的执行被终止,但是父进程还没有发布wait4或者waitpid命令来获取进程信息。这时内核不会自动丢弃进程的信息,因为父进程可能还需要这些信息
        10.僵死撤销状态
    2. thread_info 进程的基本信息
    3. fs_struct 当前目录
    4. signal_struct 收到的信号
    5. pid 进程的ID。顺序递增,最大是32767,超过后,从1开始获取闲置的PID值。进程里面的线程,也拥有自己的pid,同时每个线程有一个tgid(thread group id),表示线程组ID,这个ID等于进程中第一个线程的pid。
      1. 一个进程里面至少有一个线程

进程链表

  • 一个进程描述符表示一个进程
  • Linux把所有进程放在一个双向链表里面,每个item是一个进程描述符
  • TASK_RUNNING状态的进程链表
    • 由于CPU在进行进程切换时,需要快速知道下一个执行的进程是什么,所以Linux把所有可以执行的进程都放在一个单独的链表。
    • 由于不同进程有不同的优先级,所以linux的做法是
      • 由于有140种优先级(优先级用prio表示,0-139),所以用140个链表来保存
      • 用一个140长度的位图(bitmap)来表示140个链接中,哪些有数据
      • 所以获取下一个优先级最高的进程的做法是:
        • 查看位图,看第一个=1的位的下标是多少,例如是15
        • 访问第15个链表,queue[15],获取第一个元素

进程间的关系

进程描述符里面有特定的字段,记录每个进程的父进程,兄弟进程和子进程

  • real_parent 父进程的描述符指针,如果父进程不存在,指向进程1
  • parent 当前父进程,通常和real_parent一致,指引当进程被追踪时不一致
  • children 链表,记录所有子进程
  • sibling 有prev和next两个元素,表示上一个兄弟进程,和下一个兄弟进程

pidhash

有时候内核需要根据pid来获取进程描述符
所以内核会保存一个pidhash数据结构,是个hash表(c里面的hash表的实现和redis的hash表实现类似),key是pid,value是进程描述符

进程切换

进程切换,任务切换,上下文切换是一样的

每个进程都有自己的地址空间(在内存),但是进程之间是共享寄存器的,所以进程的切换需要(硬件上下文是寄存器的数据):

  • 保存prev进程的硬件上下文
  • 用next硬件上下文替换prev

上面的操作使用一个switch_to宏来实现,传入参数prev,next,prev。传入两次prev是怕切换上下文后,把第一个prev丢了。

创建进程

Linux进程的特性:

  • 写时复制
  • 轻量级进程允许父子进程共享很多数据结构

创建进程的系统调用:

  • close()

    • fn 子进程创建后执行的函数,函数结束,子进程终止
    • arg 传给函数的数据
    • 其他还有很多参数
  • fork close函数的封装
  • vfork close函数的封装

内核进程

内核进程是一直运行在内核态的

进程0
进程0是linux启动后的第一个进程,由它创建进程1
进程1
进程1也叫init进程,进程1会一直运行知道linux关闭

撤销进程

进程执行完指定的代码后,就会终止,这时必须通知内核回收进程的资源。
一般是exit系统调用,c编译程序会自己动把exit函数插入到main函数最后
内核可以强迫整个线程组死掉(例如收到kill -9)

进程删除
当进程终止后,进程会进入僵死状态,直到父进程调用wait4来获取进程的状态数据,然后进程就会被删除。
如果父进程已经不存在,进程会交给init进程托管,init进程会定期执行wait4命令来查看进程的状态,如果进程已经终止,就会删除这个进程

《深入理解Linux内核》 读书笔记的更多相关文章

  1. csapp读书笔记-并发编程

    这是基础,理解不能有偏差 如果线程/进程的逻辑控制流在时间上重叠,那么就是并发的.我们可以将并发看成是一种os内核用来运行多个应用程序的实例,但是并发不仅在内核,在应用程序中的角色也很重要. 在应用级 ...

  2. CSAPP 读书笔记 - 2.31练习题

    根据等式(2-14) 假如w = 4 数值范围在-8 ~ 7之间 2^w = 16 x = 5, y = 4的情况下面 x + y = 9 >=2 ^(w-1)  属于第一种情况 sum = x ...

  3. CSAPP读书笔记--第八章 异常控制流

    第八章 异常控制流 2017-11-14 概述 控制转移序列叫做控制流.目前为止,我们学过两种改变控制流的方式: 1)跳转和分支: 2)调用和返回. 但是上面的方法只能控制程序本身,发生以下系统状态的 ...

  4. CSAPP 并发编程读书笔记

    CSAPP 并发编程笔记 并发和并行 并发:Concurrency,只要时间上重叠就算并发,可以是单处理器交替处理 并行:Parallel,属于并发的一种特殊情况(真子集),多核/多 CPU 同时处理 ...

  5. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  6. 读书笔记--SQL必知必会18--视图

    读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...

  7. 《C#本质论》读书笔记(18)多线程处理

    .NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...

  8. C#温故知新:《C#图解教程》读书笔记系列

    一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种 ...

  9. C#刨根究底:《你必须知道的.NET》读书笔记系列

    一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...

  10. Web高级征程:《大型网站技术架构》读书笔记系列

    一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术发展历程,剖析大型网站技术架构模式,深入讲述大型互联网架构设计的核心原理,并通过一组典型网站技术架构设计 ...

随机推荐

  1. Bean property ‘mapperHelper’ is not writable or has an invalid setter method. Does the parameter type of the setter match the return type of the getter?

    spring boot 报错: Caused by: org.springframework.beans.NotWritablePropertyException: Invalid property ...

  2. koa-session 知识点

    github 网址:https://github.com/koajs/session session 是一个对象

  3. Spring Boot + Mybatis 配置多数据源

    Spring Boot + Mybatis 配置多数据源 Mybatis拦截器,字段名大写转小写 package com.sgcc.tysj.s.common.mybatis; import java ...

  4. 安装GO

    1.中文社区 下载地址   https://studygolang.com/dl    选择自己操作系统版本 2.找到适合你系统的版本下载,本人下载的是windows版本.也可以下载Source自己更 ...

  5. Spring,Spring MVC,Spring Boot 三者比较

    Spring,Spring MVC,Spring Boot 三者比较 Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等.但他们的基础都是Spring 的 io ...

  6. (11)树莓派3 有线网卡静态IP设置

    https://www.cnblogs.com/10e-6/p/5778355.html 树莓派设置静态IP地址 首先终端输入: ifconfig 查看树莓派默认分配的动态IP地址. 图 1-4 配置 ...

  7. springcloud(三)

    雪崩效应 一.为什么需要 Hystrix? 在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用(RPC).为了保证其高可用,单个服务又必须集群部署.由于网络原因或者自身的原因,服 ...

  8. kuma kong 团队开发的可视化&&安全的service mesh

    最近service mesh 的开源产品是越来越多了,好多团队都开源了自己的解决方案 maesh 最近kong 团队也开源了自己的service meshkuma 一张参考图 说明 kuma 没有基于 ...

  9. cube.js 通过presto-gateway 进行连接

    cube.js 对于presto 的支持是通过presto-client 刚好简单修改了一个可以支持presto-gateway 连接的 以下是一个简单的集成,以及关于集成中原有的一些修改 环境准备 ...

  10. 将zabbix服务和monitor服务在一个机器上部署

    问题,两个服务的文件路径都是 /usr/local/sdata下,要让两个服务共存,至少需要讲一个服务的文件迁移到别的文件夹,同时将所有的配置项都进行修改,使能找到指定的文件路径, 方案1,先按照za ...