深入理解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. adb命令 判断锁屏

    通过adb命令获取手机是否锁屏状态,可以通过下面指令:1.adb shell dumpsys window policy |find "isStatusBarKeyguard"2. ...

  2. 第三方百度网盘客户端 PanDownload、速盘、panlight

    PanDownload PanDownload是一款能够快速下载百度网盘内资源的强大工具.PanDownload能够无限速高速下载,满速下载百度云盘里的各种资源.而且PanDownload完全免费,免 ...

  3. js语言评价--js 基于哈希表、原型链、作用域、属性类型可配置的多范式编程语言

    js 基于哈希表.原型链.作用域.属性类型可配置的多范式编程语言 值类型.引用类型.直接赋值: 原型是以对象形式存在的类型信息. ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值,对 ...

  4. 范式(Paradigm)是什么?

    Paradigm (范式) 是一个领域中主流的行事套路,它包括 philosophy (理念) 和 methods (方法)两部分.Philosophy (理念) 这个概念很好理解.比如,购物理念就是 ...

  5. mui 等待动画loading mui.showLoading

    显示加载框:mui.showLoading("正在加载..","div"); //加载文字和类型,plus环境中类型为div时强制以div方式显示隐藏加载框:m ...

  6. csp-s 考前刷题记录

    洛谷 P2615 神奇的幻方 洛谷 P2678 跳石头 洛谷 P1226 [模板]快速幂||取余运算 洛谷 P2661 信息传递 LOJ P10147 石子合并 LOJ P10148 能量项链 LOJ ...

  7. Aquameta 基于postgresql的web 开发平台

    Aquameta 是一个完全基于pg 开发的web平台 ,目前还在开发中. 当前支持的功能 meta 写入系统信息到pg bundle 基于pg 类似git 的文件系统 filesystem 双向文件 ...

  8. 使用mustache 做为docker容器运行动态配置工具

    很多时候我们需要在启动容器的时候基于配置文件运行,如果在配置比较简单的时候我们可以通过环境变量 注入,同时当前12 factors 越来越融入大家的开发中了(对于配置通过环境变量处理),但是好多老的软 ...

  9. c# 如何进行动态加载dll

    最近遇到了在c#中如何进行动态加载dll的话,搞定了,下面介绍一下自己的步骤. 1,新建dll. 打开vs,新建project->Class Library->项目名为testdll1.在 ...

  10. bzoj3745: [Coci2015]Norma 分治,单调队列

    链接 bzoj 思路 首先\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=i}^{j}max(a_k)\)可以用单调队列求解.参见 ...