第三章 进程管理

3.1 进程

进程的定义:

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

线程的定义:

是在进程中活动的对象。

每个线程都拥有一个独立的程序计数器、进程栈和一组进程寄存器。

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

3.2 进程描述符及任务结构

进程描述符的结构:task_struct,定义在<linux/sched.h>中,包含一个具体进程的所有信息。

task_struct 就是指 PCB (进程控制块)。

3.2.1 分配进程描述符

thread_info结构在文件<asm/thread_info.h>中。

3.2.2 进程描述符的存放

3.2.3 进程状态

1.TASK_RUNNING (运行):无论进程是否正在占用 CPU ,只要具备运行条件,都处于该状态。 事实上, Linux 是将就绪态和运行态合并为了一种状态。

2.TASK_INTERRUPTIBLE (可中断阻塞):在资源有效时被唤醒,也可以通过信号或定时中断唤醒。

3.TASK_UNINTERRUPTIBLE (不可中断阻塞):另一种阻塞状态,处于该状态的进程只有当资源有效时被唤醒,不能通过信号或定时中断唤醒。

4.TASK_STOPPED (暂停):第三种阻塞状态,进程被停止,通常是通过接收一个信号SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU。

5.TASK_ZOMBILE (僵死):进程已结束但尚未消亡,已经释放了大部分资源, PCB 仍未被释放,在task数据中仍然保留task_struct结构。一旦父进程调用了wait4(),进程描述符就会被释放。

3.2.4 设置当前进程状态

set_task_state(task, state); /* 设置任务 'task' 的状态变成 'state' */

3.2.5 进程上下文

内核“代表进程执行”并处于进程上下文中。

此上下文中current宏有效。

3.2.6 进程家族树

1.获得父进程的进程描述符:

struct task_struct *my_parent = current->parent;

2.依次访问子进程:

struct task_struct *task;

struct list_head *list;

list_for_each(list, &current->children) {

task = list_entry(list, struct task_struct, sibling);

/* task指向当前某个子进程*/

}

3.获取链表中的下一个进程:

list_entry(task->tasks.next, struct task_struct, tasks)

4.获取链表中的前一个进程:

list_entry(task->tasks.prev, struct task_struct, tasks)

5.宏for_each_process(task),提供了依次访问整个任务队列的能力,

struct task_struct *task;

for_each_process(task) {

/* 打印出每个任务名称和pid*/

printk("%s[%d]\n", task->comm, task->pid);

}

3.3 进程创建

3.3.1 写时拷贝

fork() 和 exec()

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

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

3.3.2 fork()

通过clone()系统调用实现fork()。

do_fork完成创建中大量工作,定义在kernel/fork.c文件中。

调用copy_process()函数让进程开始运行。(具体工作很有意思详见《Linux内核设计与实现》第27页)

3.3.3 vfork()

与fork()很类似。

实现是通过向clone()系统调用传递一个特殊标志来进行。(具体工作很有意思详见《Linux内核设计与实现》第28页)

3.4 线程在Linux中的实现

3.4.1 创建线程

在调用clone()需传递一些参数标志指明共享资源。

clone(CLONE_VM | CLONE_FS | CLONE_SIGHAND, 0);

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

一个普通的fork()。

clone(SIGHAND, 0);

vfork()的实现。

clone(CLONE_VFORK | CLONE_VM | SIGHAND, 0);

clone()参数标志决定新创建进程的行为方式和父子进程之间共享的资源种类。(具体参数标识详见《Linux内核设计与实现》第29-30页)

3.4.2 内核线程

内核线程只能由其他内核线程创建。

内核通过从kthreadd内核进程中衍生出所有新内核线程来自动处理。

在<linux/kthread.h>中声明接口。

新的任务是由kthread内核进系统调用程通过clone()而创建的。

内核线程启动后一直运行知道调用do_exit()退出,或者内核其它部分调用kthread_stop()退出。

3.5 进程终结

进程的退出一般是显示或隐式地调用了exit(),或者接受了某种信号。

只要退出,最终都调用了do_exit()(具体完成的繁琐工作详见《Linux内核设计与实现》第31页)。

3.5.1 删除进程描述符

wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。

