Linux内核分析— —创建新进程的过程
分析Linux内核创建一个新进程的过程
实验过程
要求:使用gdb跟踪分析一个fork系统调用内核处理函数sys_clone ,验证对Linux系统创建一个新进程的理解,推荐在实验楼Linux虚拟机环境下完成实验。

cd LinuxKernel
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S

课程内容
阅读理解task_struct数据结构:
进程控制块PCB——task_struct
1、操作系统的三大管理功能包括:
(1)进程管理
(2)内存管理
(3)文件系统
2、PCB task_struct中包含:
(1)进程状态
(2)进程打开的文件
(3)进程优先级信息
3、通过唯一的进程标识PID来区别每个进程。
4、进程状态转化
(1)创建新进程后实际的状态是TASK_RUNNING,就绪但是没有运行,调度器选择一个task之后进入运行态,也叫TASK_RUNNING。
(2)当进程是TASK_RUNNING时,代表这个进程是可运行的,至于它有没有真的在运行,取决于它有没有获得cpu的控制权,即有没有在cpu上实际的运行。
(3)一个正在进行的进程调用do_exit(),进入TASK_ZOMBIE,进程被终止,“僵尸进程”。
(4)等待特定时间或者资源的时候,进入阻塞态,如果条件满足就进入就绪态,被选择后进入运行态。
5、task_struct结构体分析
struct task_struct{
volatile long state; //进程的状态
unsigned long flags; //调用fork时候给出的进程号
long nice; //进程的基本时间片
unsigned long policy; //进程的调度策略
struct mm_struct *mm; //进程内存管理信息
struct list_head run_list; //指向运行队列的指针
unsigned long sleep_time; //进程的睡眠时间
struct task_struct *next_task, *prev_task; //用于将系统中所有的进程连接成一个双向循环链表
pid_t pid;//进程标识符,用来代表一个进程
pid_t pgrp;//进程组标识,表示进程所属的进程组
pid_t tty_old_pgrp;//进程控制终端所在的组标识
pid_t session;//进程的会话标识
pid_t tgid;
struct list_head thread_group; //线程链表
struct task_struct *pidhash_next;//用于将进程链入HASH表pidhash
struct task_struct **pidhash_pprev;
wait_queue_head_t wait_chldexit; //供wait4()使用
struct completion *vfork_done; // 供vfork() 使用
unsigned long rt_priority;//实时优先级
struct fs_struct *fs; //文件系统信息
struct files_struct *files; //打开文件信息
}
Linux系统如何创建一个新进程:
使用fork系统调用可以创建一个进程,fork之后可以调用exec接口用来执行新进程的代码。
fork函数对应的内核处理过程sys_clone。
do_fork步骤:
查找pidmap_array位图,为子进程分配新的PID
检查父进程ptrace字段,若其不为0,而且紫禁城不是内核线程,则do_fork()函数就会设置CLONE_PTRACE标志
调用函数copy_process(),从而将复制进程描述符。如果所有必要的资源都是可用的,则copy_process()返回刚创建的task_struct描述符的地址。copy_process的具体步骤:
检查参数clone_flags所传递标志的一致性
通过调用security_task_create(clone_flags)函数以及security_task_alloc(p)函数执行安全检查
调用dup_task_struct(current)函数来为子进程获得进程描述符
dup_task_struct函数将当前进程所获取的thread_info结构复制给子进程的thread_info结构中。
执行alloc_task_struct(),用分配器task_struct_cachep为新进程获取进程描述符,并将进程描述符的地址保存在tsk中。
执行alloc_thread_info来获取一片空的内存空间,用来存放新进程的thread_info和内核堆栈,并将这些内存区域字段的地址存放在变量ti中。
将current进程描述符的内容复制到tsk所指向的task_struct结构体之中,然后把ti赋给tsk->thread_info,让心建立的tsk指向的task_struct和orig指向父进程的task_struct中的每个值,即将父进程的所有内容都复制给新的进程之中。
把current进程的thread_info描述符的内容复制给ti所指向的结构体之中,将tsk赋给ti->task
返回新进程的进程描述符指针tsk
设置子进程与进程状态相关的几个关键字段:
把大内核锁计数器tsk->lock_depth初始化为-1。
把tsk->did_exec字段初始化为0:它记录了进程发出的execve()系统调用的次数。
通过copy_flags函数更新从父进程复制到tsk->flags字段中的一些标志:首先清除PF_SUPERPRIV标志,该标志表示进程是否使用了某种超级用户权限。然后设置PF_FORKNOEXEC标志,它表示子进程还没有发出execve()系统调用。
将新进程的PID存入tsk_pid字段
调用copy_semundo、copy_files、copy_fs、copy_sighand、copy_signal、copy_mm和copy_namespace来创建新的数据结构,并把父进程的相应数据结构的值复制到新数据结构中,除非clone_flags参数指出它们有不同的值。
调用copy_thread(0, clone_flags, stack_start, stack_size, p, regs),用发出clone()系统调用时CPU寄存器的值来初始化子进程的内核栈。进程描述符的thread.esp字段初始化为子进程内核栈的基地址,汇编语言函数ret_from_fork()的地址存放在thread.eip字段中。
调用sched_fork(p)完成对新进程调度程序数据结构的初始化。
如果已经设置了CLONE_STOPPED标志,那么子进程的状态会被设置成了终止状态。在另一个进程把子进程状态恢复成TASK_RUNNING之前,一直保持该状态。
如果没有设置ClONE_STOPPED标志,则调用wake_up_new_task函数来调节父进程与子进程的调用顺序。
终止并返回子进程描述符指针。
在do_fork()结束之后,在内存开始调用子进程的时候,将会继续完善子进程,即将子进程描述符thread字段的值装入各CPU寄存器之中。尤其需要注意的是,需要把thread.esp装入esp寄存器,把函数ret_from_fork()的地址装入eip寄存器中。
分析新进程的执行起点及对应的堆栈状态:
创建的新进程的执行起点:ret_from_fork
对应的堆栈状态:
*childregs = *current_pt_regs(); //复制内核堆栈
childregs->ax = 0; //为什么子进程的fork返回0,这里就是原因!
p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址
ip指向的是ret_from_fork,所以是从这里开始执行的。
复制内核堆栈的时候是复制的pt_regs,即只复制了SAVE_ALL相关的那一部分,即系统调用压栈的那一部分。
pt_regs里面内容有:
Entry(ret_from_fork):
最终会跳转到syscall_exit,这之前的内核堆栈状态和syscall_call的一致,然后返回用户态,变成子进程的用户态。
总结部分
对“Linux系统创建一个新进程”的理解:
在Linux系统中,使用fork系统调用可以创建一个进程。fork()系统调用从内核返回两次:一次回到父进程,另一次回到新产生的子进程。它实际上是由clone()系统调用实现的。
可以通过fork,复制一个已有的进程,进而产生一个子进程,新进程几乎但不完全与父进程相同。子进程得到和父进程用户级虚拟地址空间相同的一份拷贝,包 括代码段,数据段和bss段,堆以及用户栈。子进程还获得和父进程任何打开文件描述符相同的拷贝,最大的区别就是在于他们拥有不同的PID.
注:林涵锦 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
Linux内核分析— —创建新进程的过程的更多相关文章
- Linux内核分析-创建新进程的过程
分析Linux内核创建一个新进程的过程 task_struct结构体分析 struct task_struct{ volatile long state; //进程的状态 unsigned long ...
- Linux内核分析 笔记六 进程的描述和进程的创建 ——by王玥
一.知识点总结 (一)进程的描述 1.操作系统内核里有三大功能: 进程管理 内存管理 文件系统 2.进程描述符:task_struct 2.进程描述符——struct task_struct 1. p ...
- Linux内核分析 笔记八 进程的切换和系统的一般执行过程 ——by王玥
一.进程切换的关键代码switch_to的分析 (一)进程调度与进程调度的时机分析 1.不同类型的进程有不同的调度需求 第一种分类: I/O-bound:频繁地进行I/O,花费很多的时间等待I/O操作 ...
- 分析Linux内核创建一个新进程的过程【转】
转自:http://www.cnblogs.com/MarkWoo/p/4420588.html 前言说明 本篇为网易云课堂Linux内核分析课程的第六周作业,本次作业我们将具体来分析fork系统调用 ...
- 20135202闫佳歆--week6 分析Linux内核创建一个新进程的过程——实验及总结
week 6 实验:分析Linux内核创建一个新进程的过程 1.使用gdb跟踪创建新进程的过程 准备工作: rm menu -rf git clone https://github.com/mengn ...
- 《Linux内核分析》第六周 进程的描述与创建
[刘蔚然 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] WEEK SIX(3 ...
- LINUX内核分析第六周学习总结——进程的描述和进程的创建
LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- 20135239益西拉姆 Linux内核分析 进程的描述和进程的创建
[益西拉姆 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000] 第六周 进程的描述 ...
- 《Linux内核分析》第六周笔记 进程的描述和进程的创建
进程的描述和进程的创建 一.进程的描述 1.进程描述符task_struct数据结构(一) 操作系统的三大功能:进程管理(核心).内存管理.文件系统. 进程控制块PCB——task_struct(进程 ...
随机推荐
- DLL加载顺序
最近碰到了一个问题,要引入一个第三方的SDK,但是SDK中使用的一些dll和我原本程序里面有些dll是同名的,而且本程序的dll和sdk的dll名称都不能修改. 解决这个问题,首先想到的就是多进程,这 ...
- 使用CefSharp跳转页面不弹出页面:
using CefSharp; using CefSharp.Wpf; namespace Common.Control { internal class CefSharpOpenPageSelf : ...
- 五、git创建及合并分支
1. 创建并切换到dev分支 git checkout -b dev // git checkout命令加上-b参数表示创建并切换,相当于以下两条命令 git branch dev git check ...
- pandas中DataFrame对象to_csv()方法中的encoding参数
当使用pd.read_csv()方法读取csv格式文件的时候,常常会因为csv文件中带有中文字符而产生字符编码错误,造成读取文件错误,在这个时候,我们可以尝试将pd.read_csv()函数的enco ...
- 在Oracle中使用Guid
sys_guid() - 唯一索引 在Oracle中可以用SYS_GUID()来生成一个guid,相当于msSql中的newid(). 在Oracle9i和Oracle 10g 里SYS_GUID ...
- Java链式方法
http://blog.csdn.net/lemon_shenzhen/article/details/6358537 有两种情况可运用链式方法: 第一种 除最后一个方法外,每个方法都返回一个对象 ...
- Android UI开发神兵利器之Android Action Bar Style Generator
版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/x359981514/article/details/26283129 ActionBar是3.0后的 ...
- MongoDB逻辑操作符$or, $and,$not,$nor
$or是一个逻辑or操作符操作在一个数据或者多个表达式并且需要选择至少一个满足条件的表达式,$or有至少以下表达式: { $or: [ { <expression1> }, { <e ...
- Qt 编程指南10 QImage Mat QPixmap转换
//示例 pushButtonOpenPicBig按钮clicked单击动作触发 void Qt_Window::on_pushButtonOpenPicBig_clicked() { strin ...
- MATLAB——线性神经网络
这个函数默认使用最小二乘,所以不需要训练 % example5_1.m x=-:; y=*x-; % 直线方程为 randn(); % 设置种子,便于重复执行 y=y+randn(,length(y ...