《深入理解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命令来查看进程的状态,如果进程已经终止,就会删除这个进程
转载于:https://www.cnblogs.com/Xjng/p/11516471.html
《深入理解Linux内核》 读书笔记相关推荐
- 读书笔记 | 墨菲定律
1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...
- 读书笔记 | 墨菲定律(一)
1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...
- 洛克菲勒的38封信pdf下载_《洛克菲勒写给孩子的38封信》读书笔记
<洛克菲勒写给孩子的38封信>读书笔记 洛克菲勒写给孩子的38封信 第1封信:起点不决定终点 人人生而平等,但这种平等是权利与法律意义上的平等,与经济和文化优势无关 第2封信:运气靠策划 ...
- 股神大家了解多少?深度剖析股神巴菲特
股神巴菲特是金融界里的传奇,大家是否都对股神巴菲特感兴趣呢?大家对股神了解多少?小编最近在QR社区发现了<阿尔法狗与巴菲特>,里面记载了许多股神巴菲特的人生经历,今天小编简单说一说关于股神 ...
- 2014巴菲特股东大会及巴菲特创业分享
沃伦·巴菲特,这位传奇人物.在美国,巴菲特被称为"先知".在中国,他更多的被喻为"股神",巴菲特在11岁时第一次购买股票以来,白手起家缔造了一个千亿规模的 ...
- 《成为沃伦·巴菲特》笔记与感想
本文首发于微信公众帐号: 一界码农(The_hard_the_luckier) 无需授权即可转载: 甚至无需保留以上版权声明-- 沃伦·巴菲特传记的纪录片 http://www.bilibili.co ...
- 读书笔记002:托尼.巴赞之快速阅读
读书笔记002:托尼.巴赞之快速阅读 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<快速阅读>之后,我们就可以可以快速提高阅读速度,保持并改善理解嗯嗯管理,通过增进了解眼睛和大脑功能 ...
- 读书笔记001:托尼.巴赞之开动大脑
读书笔记001:托尼.巴赞之开动大脑 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<开动大脑>之后,我们就可以对我们的大脑有更多的了解:大脑可以进行比我们预期多得多的工作:我们可以最 ...
- 读书笔记003:托尼.巴赞之思维导图
读书笔记003:托尼.巴赞之思维导图 托尼.巴赞的<思维导图>一书,详细的介绍了思维发展的新概念--放射性思维:如何利用思维导图实施你的放射性思维,实现你的创造性思维,从而给出一种深刻的智 ...
- 产品读书《滚雪球:巴菲特和他的财富人生》
作者简介 艾丽斯.施罗德,曾经担任世界知名投行摩根士丹利的董事总经理,因为撰写研究报告与巴菲特相识.业务上的往来使得施罗德有更多的机会与巴菲特亲密接触,她不仅是巴菲特别的忘年交,她也是第一个向巴菲特建 ...
最新文章
- web前端开发培训完就业前景怎么样
- java WEB 基础复习_开篇--Java Web基础知识
- 【MATLAB】进阶绘图 ( colormap 颜色图矩阵分析 | 自定义 colormap 颜色图 | 生成 64 x 3 的 colormap 颜色图矩阵 )
- mysql 单表查询
- 转发:为什么函数式编程至关重要
- Storm 04_Storm单机模式搭建完全分布式安装部署集群drpc
- 洛谷T172098 子串-substr
- Linux下Shell文件内容替换(sed)(转)
- linux_bash_shell_cheat_sheet(自译)
- SVM中引入拉格朗日对偶理解
- 3d激光雷达开发(icp匹配)
- matlab负荷分配程序,利用MATLAB工具箱进行机组负荷优化分配
- C# Winform用户体验整理【原】
- easypoi的学习笔记
- HTTP协议原理与代码实践之大纲
- ad9原理图转到orcad capture16.5
- SPSS——相关分析——Pearson简单相关系数
- python玫瑰花数量的含义_玫瑰花数量代表的含义
- Java中的23种设计模式的介绍
- 5月全球CTF比赛时间汇总来了!
热门文章
- Matlab实用代码——定位文件位置,自动导入文件
- Matlab使用过程中内存不足问题的总结(修改)
- python gridsearch_Python超参数自动搜索模块GridSearchCV上手
- 基于BERT 的中文数据集下的命名实体识别(NER)
- 两个变量相乘_自动控制原理-信号流图与系统状态变量传递函数之间联系如此紧密...
- 动态改变标题_小米相册更新,新增动态换天/赛博朋克/MIUI12界面等等!
- python oop 继承_关于oop:使类数据在python中可继承的正确方法是什么?
- Oracle数据库完全卸载
- Linux下创建指定路径下的文件夹/文件,通过get_option()传递路径
- 筛选出英语与计算机成绩之和,职称计算机和英语考试的成绩什么地方能够查到 – 手机爱问...