《深入理解Linux内核》 读书笔记
深入理解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
- 修改时间等
- 访问权限
- inode有(通过ll命令看到的):
- 每个文件都有一个索引节点(inode)的数据结构,用来存储文件的描述信息,和文件的内容是区分开的。
- 访问权限和文件模式
- 拥有者,组,其他人,各有读写执行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字节
- 物理地址。内存芯片级的地址
- 逻辑地址,经过分段单元,转换为线性地址,线性地址,经过分页单元,转换为物理地址
- 内存地址有3种
- 分段单元(用于把逻辑地址,转换为线性地址)
- 概念
- 段选择符,也叫段标识符,也就是上面说的段,程序传入给分段单元。有字段:
- 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是段描述符
- 段选择符,也叫段标识符,也就是上面说的段,程序传入给分段单元。有字段:
- 转换流程
- 传入逻辑地址给分段单元,逻辑地址包含段选择符和偏移量
- 查看段选择符的TI字段,决定是从GDT中还是LDT中获取段描述符,假如是GDT
- 查看段选择符的index字段,假如是2,从gdtr寄存器中获取GDT列表的首字节地址,假如是0x00002000,计算段描述符的位置=0x00002000+2*8,=0x00002016 (每个段描述符8字节),所以段描述符在内存的0x00002016-0x00002024位置
- 查看段描述符的Base字段,假如是0x00003000,加上偏移量,假如是100,得到线性地址是0x00003100
- 概念
三、进程
进程,轻量级进程(LWP)和线程
- 进程是程序执行时的一个实例
- 线程 是进程里面的一个执行流,线程的切换时在用户态进行的。但是这样就不能做到并发了
- 轻量级进程,类似线程,但是切换时在内核态进行
所以Linux的做法是(TODO 这一块还不是很明白)
- 把线程和轻量级进程关联起来,所以线程和轻量级进程是等价的
- 对内核来说,进程和LWP是一样的,使用同样的调度方法
- LWP之间可以共享部分数据
进程描述符
进程描述符是一个数据结构(c的struct,类似Python的字典)
- 进程描述符有字段:
- state 状态
- 可运行状态(TASK_RUNNING),要么在运行,要么准备运行
- 可中断的等待状态(TASK_INTERRUPTIBLE)进程被挂起(睡眠),表示它在等待一个事件的发生,例如等待某个系统资源。当这个系统资源可用,内核会产生一个硬件中断,来唤醒进程
- 不可中断的等待状态(TASK_UNINTERRUPTIBLE),和可中断的等待状态类似,这个状态较少用到
- 暂停状态(TASK_TOPPED)进程被暂停执行,当进程收到信号SIGSTOP,SIGSTP,SIGTTIN SIGTTOU信号后,会进入暂停状态
- 跟踪状态(TASK_TRACED)当进程被另一个进程跟踪,例如执行ptrace命令,
- 僵死状态(EXIT_ZOMBIE)进程的执行被终止,但是父进程还没有发布wait4或者waitpid命令来获取进程信息。这时内核不会自动丢弃进程的信息,因为父进程可能还需要这些信息
10.僵死撤销状态
- thread_info 进程的基本信息
- fs_struct 当前目录
- signal_struct 收到的信号
- pid 进程的ID。顺序递增,最大是32767,超过后,从1开始获取闲置的PID值。进程里面的线程,也拥有自己的pid,同时每个线程有一个tgid(thread group id),表示线程组ID,这个ID等于进程中第一个线程的pid。
- 一个进程里面至少有一个线程
- state 状态
进程链表
- 一个进程描述符表示一个进程
- 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内核》 读书笔记的更多相关文章
- csapp读书笔记-并发编程
这是基础,理解不能有偏差 如果线程/进程的逻辑控制流在时间上重叠,那么就是并发的.我们可以将并发看成是一种os内核用来运行多个应用程序的实例,但是并发不仅在内核,在应用程序中的角色也很重要. 在应用级 ...
- CSAPP 读书笔记 - 2.31练习题
根据等式(2-14) 假如w = 4 数值范围在-8 ~ 7之间 2^w = 16 x = 5, y = 4的情况下面 x + y = 9 >=2 ^(w-1) 属于第一种情况 sum = x ...
- CSAPP读书笔记--第八章 异常控制流
第八章 异常控制流 2017-11-14 概述 控制转移序列叫做控制流.目前为止,我们学过两种改变控制流的方式: 1)跳转和分支: 2)调用和返回. 但是上面的方法只能控制程序本身,发生以下系统状态的 ...
- CSAPP 并发编程读书笔记
CSAPP 并发编程笔记 并发和并行 并发:Concurrency,只要时间上重叠就算并发,可以是单处理器交替处理 并行:Parallel,属于并发的一种特殊情况(真子集),多核/多 CPU 同时处理 ...
- 读书笔记汇总 - SQL必知必会(第4版)
本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...
- 读书笔记--SQL必知必会18--视图
读书笔记--SQL必知必会18--视图 18.1 视图 视图是虚拟的表,只包含使用时动态检索数据的查询. 也就是说作为视图,它不包含任何列和数据,包含的是一个查询. 18.1.1 为什么使用视图 重用 ...
- 《C#本质论》读书笔记(18)多线程处理
.NET Framework 4.0 看(本质论第3版) .NET Framework 4.5 看(本质论第4版) .NET 4.0为多线程引入了两组新API:TPL(Task Parallel Li ...
- C#温故知新:《C#图解教程》读书笔记系列
一.此书到底何方神圣? 本书是广受赞誉C#图解教程的最新版本.作者在本书中创造了一种全新的可视化叙述方式,以图文并茂的形式.朴实简洁的文字,并辅之以大量表格和代码示例,全面.直观地阐述了C#语言的各种 ...
- C#刨根究底:《你必须知道的.NET》读书笔记系列
一.此书到底何方神圣? <你必须知道的.NET>来自于微软MVP—王涛(网名:AnyTao,博客园大牛之一,其博客地址为:http://anytao.cnblogs.com/)的最新技术心 ...
- Web高级征程:《大型网站技术架构》读书笔记系列
一.此书到底何方神圣? <大型网站技术架构:核心原理与案例分析>通过梳理大型网站技术发展历程,剖析大型网站技术架构模式,深入讲述大型互联网架构设计的核心原理,并通过一组典型网站技术架构设计 ...
随机推荐
- adb命令 判断锁屏
通过adb命令获取手机是否锁屏状态,可以通过下面指令:1.adb shell dumpsys window policy |find "isStatusBarKeyguard"2. ...
- 第三方百度网盘客户端 PanDownload、速盘、panlight
PanDownload PanDownload是一款能够快速下载百度网盘内资源的强大工具.PanDownload能够无限速高速下载,满速下载百度云盘里的各种资源.而且PanDownload完全免费,免 ...
- js语言评价--js 基于哈希表、原型链、作用域、属性类型可配置的多范式编程语言
js 基于哈希表.原型链.作用域.属性类型可配置的多范式编程语言 值类型.引用类型.直接赋值: 原型是以对象形式存在的类型信息. ECMA-262把对象定义为:无序属性的集合,其属性可以包含基本值,对 ...
- 范式(Paradigm)是什么?
Paradigm (范式) 是一个领域中主流的行事套路,它包括 philosophy (理念) 和 methods (方法)两部分.Philosophy (理念) 这个概念很好理解.比如,购物理念就是 ...
- mui 等待动画loading mui.showLoading
显示加载框:mui.showLoading("正在加载..","div"); //加载文字和类型,plus环境中类型为div时强制以div方式显示隐藏加载框:m ...
- csp-s 考前刷题记录
洛谷 P2615 神奇的幻方 洛谷 P2678 跳石头 洛谷 P1226 [模板]快速幂||取余运算 洛谷 P2661 信息传递 LOJ P10147 石子合并 LOJ P10148 能量项链 LOJ ...
- Aquameta 基于postgresql的web 开发平台
Aquameta 是一个完全基于pg 开发的web平台 ,目前还在开发中. 当前支持的功能 meta 写入系统信息到pg bundle 基于pg 类似git 的文件系统 filesystem 双向文件 ...
- 使用mustache 做为docker容器运行动态配置工具
很多时候我们需要在启动容器的时候基于配置文件运行,如果在配置比较简单的时候我们可以通过环境变量 注入,同时当前12 factors 越来越融入大家的开发中了(对于配置通过环境变量处理),但是好多老的软 ...
- c# 如何进行动态加载dll
最近遇到了在c#中如何进行动态加载dll的话,搞定了,下面介绍一下自己的步骤. 1,新建dll. 打开vs,新建project->Class Library->项目名为testdll1.在 ...
- bzoj3745: [Coci2015]Norma 分治,单调队列
链接 bzoj 思路 首先\(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{k=i}^{j}max(a_k)\)可以用单调队列求解.参见 ...