《Linux内核分析》第六周笔记 进程的描述和进程的创建
进程的描述和进程的创建
一、进程的描述
1、进程描述符task_struct数据结构(一)
操作系统的三大功能:进程管理(核心)、内存管理、文件系统。
进程控制块PCB——task_struct(进程描述符):为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。
- struct task_struct数据结构很庞大,共有约400行代码

- Linux进程的状态与操作系统原理中的描述的进程状态似乎有所不同,比如就绪状态和运行状态都是TASK_RUNNING,为什么呢?
操作系统原理中有三个状态:就绪状态、运行状态。阻塞状态。
调用fork创建一个新进程的时候实际上的状态是TASK_RUNNING(就绪但没有在运行),当调度器选择一个task时还是切换到TASK_RUNNING,(为什么呢?当进程是TASK_RUNNING状态时是可运行的,但是否运行还是看是否获得CPU的控制权(有没有在CPU上实际的执行))进程调用do_exit()中止执行,进入TASK_ZOMBIE(僵尸进程)
一个正在运行的进程在等待特定的事件或者是资源的时候会进入阻塞态,当阻塞的条件没有了的时候,就进入就绪态。
- 进程的标示pid
pid及tpid用来标识进程的
- 所有进程链表struct list_head tasks;
- 内核的双向循环链表的实现方法 - 一个更简略的双向循环链表
- 程序创建的进程具有父子关系,在编程时往往需要引用这样的父子关系。进程描述符中有几个域用来表示这样的关系
- Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构:Thread_info和进程的内核堆栈
- 进程处于内核态时使用,不同于用户态堆栈,即PCB中指定了内核栈,那为什么PCB中没有用户态堆栈?用户态堆栈是怎么设定的?
- 内核控制路径所用的堆栈很少,因此对栈和Thread_info来说,8KB足够了
- struct thread_struct thread; //CPU-specific state of this task
- 文件系统和文件描述符
- 内存管理——进程的地址空间
2、进程描述符task_struct数据结构(二)
阅读理解task_struct数据结构
struct task_struct {
1236 volatile long state; /*state是运行状态*/
1237 void *stack;/*指定了进程的内核堆栈 */
1238atomic_tusage;
1239 unsigned int flags; /* 标识符*/
1240 unsigned int ptrace;
1241
1242#ifdef CONFIG_SMP/*条件编译多处理器用到*/
1243 struct llist_nodewake_entry;
1244 int on_cpu;
1245 struct task_struct *last_wakee;
1246 unsigned long wakee_flips;
1247 unsigned long wakee_flip_decay_ts;
1248
1249 int wake_cpu;
1250#endif
1251 int on_rq;/*运行队列和进程调度相关程序*/
1252
1253 int prio, static_prio, normal_prio;
1254 unsigned int rt_priority;
1255 const struct sched_class *sched_class;
1256 struct sched_entityse;
1257 struct sched_rt_entityrt;
1258#ifdef CONFIG_CGROUP_SCHED
1259 struct task_group *sched_task_group;
1260#endif
1295 struct list_head tasks;/*进程链表*/


/*双向链表*/
1296#ifdef CONFIG_SMP
1297 struct plist_nodepushable_tasks;
1298 struct rb_nodepushable_dl_tasks;
1299#endif
1300
1301 struct mm_struct *mm, *active_mm;/*进程管理进程的地址空间相关*/ 每个进程有独立的进程地址空间4G,32位x86。
1302#ifdef CONFIG_COMPAT_BRK
1303 unsigned brk_randomized:1;
1304#endif
1305 /* per-thread vma caching */
1306 u32 vmacache_seqnum;
1307 struct vm_area_struct *vmacache[VMACACHE_SIZE];
1308#if defined(SPLIT_RSS_COUNTING)
1309 struct task_rss_statrss_stat;
1310#endif
1330 pid_t pid;/*标识*/
1331pid_ttgid;
1337 /*
1338 * pointers to (original) parent process, youngest child, younger sibling,/*进程的父子关系*/
1339 * older sibling, respectively. (p->father can be replaced with
1340 * p->real_parent->pid)
1341 */
1342 struct task_struct __rcu *real_parent; /* real parent process */
1343 struct task_struct __rcu *parent; /* recipient of SIGCHLD, wait4() reports */
1344 /*
1345 * children/sibling forms the list of my natural children
1346 */
1347 struct list_head children; /* list of my children */
1348 struct list_head sibling; /* linkage in my parent's children list */
1349 struct task_struct *group_leader; /* threadgroup leader */
1411/*当前任务和CPU相关的状态,在进程上下文切换的过程中起着重要的作用 */
1412 struct thread_struct thread;
1413/* filesystem information */

1414 struct fs_struct *fs;/*文件系统相关的数据结构*/
1415/* open file information */
1416 struct files_struct *files;/*打开的文件描述符列表*/
1417/* namespaces */
1418 struct nsproxy *nsproxy;
1419/* signal handlers *//*与信号处理相关的工作*/
二、进程的创建
1、进程的创建概览及fork一个进程的用户态代码
进程描述符是整个系统管理中挈领性的东西。
了解进程是如何创建的?进程之间如何调度切换的?

一号进程的创建:复制了0号进程的pcb,然后根据1号进程的需要修改,再加载一个init执行程序 。
fork一个子进程的代码
- #include <stdio.h>
- #include <stdlib.h>
- #include <unistd.h>
- int main(int argc, char * argv[])
- {
- int pid;
- /* fork another process */
- pid = fork();/*在用户态用于创建一个子进程的系统调用*/
- if (pid < 0) /*出错处理*/
- {
- /* error occurred */
- fprintf(stderr,"Fork Failed!");
- exit(-1);
- }
- else if (pid == 0) /*与else共同执行*/
- {
- /* child process */
- printf("This is Child Process!\n");
- }
- else
- {
- /* parent process */
- printf("This is Parent Process!\n");
- /* parent will wait for the child to complete*/
- wait(NULL);
- printf("Child Complete!\n");
- }
- }
fork系统调用在子进程和父进程各返回一次。子进程中pid的返回值是:0。父进程中pid的返回值是:子进程的ID。
fork之后两个进程。
2、理解进程创建过程复杂代码的方法
在进程调度的过程中,调度到一个未调度的新进程,执行的起点是我们设定的my process的ip。
创建一个新进程就是复制当前进程的信息来实现的。
一个父进程创建一个子进程,有一个地方复制子进程的pcb,修改复制出来的pcb.
要给新进程分配一个新的内核堆栈.
回顾:系统调用的进程创建过程

Linux中创建进程一共有三个函数:
- fork,创建子进程
- vfork,与fork类似,但是父子进程共享地址空间,而且子进程先于父进程运行。
- clone,主要用于创建线程
这里值得注意的是,Linux中得线程是通过模拟进程实现的,较新的内核使用的线程库一般都是NPTL。
3、浏览进程创建过程相关的关键代码

4、创建的新进程是从哪里开始执行的
fork,vfork,clone都可以创建新进程,他们都是通过调用do_fork来实现的。

ip指向ret_from_fork
fork()系统调用产生的子进程在系统调用处理过程中从ret_from_fork开始执行。
只复制了部分内核堆栈

5、使用gdb跟踪创建新进程的过程
为了减少对之后实验的影响,删除test_fork.c以及test.c,编译内核:

gdb调试,设断点:


执行fork,发现fork函数停在了父进程中。
特别关注新进程是从哪里开始执行的?为什么从哪里能顺利执行下去?即执行起点与内核堆栈如何保证一致。
- ret_ from_ fork决定了新进程的第一条指令地址。
- 子进程从ret_ from_ fork处开始执行。
- 因为在ret_ from_ fork之前,也就是在copy_ thread()函数中* childregs = * current_ pt_ regs();该句将父进程的regs参数赋值到子进程的内核堆栈。
- * childregs的类型为pt_ regs,里面存放了SAVE_ ALL中压入栈的参数,因此在之后的RESTORE ALL中能顺利执行下去。
三、总结
fork()函数创建新进程是通过下列一系列函数实现的:fork() -> sys_clone() -> do_fork() -> dup_task_struct() -> copy_process() -> copy_thread() -> ret_from_fork()。操作系统的三大功能:进程管理(核心)、内存管理、文件系统。进程控制块PCB——task_struct(进程描述符):为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。Linux通过复制父进程来创建一个新进程,fork系统调用在子进程和父进程各返回一次。子进程中pid的返回值是:0。父进程中pid的返回值是:子进程的ID。
《Linux内核分析》第六周笔记 进程的描述和进程的创建的更多相关文章
- Linux内核分析第六周学习笔记——分析Linux内核创建一个新进程的过程
Linux内核分析第六周学习笔记--分析Linux内核创建一个新进程的过程 zl + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...
- LINUX内核分析第六周学习总结——进程的描述和进程的创建
LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- LINUX内核分析第六周学习总结——进程的描述与创建
LINUX内核分析第六周学习总结--进程的描述与创建 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc ...
- linux内核分析第六周学习笔记
LINUX内核分析第六周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...
- Linux内核分析——第六周学习笔记20135308
第六周 进程的描述和进程的创建 一.进程描述符task_struct数据结构 1.操作系统三大功能 进程管理 内存管理 文件系统 2.进程控制块PCB——task_struct 也叫进程描述符,为了管 ...
- Linux内核分析第六周学习总结:进程的描述和进程的创建
韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.进程的描述 ...
- 20135327郭皓--Linux内核分析第六周 进程的描述和进程的创建
进程的描述和进程的创建 一.进程的描述 操作系统三大功能: 进程管理 内存管理 文件系统 进程描述符task_struct数据结构 task _ struct:为了管理进程,内核必须对每个进程进行清晰 ...
- Linux内核分析——第六周学习笔记
进程的描述和进程的创建 前言:以下笔记除了一些讲解视频中的概念记录,图示.图示中的补充文字.总结.分析.小结部分均是个人理解.如有错误观点,请多指教! PS.实验操作会在提交到MOOC网站的博客中写.
- "Linux内核分析"第六周实验报告
张文俊 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 1.进程的描述 ...
- linux内核分析 第六周
一.进程的描述 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息. 1.进程控制块PCB--task_struct 进程状态 进程打开的文件 进程优先级信息 2. ...
随机推荐
- 【PAT】B1070 结绳(25 分)
此题太给其他25分的题丢人了,只值15分 注意要求最终结果最长,而且向下取整 #include<stdio.h> #include<algorithm> using names ...
- nginx、tomcat调优方向及压测网站步骤
nginx调优方向: 1.所用事件处理模型 2.进程数 3.每个进程的连接数 4.压缩 5.缓存 tomcat调优方向: 1.内存 2.总内存 3.初始申请内存 4.线程内存 5.GC方面 tomca ...
- 查看tomcat项目中,具体占用cpu高的线程。
1.查看主进程占用cpu高: 此处主进程:27823 ~]# top top - :0: up days, :, 3 users, load average: 13.12, 13.31, 13.23 ...
- nginx1.14的安装
编译安装nginx1.14.2 #拷贝指定文件到当前目录下[root@localhost ~]# find /usr/share -iname "*.jpg" -exec cp { ...
- java连接zookeeper服务器出现“KeeperErrorCode = ConnectionLoss for ...”
错误信息如下: Exception in thread "main" org.apache.zookeeper.KeeperException$ConnectionLossExce ...
- ES 使用小结
ES 是 Elastic Search 的缩写,可以理解为一个支持分布式部署的软件. 部署了以后可以当数据库用,虽然官方不建议这样做,但我们是这样干的. 它解决了很多场景下的查询需求,发版速度飞快,用 ...
- nginx+uwsgi+djangos部署项目完整
1.基本信息 Linux 版本:SentOS7.4 Python 版本:3.7.1 2.下载 uWSGI pip3 install uwsgi uwsgi 主要的任务是座位分发路由的服务器. 先写一个 ...
- UOJ #390. 【UNR #3】百鸽笼
UOJ #390. [UNR #3]百鸽笼 题目链接 看这道题之前先看一道相似的题目 [PKUWC2018]猎人杀. 考虑类似的容斥: 我们不妨设处理\(1\)的概率. 我们令集合\(T\)中的所有鸽 ...
- 普通用户使用docker命令
由于docker 都是root权限启动的容器, 要给研发 登录权限查看log,对于普通用,使用docker是会出现报错, 使用 gpasswd 命令把用户加入到docker组中 gpasswd -a ...
- 使用eclipse阅读java源码
很多时候想要阅读java源代码(无论是jdk自带的,还在第三方的),但是我们使用的jar包都是编译好的class包,无法在eclipse中直接打开,此时需要下载源码包. 本文以查看HttpClient ...