Linux第六周学习总结——进程额管理和进程的创建
Linux第六周学习总结——进程额管理和进程的创建
作者:刘浩晨
【原创作品转载请注明出处】 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、 进程的描述
操作系统内核三大功能:进程管理(核心)、内存管理和文件系统。
进程控制快PCB——进程描述符task_struct数据结构
进程状态(五种状态)转化:

注意:就绪状态和运行状态都是TASK_RUNNING,具体是就绪还是执行要看系统当前的资源分配情况。
进程标识符PID
进程标识符pid_t pid唯一地标识进程所有进程链表struct list_ head tasks;
双向循环链表链接起了所有的进程,也表示了父子、兄弟等进程关系程序创建的进程具有父子关系,在编程时往往需要引用这样的父子关系。Linux为每个进程分配一个8KB大小的内存区域,用于存放该进程两个不同的数据结构:Thread_ info和进程的内核堆栈。内核控制路径所用的堆栈很少,因此对栈和Thread_ info来说,8KB足够了。
进程处于内核态时使用,不同于用户态堆栈,即PCB中指定了内核栈。
struct thread_ struct thread; //与当前任务CPU状态相关,对进程上下文切换有关键性作用
struct mm_struct *mm, *active_mm; //内存管理进程的地址空间
struct files_struct *files; //打开文件描述符列表
二、 进程的创建
1. 进程的创建概览及fork一个进程的源代码
进程的起源回顾:
start_ kernel创建了cpu_ idle,即0号进程。0号进程又创建了两个线程,一个是kernel_ init,即1号进程,这个进程最终启动了用户态;另一个是kthreadd。0号进程是固定的代码,1号进程是通过复制0号进程PCB之后在此基础上做修改得到的。
2.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) //pid == 0和下面的else都会被执行到(一个是在父进程中即pid ==0的情况,一个是 在子进程中,即pid不等于0)
{
/* 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");
}
}
3. 系统调用回顾



- iret与int 0x80指令对应,一个是弹出寄存器值,一个是压入寄存器的值。
- 如果将系统调用类比于fork();那么就相当于系统调用创建了一个子进程,然后子进程返回之后将在内核态运行,而返回到父进程后仍然在用户态运行。
4.创建一个新进程在内核中的执行过程
fork、vork和clone三个系统调用都可以创建一个新进程,都通过调用do_fork()实现进程创建。
Linux通过复制父进程创建新进程:
• 复制一个PCB——task_struct
err = arch_dup_task_struct(tsk, orig);
• 给新进程分配一个新的内核堆栈
ti = alloc_ thread_ info_ node(tsk, node);
tsk->stack = ti;
setup_ thread_ stack(tsk, orig); //这里只是复制thread_ info,而非复制内核堆栈
• 从用户态的代码看fork(),函数返回了两次,即在父子进程中各返回一次。这就涉及子进程的内核堆栈数据状态和task_struct中thread记录的sp和ip的一致性问题,这是在哪里设定的——copy_thread in copy_process
*childregs = *current_pt_regs(); //复制内核堆栈,并不是全部,只是regs结构体(内核堆栈栈底的程序)
childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址,也就是说返回的就是子进程的空间了
5.创建的新进程从哪里开始执行?
一个新创建的子进程,获得CPU之后,从哪一行代码进程执行:
• 与之前写过的my_ kernel相比较,kernel中是可以指定新进程开始的位置(也就是通过eip寄存器指定代码行)。fork中也有相似的机制
• 这涉及子进程的内核堆栈数据状态和task_ struct中thread记录的sp和ip的一致性问题,这是在copy_ thread in copy_ process设定的
*childregs = *current_pt_regs(); //复制内核堆栈,并不是全部,只是regs结构体(内核堆栈栈底的程序)
childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址,也就是说返回的就是子进程的空间了
三、 实验——分析Linux内核创建一个新进程的过程
1.更新menu内核,删除test_fork.c以及test.cc,并重新执行make rootfs

2.比原先多出fork命令,编译内核查看:

3.启动gdb跟踪调试内核,在一些重要函数处设置断点:


4.在MenuOS中执行fork,停在父进程中。继续执行后,停在do_fork的位置:

5.n命令进行单步执行,依次进入copy_process、dup_task_struct。此时父进程的PCB(task_struct数据结构)已经复制过来。s命令进入函数,可以看到dst = src:


6.copy_thread函数中,把task_pg_regs(p)也就是内核堆栈特定的地址找到并初始化

7.当前进程的内核堆栈寄存器中的值复制到子进程中

8.164行:p->thread.ip = (unsigned long) ret_from_fork; //确定返回地址
9.当程序跳转到syscall_exit,就不能再继续gdb跟踪调试,输入finish使得进程运行完。
总结:
1.Linux通过复制父进程来创建一个新进程,通过调用do_fork来实现。
2.Linux为每个新创建的进程动态地分配一个task_struct结构。
3.为了把内核中的所有进程组织起来,Linux提供了几种组织方式,其中哈希表和双向循环链表方式是针对系统中的所有进程(包括内核线程),而运行队列和等待队列是把处于同一状态的进程组织起来。
4.fork()函数被调用一次,但返回两次。
Linux第六周学习总结——进程额管理和进程的创建的更多相关文章
- 20135337朱荟潼 Linux第六周学习总结——进程的描述和进程的创建
朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 第六周 进程的描述 ...
- 20135320赵瀚青LINUX第六周学习笔记
赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 这周主要讲解的是进程. ...
- LINUX内核分析第六周学习总结——进程的描述与创建
LINUX内核分析第六周学习总结--进程的描述与创建 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc ...
- LINUX内核分析第六周学习总结——进程的描述和进程的创建
LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- Linux内核分析第六周学习笔记——分析Linux内核创建一个新进程的过程
Linux内核分析第六周学习笔记--分析Linux内核创建一个新进程的过程 zl + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/U ...
- 《Linux内核分析》第六周学习总结
<Linux内核分析>第六周学习总结 ——进程的描述和进程的创建 姓名:王玮怡 学号:20135116 一.理论部分 (一)进程的描述 1 ...
- 《Linux内核分析》第六周学习笔记
<Linux内核分析>第六周学习笔记 进程的描述和创建 郭垚 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/co ...
- linux内核分析第六周学习笔记
LINUX内核分析第六周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...
- 2017-2018-1 20155228 《信息安全系统设计基础》第六周学习总结&课下作业
20155228 2017-2018-1 <信息安全系统设计基础>第六周学习总结&课下作业 教材学习内容总结 异常及其种类 异常可以分为四类:中断(interrupt) ,陷阱(t ...
随机推荐
- leetcode322—Coin Change
You are given coins of different denominations and a total amount of money amount. Write a function ...
- linux内核中socket的创建过程源码分析(详细分析)
1三个相关数据结构. 关于socket的创建,首先需要分析socket这个结构体,这是整个的核心. 104 struct socket { 105 socket_state ...
- Controller中添加一个异步的Action
给一段示例代码: public Task<ActionResult> TbReport(string code) { return Task.Factory.StartNew(() =&g ...
- C# 取两个集合的交集\并集\差集
交集:Intersect 并集:Union 差集:Except , , , , , }; , , , ,,, }; var C= A.Intersect(B); //交集 { 3, 4, 5, 6 } ...
- .NetCore Session.Redis (转载)
首先创建ASP.NET CORE Web项目,然后按如下顺序操作. 1.添加nuget程序包: Microsoft.AspNetCore.Session; Microsoft.AspNetCore.D ...
- CentOS 建立本地yum源服务器
安装CentOS系统,配置系统的网络环境 配置静态IP vi /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0 TYPE=Ethernet O ...
- intellij idea新建maven项目,一直loading archetype list.....
不知道什么时候开始,在idea里新建maven项目时,在new module页面,一直显示loading archetype list....,导致一直没办法新建.后来我以为是防火墙问题,各种设置还是 ...
- Java基础系列篇:JAVA多线程 并发编程
一:为什么要用多线程: 我相信所有的东西都是以实际使用价值而去学习的,没有实际价值的学习,学了没用,没用就不会学的好. 多线程也是一样,以前学习java并没有觉得多线程有多了不起,不用多线程我一样可以 ...
- 网络对抗技术 2017-2018-2 20152515 Exp6 信息搜集与漏洞扫描
1.实践目标 掌握信息搜集的最基础技能与常用工具的使用方法.包括: (1)各种搜索技巧的应用 (2)DNS IP注册信息的查询 (3)基本的扫描技术:主机发现.端口扫描.OS及服务版本探测.具体服务的 ...
- 20155310 《网络攻防》Exp4 恶意代码分析
20155310 <网络攻防>Exp4 恶意代码分析 基础问题 1.如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些, ...