《Linux内核设计与实现》Chapter 3 读书笔记

进程管理是所有操作系统的心脏所在。

一、进程

1.进程就是处于执行期的程序以及它所包含的资源的总称。

2.线程是在进程中活动的对象。

3.进程提供两种虚拟机制:虚拟处理器和虚拟内存。

4.内核调度的对象是线程,而不是进程。

二、进程描述符及任务结构

内核把进程的列表存放在叫做任务队列的双向循环链表中。链表中的每一项都是类型为task_struct的进程描述符结构,该结构定义在<linux/sched.h>文件中。

1.分配进程描述符

Linux通过slab分配器分配task_struct结构——能达到对象复用缓存着色的目的。

用slab分配器动态生成task_struct,只需在栈底或者栈顶创建一个新的结构struct thread_info

2.进程描述符的存放

内核通过一个唯一的进程标识值PID来标识每个进程。PID是一个数,表示为pid_t隐含类型,实际上就是一个int类型,最大值默认设置为32768。

3.进程状态

进程描述符中的state域是用来描述进程当前状态。

  • TASK_RUNNING(运行):进程是可执行的,或者正在执行,或者在运行队列中等待执行
  • TASK_INTERRUPTIBLE(可中断):进程正在睡眠,也就是被阻塞
  • TASK_UNINTERRUPTIBLE(不可中断):与可中断状态相同,接收到信号也不会被唤醒或准备投入运行
  • TASK_TRACED:被其他进程跟踪的进程
  • TASK_STOPPED(停止):进程停止执行;进程没有投入运行也不能投入运行。

4.设置当前进程状态

调整某个进程的状态,最好用set_task_state(task,state)函数。

功能:该函数将指定的的进程设置为指定的状态。

等价于

task -> state = state

5.进程上下文

陷入内核空间:从一个可执行文件载入到进程的地址空间执行。

进程只有通过接口才能陷入内核执行。

6.进程家族树

所有的进程都是PID为1的init进程的后代。

系统中的每一个进程必有一个父进程,可以拥有零个或多个子进程,拥有同一个父进程的进程叫做兄弟。

获得父进程的进程描述符:
struct task_struct *my_parent = current->parent; 依次访问子进程:
struct task_struct *task;
struct list_head *list; list_for_each(list, &current->children) {
task = list_entry(list, struct task_struct, sibling);
/* task指向当前某个子进程*/
}

init进程的进程描述符是作为init_task静态分配的。

获取链表中的下一个进程: list_entry(task->tasks.next, struct task_struct, tasks) 获取链表中的前一个进程: list_entry(task->tasks.prev, struct task_struct, tasks) for_each_process(task)宏提供了依次访问整个任务队列的能力, struct task_struct *task; for_each_process(task) { /* 它打印出每个任务名称和PID*/ printk("%s[%d]\n", task->comm, task->pid); }

三、进程创建

fork()通过拷贝当前进程创建一个子进程。

(子进程与父进程的区别仅在于PID,PPID和某些资源和统计量)

exec()负责读取可执行文件并将其载入地址空间开始运行。

1.写时拷贝

写时拷贝是一种可以推迟甚至免除拷贝数据的技术,内核不复制整个进程地址空间,而是让父进程和子进程共享一个拷贝。

资源的复制只有在需要写入时才会进行,在此之前以只读方式共享。

2.fork()

do_fork定义在kernel/fork.c文件中,调用copy_process

创建进程的大概步骤:
.fork()、vfork()、__clone()都根据各自需要的参数标志调用clone()。
.由clone()去调用do_fork()。
.do_fork()调用copy_process()函数,然后让进程开始运行。
.返回do_fork()函数,如果copy_process()函数成功返回,新创建的子进程被唤醒并让其投入运行。

3.vfork()

与fork()功能基本相同。

优点:

不拷贝父进程的页表项

vfork()系统调用的实现是通过向clone()传递一个特殊标志来进行的。

  • 调用copy_process()时,task_struct的vfor_done成员被设置为NULL。
  • 在执行do_fork()时,如果给定特定标志,则vfor_done会指向一个特定地址。
  • 子进程先开始执行后,父进程不是马上恢复执行,而是一直等待,知道子进程通过vfor_done指针向它发送信号。
  • 在调用mm_release()时,该函数用于进程退出内存地址空间,并且检查vfor_done是否为空,如果不为空,则会向父进程发送信号。
  • 回到do_fork(),父进程醒来并返回。

四、线程在Linux中的实现

Linux把所有的线程都当做进程来实现。

1.创建线程

  • 在调用clone()需传递一些参数标志指明共享资源。
 clone(CLONE_VM | CLONE_FS | CLONE_SIGHAND, );

新建的进程和它的父进程就是线程。

  • 一个普通的fork()。
clone(SIGHAND, );
  • vfork()的实现。

clone(CLONE_VFORK | CLONE_VM | SIGHAND, );

clone()参数标志决定新创建进程的行为方式和父子进程之间共享的资源种类。

2.内核线程

内核线程没有独立的地址空间,只在内核空间进行。内核线程也只能由其他线程创建。

内核线程启动后就一直运行直到调用do_exit

五、进程终结

进程终结时,内核必须释放它所占有的资源并告知父进程。

原因:

一般是来自自身,发生在调用exit()系统调用时。

  • 显式的调用
  • 隐式的从某个程序的主函数返回

1.删除进程描述符

释放进程描述符时,需要调用release_task()

