Linux内核分析第三章读书笔记
第三章 进程管理
3.1 进程
进程就是处于执行期的程序
进程就是正在执行的程序代码的实时结果
线程:在进程中活动的对象。每个线程都拥有一个独立的程序计数器、进程栈和一组进程寄存器。
内核调度的对象是线程,不是进程,对于Linux而言,线程只是一种特殊的进程。
进程提供两种虚拟机制:虚拟处理器和虚拟内存
虚拟处理器给进程一种假象,让这些进程觉得自己在独享处理器。
虚拟内存让进程在分配和管理内存时觉得自己拥有整个系统的所有内存资源。
在线程之间可以共享虚拟内存,但每个都拥有各自的虚拟处理器
进程是处于执行器的程序以及相关资源的总称
该系统调用通过复制一个现有进程来创建一个全新的进程
Fork()系统调用返回两次:一次回到父进程,一次回到新产生的子进程
通过exec()这组函数可以创建新的地址空间,把新的程序载入其中
通过exit()退出执行,会终结进程并将其占用的资源放掉。
父进程通过wait4系统调用调查子进程是否终结,使进程有了等待特定进程执行完毕的能力
进程退出执行后被设置为僵死状态,直到它的父进程调用wait()或waitpid()
3.2 进程描述符及任务结构
内核把进程的列表存放在叫做任务队列的双向循环链表中,链表中的每一项都是类型为task_struct、称为进程描述符的结构,定义在<linux/sched.h>文件中
进程描述符中包含的数据能完整地描述一个正在执行的程序
3.2.1 分配进程描述符
Linux通过slab分配器分配task_struct结构
目的:达到对象复用和缓和着色
在栈底或栈顶创建一个新的结构struct_thread_info,在<asm/thread_info.h>下定义
每个任务的thread_info结构在它的内核栈的尾端分配,结构中task域中存放的是指向该任务实际task_struct的指针
3.2.2 进程描述符的存放
内核通过一个唯一的进程标志值或PID来标识每个进程
PID是一个数,表示为pid_t隐含类型,实际上是一个int类型,最大值默认为32768
内核把每一个进程的PID存放在它们各自的进程描述符中
最大值:系统允许同时存在的进程的最大数目,通过修改/proc/sys/kernel/pid_max来提高上限
访问任务通常需要获得指向其task_struct的指针,内核中大部分处理进程的代码都是直接通过task_struct进行的
通过current宏查找到当前正在运行的进程的进程描述符
Current把栈指针的后13个有效位屏蔽掉,用来计算thread_info的偏移,通过current_thread_info()函数来完成
Current再从thread_info的task域中提取并返回task_struct的地址
3.2.3 进程状态
系统中的每个进程都必然处于五个状态的一种:运行、可中断、不可中断、被其他进程跟踪的进程、停止
3.2.4 设置当前进程状态
使用set_task_state(task,state)函数,该函数将指定的进程设置为指定的状态
3.2.5 进程上下文
可执行程序代码:从一个可执行文件载入到进程的地址空间执行
当一个进程执行了系统调用或触发了某个异常,就陷入内核空间,我们称其“代表进程执行”并处于进程上下文中,在此上下文current宏是有效的
系统调用和异常处理程序是对内核明确定义的接口,进程只有通过这些接口才能陷入内核执行——对内核的所有访问都必须通过接口
3.2.6 进程家族树
所有的进程都是PID为1的init进程的后代。内核在系统启动的最后阶段启动init进程,该进程读取系统的初始化脚本,完成系统调用的整个过程
每个进程必须有一个父进程,每个进程都可以拥有零个或多个子进程,拥有同一个父进程的所有进程被称为兄弟。进程间的关系存放在进程描述符中,每个task_struct都包含一个指向其父进程task_struct、叫做parent的指针,还包含一个称为children的子进程链表
Init进程的进程描述符是作为init_task静态分配的
任务队列:双向循环链表
获取链表下一个进程:next_task(task)
获取链表前一个进程:prev_task(task)
依次访问整个任务队列的能力:for_each_precess(task),每次访问,任务指针都指向链表中的下一个元素
3.3 进程创建
两个函数:fork() evec()
Fork()通过拷贝当前进程创建一个子进程
子进程和父进程的区别:PID、PPID和某些资源和统计量
Exec函数负责读取可执行文件并将其载入地址空间开始运行
3.3.1 写时拷贝
Fork()使用写时拷贝页实现,可以推迟甚至免除拷贝数据,内核让父进程和子进程共享同一个拷贝
资源的复制只有在需要写入的时候才进行,在此之前,只是以只读的方式共享,使地址空间上的页的拷贝被推迟到实际发生写入的时候进行
Fork()的实际开销就是复制父进程的页表以及给子进程创建唯一的进程描述符
3.3.2 fork()
通过clone()系统调用实现fork()
Fork(),vfork(),_clone()库函数都根据各自需要的参数标志去调用clone(),然后由clone()去调用do_fork()
Do_fork()定义在kernel/fork.c文件中,调用copy_precess函数,让进程开始运行
3.3.3 vfork()
除了不拷贝父进程的页表外,功能与fork()相同,通过向clone()系统调用传递一个特殊标志来进行
3.4 线程在Linux中的实现
线程机制:提供了在同一程序内共享 内存地址空间运行的一组线程,可以共享打开的文件和其他资源,在多处理器系统上,能够保证真正的并行处理
线程仅仅被视为一个与其他进程共享某些资源的进程,每个线程都拥有唯一隶属自己的task_struct,看起来就像一个普通的进程
对于Linux来说,它只是一种进程间共享资源的手段
3.4.1 创建线程
在调用clone()的时候需要传递一些参数标志来指明需要共享的资源
父子俩共享地址空间、文件系统资源、文件描述符和信号处理程序
传递给clone()的参数标志决定了 新创建进程的行为方式和父子进程之间共享的资源种类,在<linux/sched.h>中定义
3.4.2 内核线程
内核线程没有独立的地址空间,指向地址空间的mm指针被设置为NULL,它只在内核空间中运行,从来不切换到用户空间去,可以被调度,可以被抢占
运行ps –ef命令,可以看到内核线程
内核线程只能由其他内核线程创建,kthreadd内核进程中衍生出所有新的内核线程,在<linux/kthread.h>中申明有接口
新的任务是由kthread内核进程通过clone()系统调用而创建的。新的进程将运行threadfn函数,给其传递的参数为data。进程被命名为namefmt
新创建的进程处于不可运行状态,如果不通过wake_up_process()唤醒它,它不会运行
创建一个进程并让它运行,可以通过kthread_run()来达到
内核线程启动后就一直运行直到调用do_exit()退出,或者内核的其他部分调用kthread_stop()退出,传递给kthread_stop()的参数为kthread_create函数返回的task_struct结构的地址
3.5 进程终结
当一个进程终结时,内核必须释放它所占有的资源并告知其父进程
进程的终结发生在进程调用exit()系统调用时。当进程接受到它既不能处理也不能忽略的信号或异常时,它还可能被动地终结
终结大部分靠do_exit()来完成(定义于kernel/exit.c)
Do_exit()永不返回
之后,进程不可运行并处于EXIT_ZOMBIE退出状态,存在的唯一目的就是向它的父进程提供新消息,父进程检索到信息后,由进程所持有的剩余内存被释放
3.5.1 删除进程描述符
系统还保留了进程描述符,这样做可以让系统有办法在子进程终结后仍能获得它的信息
进程终结时所需的清理工作和进程描述符的删除被分开执行。
在父进程获得已终结的子进程信息后,子进程的task_struct才被释放
Wait():通过唯一的系统调用wait4()来实现,它的标准动作是挂起调用它的进程,直到其中一个子进程退出,此时函数返回该子进程的PID,调用该函数时提供的指针会包含子函数退出时的退出代码
当最终需要释放进程描述符时,release_task()会被调用
3.5.2 孤儿进程造成的进退维谷
父进程在子进程之前退出,必须保证子进程找到新的父进程,否则这些孤儿进程会永远处于僵死状态,白白的耗费内存
解决方法:给子进程在当前进程组内找到一个线程作为父亲,如果不行,就让init做它们的父进程。
在do_exit()中会调用exit_notify(),该函数会调用forget_original_parents(),而后者调用find_new_reaper()来执行寻父过程
遍历所有子进程并为它们设置新的父进程
遍历了两个链表:子进程链表和ptrace子进程链表
解决孤儿问题的方法:在一个单独的被ptrace跟踪的子进程链表中搜索相关的兄弟进程
一旦系统为进程成功的找到和设置了新的父进程,就不会再有出现驻留僵死进程的危险了,init进程会例行调用wait()来检查子进程,清除所有与其相关的僵死进程。
Linux内核分析第三章读书笔记的更多相关文章
- Linux内核分析第四章 读书笔记
Linux内核分析第四章 读书笔记 第一部分--进程调度 进程调度:操作系统规定下的进程选取模式 面临问题:多任务选择问题 多任务操作系统就是能同时并发地交互执行多个进程的操作系统,在单处理器机器上这 ...
- Linux内核分析第一二章读书笔记
linux读书笔记(1,2章) 标签(空格分隔): 20135328陈都 第一章 Linux内核简介 Unix的历史 Unix 虽然已经使用了40年,但计算机科学家仍然认为它是现存操作系统中最强大和最 ...
- linux内核分析 第3章读书笔记
第三章 进程管理 一.进程 1.进程 进程就是处于执行期的程序. 进程就是正在执行的程序代码的实时结果. 进程是处于执行期的程序以及相关的资源的总称. 进程包括代码段和其他资源. 2.线程 执行线程, ...
- linux内核分析 第4章读书笔记
第四章 进程调度 一.抢占与非抢占 1.非抢占式进程调度 进程会一直执行直到自己主动停止运行 2.抢占式进程调度 Linux/Unix使用的是抢占式的方式,强制的挂起进程的动作就叫做抢占. 二.进程优 ...
- Linux内核分析第五章读书笔记
第五章 系统调用 在操作系统中,内核提供了用户进程与内核进行交互的一组接口,这些接口在应用程序和内核之间扮演了使者的角色,保证系统稳定可靠,避免应用程序肆意妄行. 5.1 与内核通信 系统调用在用户空 ...
- linux内核分析 第5章读书笔记
第五章 系统调用 一.与内核通信 系统调用在用户控件进程和硬件设备之间添加了一个中间层,作用有: 为用户空间提供了一种硬件的抽象接口 系统调用保证了系统的稳定和安全 每个进程都运行在虚拟系统中,而在用 ...
- Linux内核分析第四章读书笔记
第四章 进程调度 进程调度程序:确保进程能有效工作的一个内核子程序 决定将哪个进程投入运行,何时运行已经运行多长时间 进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子系统 原则:只 ...
- linux内核分析 第18章读书笔记
十八章 调试 一.内核调试概述 1.需要面对的 一个确定的bug 一个藏匿bug的内核版本 相关的内核代码的知识和运气 2.艰难的调试工作 重现bug很困难:大部分bug通常都不是行为可靠而且定义明确 ...
- linux内核分析 第7章读书笔记——《深入理解计算机系统》
第七章 链接 --<深入理解计算机系统> 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或拷贝)到存储器并执行. 一.编译器 大多数编译系统提供编译驱动 ...
随机推荐
- 【微信JSSDK】PHP版微信录音文件下载
微信的录音文件上传到微信服务器上,只能保存三天. 因此需要做一个转存到自己服务器,或者七牛云的操作. 转存到自己服务器 调用微信JSSDK API 录音, 录音结束,上传到微信服务器,获取录音文件的 ...
- 请教MAC OS下PHP的mcrypt怎么安装
安装方法一: 通过Homebrew安装mcrypt,安装成功 [Shell] 纯文本查看 复制代码 brew install mcrypt MCrypt是一个功能强大的加密算法扩展库,它包括有22种算 ...
- 转 VMware虚拟机三种联网方式(图文详细解说)
原文地址https://blog.csdn.net/lucienduan/article/details/38233147 VMware三种网络模式联网 首先说一下VMware的几个虚拟设备 安装了V ...
- swift class的虚函数表、扩展、@objc修饰、虚函数的派发方式研究
swift class的虚函数表.扩展.@objc修饰的研究 工具: swiftc -emit-sil BaseClass.swift | xcrun swift-demangle > Clas ...
- 基于Redis实现一个安全可靠的消息队列
http://doc.redisfans.com/list/rpoplpush.html
- kafka监控kafka-eagle 容器化配置
由于kafka.zk 集群已经部署在k8s中, kafka的服务名 kafka-hs, zk的服务名为:zk-cs ,对kafka进行监控,所以需要把监控部署到k8s中,选择使用kafka-eagl ...
- Unicode(UTF-8, UTF-16)令人混淆的概念(转)
文章转自http://www.cnblogs.com/kingcat/archive/2012/10/16/2726334.html (http://swiftlet.net/archives/cat ...
- 图、dfs、bfs
graphdfsbfs 1.clone graph2.copy list with random pointer3.topological sorting4.permutations5.subsets ...
- mybatis逆向工程之动态web项目
有了逆向工程,单表的增删改查以及相关的实体类,还有属性注释都不用自己写了,都可以自动化生成,只需如下三步即可 逆向工程的优点是:自动化生成实体类和对应的增删改查,效率相对于之前个人开发时一个个写增删改 ...
- [转]系统架构演变--集中式架构-垂直拆分-分布式服务-SOA(服务治理)-微服务
一.系统架构演变 1.1. 集中式架构 当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本.此时,用于简化增删改查工作量的数据访问框架(ORM)是影响项目开发的关键. 存在的 ...