最终需要释放进程描述符时,release_task()会被调用(具体需要完成的工作详见《Linux内核设计与实现》第32页)

3.5.2 孤儿进程造成的进退维谷

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

解决方法是给子进程在当前线程组内找一个线程作为父亲,如果不行,就让init做它们的父进程。在do_exit()中会调用exit_notify(),该函数会调用forget_original_parent(),而后者会调用find_new_reaper()来执行寻父。

遍历了两个链表:子进程链表和ptrace子进程链表,给每个子进程设置新的父进程。

20135320赵瀚青LINUX第三章读书笔记的更多相关文章

  1. 20135320赵瀚青LINUX第五章读书笔记

    第五章--系统调用 5.1 与内核通信 作用 1.为用户空间提供一种硬件的抽象接口 2.保证系统稳定和安全 3.除异常和陷入,是内核唯一的合法入口. API.POSIX和C库 关于Unix接口设计:提 ...

  2. 20135320赵瀚青LINUX第四章读书笔记

    概述 什么是进程调度 进程调度:在可运行态进程之间分配有限处理器时间资源的内核子系统. 一.调度策略 4.1进程类型 I/O消耗型进程:大部分时间用来提交I/O请求或是等待I/O请求,经常处于可运行状 ...

  3. 20135320赵瀚青LINUX第十八章读书笔记

    概述:调试工作艰难是内核级开发区别于用户级开发的一个显著特点 18.1准备开始 内核调试往往是一个令人挠头不已的漫长过程.幸运的是,在这些费劲的问题中也有不少比较简单而且容易消灭的小bug,运气好你可 ...

  4. 20135320赵瀚青LINUX第五周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 按照刘老师的周从三个角 ...

  5. 20135320赵瀚青LINUX第六周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 这周主要讲解的是进程. ...

  6. 20135320赵瀚青LINUX第八周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周学习的是linux ...

  7. 20135320赵瀚青LINUX第七周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周学习的内容主要是讨 ...

  8. 三20135320赵瀚青LINUX内核分析第二周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.计算机的三个法宝 存储程 ...

  9. 20135320赵瀚青LINUX内核分析第三周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周是学习的主要是构造 ...

随机推荐

  1. PHP mysql基本语句指令

    /*选择数据库 use test; */ /* 显示所有的数据库 show databases; */ /*删除表/数据库 drop database test1; delete from user1 ...

  2. LeetCode 笔记系列五 Generate Parentheses

    题目: Given n pairs of parentheses, write a function to generate all combinations of well-formed paren ...

  3. Nginx之静态资源WEB服务

    本篇主要记录学习Nginx的静态资源WEB服务的几种常见的功能记录学习 Nginx开发常用的命令 nginx -tc /etc/nginx/nginx.conf vim /etc/nginx/conf ...

  4. 通过SSH连接mysql

  5. Dynamic Programming: Fibonacci

    Recently I watched an interesting video in youtube, the vbloger use calculating Fibonacci number to ...

  6. 【转】虚拟机下CentOS7开启SSH连接

    在虚拟机(Vmware Workstation)下,安装了CentOS7,现在想通过SSH工具连接虚拟机中的CentOS7 1. 首先,要确保CentOS7安装了  openssh-server,在终 ...

  7. 如何将计算机加入域 分类: AD域 Windows服务 2015-06-10 11:04 63人阅读 评论(0) 收藏

    在上一篇博客中我已经实现了windows server 2008 R2域中的DC部署,那么如何将计算机加入到我们部署的域环境中呢? (初级教程,step by step,不足之处欢迎批评指正!) 将计 ...

  8. TIME_WAIT Accumulation and Port Exhaustion

    客户端实现连接的唯一性 HTTP The Definitive Guide 4.2.7 TIME_WAIT Accumulation and Port Exhaustion TIME_WAIT por ...

  9. 如何用 PyCharm 调试 scrapy 项目

    原理: 首先 scrapy 命令其实就是一个python脚本,你可以使用 which scrapy 查看该脚本的内容: from scrapy.cmdline import execute sys.a ...

  10. SIP UserAgent (B2BUA client)——pjsip

    SIP UserAgent常用的SIP协议栈有pjsip/bell-sip/sofia-sip/libeXosip/libre等 https://github.com/staskobzar/sip_s ...