由于上传图片大小限制,以下文本复制进xmind 进行显示查看,效果最佳,
简要概述
2.6.24 版本
内核的任务
内核屏蔽计算机的一系列操作,增强的计算机
资源管理程序
视为库,提供一组面向系统的命令
实现策略
微内核
中央内核(即微内核)实现
所有其他的功能都委托给一些独立进程,这些进程通过明确定义的通信接口与中心内核通信
独立进程可能负责实现各种文件系统、内存管理等
宏内核
构建系统内核的传统方法
模块特性依赖于内核与用户层之间设计精巧的通信方法,这使得模块的热插拔和动态装载得以实现
内核的组成部分
进程、切换、调度
unix 进程
Linux对进程采用了一种层次系统,每个进程都依赖于一个父进程。
UNIX操作系统中有两种创建新进程的机制
fork
父进程内存的内容将被复制
都执行同样的操作
在只读访问的情况下父进程和子进程可以共用同一内存页
exec
exec将一个新程序加载到当前进程的内存中并执行
旧程序的内存页将刷出,其内容将替换为新的数据。然后开始执行新程序
线程
线程和主程序共享同样的地址空间
Linux用clone方法创建线程
命名空间
地址空间与特权级别
CPU的字长决定了所能管理的地址空间的最大长度
2^32B=4GiB
2^64B=
地址空间的最大长度与实际可用的物理内存数量无关
称为虚拟地址空间
应用程序无需关注其他程序的存在,好像计算机中只有一个进程一样
Linux将虚拟地址空间划分为两个部分
内核空间
用户空间
64位计算机的情况
虚拟地址空间会包含一些不可寻址的洞
在第4章更详细地讨论该主题
特权级别
英特尔处理器区分4种特权级别
CPU都提供了几种特权级别
每个特权级别都有各种限制
执行某些汇编语言指令或访问虚拟地址空间某一特定部分的限制
IA-32体系结构使用4种特权级别构成
IA-32体系结构使用4种特权级别构成的系统,各级别可以看作是环。内环能够访问更多的功能,外环则较少
Linux只使用两种不同的状态:核心态和用户状态
用户态无法访问内核态的空间,读写内核空间数据,也无法执行内核中的代码
从用户状态到核心态的切换通过系统调用的特定转换手段完成
系统调用向内核发出请求
内核还可以由异步硬件中断激活
无法访问用户空间
在中断上下文中,内核必须比正常情况更加谨慎,例如不能进入睡眠
普通线程与内核线程
内核线程可以进入睡眠状态
进程一样被调度器跟踪
内核线程可用于各种用途:从内存和块设备之间的数据同步,到帮助调度器在CPU上分配进程。
虚拟和物理地址空间
页表来为物理地址分配虚拟地址
虚拟地址关系到进程的用户空间和内核空间
物理地址用来寻址实际可用空间
虚拟地址与物理地址被划分为等长的部分,称为页
物理内存页经常称为页帧
页则专指需内地址空间的页
进程间可以共享物理内存页
由内核决定
并不是所有的虚拟页都映射到页帧
有可能没有使用
有可能尚未使用未载入内存
有可能换出到硬盘,需要时在换回
页表
用来表述虚拟内存与物理内存的映射关系-数据结构
三级页表项
全局页目录(GPD)
指向 PMD 的启示地址
中间页表项(PMD)
指向 PTE
页表数组(PTE)
偏移量
四级页表项
MMU
不管是三级还是四级页表 CPU 访问都要逐级访问
所以有了 MMU 内存管理单元 - 优化了内存访问
最频繁的放到后备地址缓冲器 (TLB)
与 CPU 交互
IA-32
使用了两级页表
64位,Alpha、Sparc64、IA-64
需要使用三级或四级页表
内核与体系结构无关的部分总是假定使用四级页表
内存映射
重要抽象手段
内核中大量使用
用于用户应用程序
可以将任意来源得数据传输到进程得虚拟空间中
作为映射目标得地址空间区域,可以像普通内存那样用通常得方法访问,任何修改传递到原数据源
程序操作内存
内核保证任何修改都同步到文件中
内核在实现设备驱动程序时,使用了内存映射
输入输出映射到地址空间区域中
内存读写重定向到设备
物理内存分配
必须记录页帧的状态(分配或空闲)
避免使用到同样的内存区域
内存分配释放频繁
必须保证操作尽快完成
内核可以只分配页帧
用户标准库可以把页帧划分为更小的部分工作
伙伴系统
分配连续页
为了快速检测内存中的连续区域
空闲内存块总是两两分组,每组中的两块称为伙伴
频繁的分配释放会导致内存碎片
大块连续中间恰好分配出去一个页
slab 缓存
内核本身需要比页帧小的多的内存块
因此必须在伙伴的基础上自行定义额外的内存管理层
将伙伴系统提供的页划分为更小的部分
不仅可以分配内存
为小对象提供了一个一般性的缓存 slab 缓存
内核定义了所需类型对象的实例缓存(类似于内存池)
需要时可以从对应的缓存快速分配
slab 与伙伴系统交互,在缓存用尽时申请新的页帧
通常的小内存分配
针对不同大小的对象一组 slab 缓存
kmalloc
kfree
虽然在各种工作下负荷的性能很好
规模庞大的超级计算机
出现可伸缩性的问题
微小的嵌入式
开销又太大了
提供了两种备选方案
slab 是内核的标准方法
不详细讨论备选方案
三种方案接口相同
页面交换和页面回收
通过利用磁盘空间作为扩展内存,增大可用内存
内核需要更多内存是,不需要经常使用的页可以写入磁盘
需要访问时,将相应的页切换回内存
操作对应用程序是透明的
换出的页可以通过特别的页表项标识
在进程试图访问此类页帧时,cpu 则启动一个可以被内核截取的缺页异常
此时内核可以将硬盘数据切换回内存中,用户进程回复运行
页面回收用于
将内存映射被修改的内容与地城块设备同步
数据刷出后,页帧将用于其他用途
内核数据结构包含了相关信息
从硬盘找到相应音系数据加载
记时
测量时间以及不同时间点的时差
进程调度就会用到
jiffies
时间坐标
jiffies
jiffies_64
取决于内核的一个常熟 100-1000
颗粒度较粗
可使用高分辨率的计时手段
以纳秒级精确度和分辨率来计量
系统调用
用户进程与内核交互的经典方法
POSIX 定义了很多系统调用
传统的系统调用按不同类别分组
进程管理
创建新进程,查询信息,调试
信号
发送信号、定时器以及相关吹机制
文件
创建、打开和关闭文件、从文件读取和向文件写入,查询信息和状态
目录和文件系统
创建、删除和重命名目录、查询信息、链接、变更目录
保护机制
读取和变更UID/GID
命名空间处理
定时器函数
定时器函数和统计
设备驱动程序、块设备和字符设备
万物皆文件
/dev
适当的方式读取写入数据
字符设备
顺序读取
块设备
复杂
广泛的使用了缓存
512B 的倍数读写
网络
采用了源于 BSD 的套接字抽象
套接字看作程序、文件、内核的网络实现代理
文件系统
EXt2
基于inode
每个文件构造了一个单独的管理结构(inode)
EXT3
Reiserfs、xfs、vfat
模块与热插拔
模块用于运行时向内核添加功能
驱动程序
文件系统
网络协议
缓存
内核通过基于页得内存映射来实现访问块设备得
缓存也按页组织
页缓存
链表处理
list_head
next
prev
函数
list_add
list_add_tail
list_del
list_empty
list_splice
list_entry
list_for_each
对象管理和引用计数
2.5 一般性内核对象机制
引用计数
管理对象链表(集合)
集合加锁
将对象属性导出到用户空间
通过 sysfs 文件系统
对象集合
内核对象第一例子
kset
kobj_type
引用计数
kref
数据类型
类型定义
typedef 定义各种数据类型
处理器上标准数据类型得位长可能都不相同
sector_t
块设备扇区编号
pid_t
进程ID
__s8 __u8
若干整数数据类型,有符号无符号等
为允许数据在各个系统之间交换
字节序
大端序
小端序
per-cpu 变量
DEFINE_PER_CPU (name,type)
访问用户空间
源码中多处指针标记为 __user
用户空间未知
内核用来标识执行用户地址空间中区域得指针
没有预防措施不能轻易访问
局限性
为什么内核是特别的
代码
并发安全,可重入的和安全的
进程管理和调度
进程优先级
进程生命周期
进程状态
运行
正在执行
等待
可以执行,但没有资源,调度器下一次可以选择
睡眠
因为等待外部事件,调度器下一次无法选择
终止
僵尸
抢占式多任务处理
进程状态
用户态
内核态
建立了一个层次结构
判断哪些进程状态可以由其他状态抢占
普通进程总是可能被抢占
如果系统处在核心态,并处理系统调用
进程表示
task_struct
定义在include/sched.h中
进程管理相关的系统调用
调度器实现
完全公平调度类
实时调度类
调度器曾倩
内存管理
概述
内存中的物理内存页的管理
分配大块内存的伙伴系统
分配较小块内存的 slab、slub、slob 分配器
分配非连续内存块的 vmalloc
进程的地址空间
进程虚拟内存