2.孤儿进程造成的进退维谷

如果父进程在子进程之前退出,必须有机制来保证子进程能找到一个新的父亲,否则这些成为孤儿的进程就会在退出时永远处于僵死状态。

解决方法:

  1. 在当前进程组找一个线程作为养父
  2. 让init成为它们的父进程。

《Linux内核设计与实现》Chapter 3 读书笔记的更多相关文章

  1. 《Linux内核设计与实现》 Chapter4 读书笔记

    <Linux内核设计与实现> Chapter4 读书笔记 调度程序负责决定将哪个进程投入运行,何时运行以及运行多长时间,进程调度程序可看做在可运行态进程之间分配有限的处理器时间资源的内核子 ...

  2. Linux内核设计与实现第四周读书笔记

    第5章系统调用 5.1与内核通信 主要作用: 为用户控件提供了一种硬件的抽象接口. 保证了系统稳定性与安全性. 为用户空间&系统提供公共接口. 5.2API.POSIX和C库 一般情况,应用程 ...

  3. 《Linux内核分析》第六周 读书笔记

    <Linux内核设计与实现>CHAPTER3阅读梳理 [学习时间:3hours] [学习内容:进程的描述:进程的生命周期(包括创建.终结)] 一.进程(任务)描述 1.进程是处于执行期的程 ...

  4. linux内核分析 1、2章读书笔记

    一.linux历史 20世纪60年代,MIT开发分时操作系统(Compatible TIme-Sharing System),支持30台终端访问主机: 1965年,Bell实验室.MIT.GE(通用电 ...

  5. 《Linux内核分析》第七周 读书笔记

    <深入理解计算机系统>CHAPTER7阅读梳理 [学习时间:3hours] [学习内容:链接需要的代码&数据:链接机制:链接生成的目标文件] 一.链接概述 1.链接 定义:链接是将 ...

  6. 《Linux内核设计》第17章学习笔记

  7. 《linux内核》课本第五章读书笔记

  8. 《Linux内核设计与实现》课本第一章&第二章学习笔记

    <Linux内核设计与实现>课本学习笔记 By20135203齐岳 一.Linux内核简介 Unix内核的特点 Unix很简洁,所提供的系统调用都有很明确的设计目的. Unix中一切皆文件 ...

  9. 《Linux内核设计与实现》Chapter 1 读书笔记

    <Linux内核设计与实现>Chapter 1 读书笔记 一.Unix的特点 Unix从Multics中产生,是一个强大.健壮和稳定的操作系统. 特点 1.很简洁 2.在Unix系统中,所 ...

随机推荐

  1. SAM4E单片机之旅——20、DMAC之使用Multi-buffer进行内存拷贝

    这次使用这个DMAC的Multi-buffer传输功能,将两个缓冲区的内容拷贝至一个连续的缓冲区中. 一. DMAC 在M4中,DMA控制器(DMAC)比外设DMA控制器(PDC)要复杂,但是功能更加 ...

  2. 【SQL查询】集合查询之INTERSECT

    [SQL查询]集合查询之INTERSECT 1  BLOG文档结构图 2  前言部分 2.1  导读和注意事项 各位技术爱好者,看完本文后,你可以掌握如下的技能,也可以学到一些其它你所不知道的知识,~ ...

  3. 关于nginx的限速模块

    nginx 使用 ngx_http_limit_req_module和ngx_http_limit_conn_module 来限制对资源的请求 这种方法,对于CC攻击(Challenge Collap ...

  4. Bootstrap(转)

    Bootstrap 随着互联网的不断成熟以及我们越来越多的用各种移动端的设备访问互联网,Web设计师和Web开发者的工作也变得越来越复杂. 十年前,一切都还简单得多.那个时候,大部分用户都是坐在桌子前 ...

  5. redis AOF保存机制

    网上说AOF有三种保存方式,不自动保存.每秒自动保存.每命令自动保存. 其中每秒自动保存这个看起来很美好,但是可能会被各种IO的时间所延迟,所以究竟是怎么判断每秒保存的,并不是太明白,故有此文. AO ...

  6. JS对URL字符串进行编码/解码分析

    一.为什么要进行js编码和解码? 只有字母和数字[0-9a-zA-Z].一些特殊符号“$-_.+!*'(),”[不包括双引号].以及某些保留字,才可以不经过编码直接用于URL. 出现的情况: 网址路径 ...

  7. 第十章 MySQL 常用函数

    第十章 MySQL 常用函数 第一节:日期和时间函数 1,CURDATE() 返回当前日期:2,CURTIME() 返回当前时间:3,MONTH(d) 返回日期 d 中的月份值,范围是 1~12 第二 ...

  8. 烂泥:KVM、kickstart与NFS集成

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 其实这篇文章原本是可以不写的,不过为了学习NFS的使用形式还是写下,算是作为一个笔记. 有关NFS的搭建与配置,可以参考我以前的文档<烂泥:NFS ...

  9. 05_最长公共子序列问题(LCS)

    问题来源:刘汝佳<算法竞赛入门经典--训练指南> P60 问题7: 问题描述:给两个子序列A和B,求长度最大的公共子序列.比如1,5,2,6,8,和2,3,5,6,9,8,4的最长公共子序 ...

  10. php的amqp扩展set导致内存溢出

    最近做的一个项目中需要用到rabbitmq,按照自己的之前的一篇文章http://www.cnblogs.com/mingaixin/archive/2012/10/28/2743807.html进行 ...