1 介绍
每个程序员对于阅读内核,以及往内核中打补丁patch作为一种荣耀。Linux内核大体的模块主要包括四大部分:
进程管理(调度,创建,内核线程等);
内存管理(物理内存和虚拟内存);
文件系统(虚拟文件系统VFS,真实的实时文件系统ext3/ext4)
内核协议栈:可参考网上的ntytcp
2 内核源码目录
如下是内核Linux4.4.4版本的内核文件内容
内核版本号含义:
V4.12.24: 4:主版本号 12:次版本号(奇数为测试版,偶数稳定版) 24:当前版本修复上个版本的补丁
3 进程原理
3.1 定义
在内核中用task_struct来描述,它的虚拟地址空间分为:用户虚拟地空间和内核虚拟地址空间。
虚拟地址空间:每个用户进程都有;对于内核地址空间:所有的进程共享
3.2 特殊存在方式
两种特殊方式:
内核线程:没有用户虚拟空间的进程称为内核线程
用户线程:共享用户虚拟地址空间的进程称为用户线程
3.3 分类
常说的c库的进程和内核标准的不一致。如下图:
它们在内核中都是用task_struct描述。
3.4 进程的四要素
a:一段程序供其执行;
b:专门的系统堆栈空间;
c:在内核有task_struct描述;
d:有独立的存储空间,拥有专有的用户空间;
无第d项,则是线程;完全无用户空间称为内核线程;若共享用户空间映射称用户线程
3.5 内核task_struct描述
描述一个进程在内核中运行的所有信息,比较大大概有1.7kb左右。如下图
主要重要的就是pid,父子关系,任务状态,调度策略相关,内存处理,文件系统,内核栈等
3.6 常见的几种创建方式
1 内核进程产生原理:
内核会使用静态数据结构(固件中的)构造0号内核线程;然后0号内核线程分列成1号内核线程和2号内核线程(kthread线程);1号线程初始化完装载用户程序产生各种子进程,2号进程产生其它的各种内核线程。如下图:
2 创建进程的方式:
1 fork(分叉):定时复制技术 clone简化版本
2 vfork:淘汰
3 clone克隆:可供pthread库线程使用
上面的3个系统调用都会调用到kernel/fork.c中的__do_fork函数
例如:在应用程序中使用系统调用fork()函数:触发80软终端,然后再去系统调用表中查找sys_call_table(),对应到内核的sys_fork()函数,然后再调用do_fork()函数;
3 __do_fork的源码分析流程:
long _do_fork(unsigned long clone_flags, //克隆标识,0为不要向父进程发信号 unsigned long stack_start,// 栈开始,指定线程的用户栈起始位置(创建线程才有意义) unsigned long stack_size,//栈大小 int __user *parent_tidptr,//新建线程保持自己的标识 int __user *child_tidptr,//子进程的标识 unsigned long tls) { //...... }
源码具体流程:
4 copy_progress源码流程:
3.7 进程的状态迁移图
在内核描述task_struct结构体中,有一个voliate int的state状态就是进程的状态。
进程主要有7种状态:就绪状态、运行状态、轻度睡眠、中度睡眠、深度睡眠、僵尸状态、死亡状态,它们之间状态变迁如下:
4 进程的调度策略
1、Linux内核支持调度策略
先进先出调度(SCHED_FIFO)、轮流调度(SCHED_RR)、限期调度策略(SCHED_DEADLINE)采用不同的调度策略调度实时进程。
普通进程支持两种调度策略:标准轮流分时(SCHED_NORMAL)和SCHED_BATCH调度普通的非实时进程。
空闲(SCHED_IDLE)则在系统空闲时调用idle进程。
2、进程优先级
限期进程的优先级比实时进程高,实时进程的优先级比普通进程高。
限制进程的优先级是-1。
实时进程的实时优先级是1-99,优先级数值越大,表示优先级越高。
普通进程的静态优先级是100-139,优先级值越小,表示优先级越高,可通过修改nice值改变普通进程 的优先级,优先级等于120加上nice值。
在task_struct结构体中,4个成员和优先级有关如下:
5 写时复制技术
写时复制核心思想:只有在不得不复制数据内容时才去复制数据内容。
在redis中也是有用到这种思想。