Linux内核分析第六周学习总结:进程的描述和进程的创建
韩玉琪 + 原创作品转载请注明出处 + 《Linux内核分析》MOOC课程http://mooc.study.163.com/course/USTC-1000029000
一、进程的描述
为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息。
1. 进程控制块PCB——task_struct
操作系统的三大管理功能
- 进程管理
- 内存管理
- 文件系统
PCB task_struct中包含
- 进程状态
- 进程打开的文件
- 进程优先级信息
struct task_struct数据结构很庞大
2. Linux进程的状态
不同于操作系统(就绪、运行、阻塞)
图片来源:《Linux内核设计与实现》
定义的进程状态
3. 我们关心的字段
4. 分析内核处理过程
(1)do_fork
- 调用
copy_process
,将当前进程复制一份出来给子进程,并且为子进程设置相应地上下文信息。 - 调用
wake_up_new_task
,将子进程放入调度器的队列中,此时的子进程就可以被调度进程选中运行。
(2)copy_process
- 创建进程描述符以及子进程所需要的其他所有数据结构,为子进程准备运行环境
- 调用
dup_task_struct
复制一份task_struct
结构体,作为子进程的进程描述符。 - 复制所有的进程信息
- 调用
copy_thread
,设置子进程的堆栈信息,为子进程分配一个pid。
(3)dup_ task_ struct
先调用
alloc_task_struct_node
分配一个task_struct
结构体。调用
alloc_thread_info_node
,分配了一个union。这里分配了一个thread_info
结构体,还分配了一个stack数组。返回值为ti,实际上就是栈底。tsk->stack = ti
将栈底的地址赋给task的stack变量。最后为子进程分配了内核栈空间。
执行完
dup_task_struct
之后,子进程和父进程的task结构体,除了stack指针之外,完全相同。
(4)copy_thread
- 获取子进程寄存器信息的存放位置
- 对子进程的thread.sp赋值,将来子进程运行,这就是子进程的esp寄存器的值。
- 如果是创建内核线程,那么它的运行位置是
ret_from_kernel_thread
,将这段代码的地址赋给thread.ip,之后准备其他寄存器信息,退出 - 将父进程的寄存器信息复制给子进程。
- 将子进程的eax寄存器值设置为0,所以fork调用在子进程中的返回值为0.
- 子进程从
ret_from_fork
开始执行,所以它的地址赋给thread.ip,也就是将来的eip寄存器。
(5)运行新进程
从ret_from_fork处开始执行
dup_task_struct
中为其分配了新的堆栈copy_process
中调用了sched_fork
,将其置为TASK_RUNNING
copy_thread
中将父进程的寄存器上下文复制给子进程,这是非常关键的一步,这里保证了父子进程的堆栈信息是一致的。- 将
ret_from_fork
的地址设置为eip寄存器的值,这是子进程的第一条指令。
二、进程的创建
1. fork
- fork系统调用在父进程和子进程各返回一次
- 子进程中返回的是0,父进程中返回值是子进程的pid。
2. 创建一个新进程在内核中的执行过程
fork、vfork和clone三个系统调用都可以创建一个新进程,而且都是通过调用do_fork来实现进程的创建。
- 创建新进程是通过复制当前进程实现的。
do_fork
主要是复制了父进程的task_struct
,然后修改必要的信息,从而得到子进程的task_struct
。
复制一个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,而非复制内核堆栈
要修改复制过来的进程数据,比如pid、进程链表等。
3. 子进程系统调用处理过程
*childregs = *current_pt_regs(); //复制内核堆栈
childregs->ax = 0; //子进程的fork返回0的原因
p->thread.sp = (unsigned long) childregs; //调度到子进程时的内核栈顶
p->thread.ip = (unsigned long) ret_from_fork; //调度到子进程时的第一条指令地址
- 刚fork出来的子进程是从
ret_from_fork
开始执行的,然后跳转到syscall_exit
,从系统调用中返回。
三、实践:分析Linux内核创建一个新进程的过程
1. 启动MenuOS
cd LinuxKernel
rm menu -rf
git clone https://github.com/mengning/menu.git
cd menu
mv test_fork.c test.c
make rootfs
2. gdb调试fork命令
qemu -kernel linux-3.18.6/arch/x86/boot/bzImage -initrd rootfs.img -s -S
在新窗口中启动调试:
$ gdb
$ file linux-3.18.6/vmlinux
$ target remote:1234
设置断点:
- b sys_clone
- b do_fork
- b dup_task_struct
- b copy_process
- b copy_thread
- b ret_from_fork
在Menu系统中输入fork指令,可以看到只输出了fork功能的描述,在断点处sys_clone处停止了。
继续调试,停在do_ fork 和copy_ process
程序停在dup_task_struct函数处
在copy_thread函数中,继续单步执行,可以看到,内核空间压栈地址被初始化了。
程序停止在了ret_ from_ fork处,当前系统执行的是汇编代码。(同时打印出进程信息)
四、总结
Linux通过复制父进程来创建一个新进程,通过调用do_ fork来实现并为每个新创建的进程动态地分配一个task_ struct结构。
1. 新进程的开始
copy_thread()中:
p->thread.ip = (unsigned long) ret _from _fork;
将子进程的ip设置为ret_ form _ fork的首地址,因此子进程是从ret_ from_ fork开始执行的。
2. 执行起点与内核堆栈保证一致
在设置子进程的ip之前:
*childregs = *current_ pt_ regs();
将父进程的regs参数赋值到子进程的内核堆栈,*childregs的类型为pt_regs,其中存放了SAVE ALL中压入栈的参数。
Linux内核分析第六周学习总结:进程的描述和进程的创建的更多相关文章
- LINUX内核分析第六周学习总结——进程的描述与创建
LINUX内核分析第六周学习总结--进程的描述与创建 标签(空格分隔): 20135321余佳源 余佳源 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc ...
- linux内核分析第六周学习笔记
LINUX内核分析第六周学习总结 标签(空格分隔): 20135328陈都 陈都 原创作品转载请注明出处 <Linux内核分析>MOOC课程 http://mooc.study.163.c ...
- 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内核分析——第六周学习笔记20135308
第六周 进程的描述和进程的创建 一.进程描述符task_struct数据结构 1.操作系统三大功能 进程管理 内存管理 文件系统 2.进程控制块PCB——task_struct 也叫进程描述符,为了管 ...
- Linux内核分析——第六周学习笔记
进程的描述和进程的创建 前言:以下笔记除了一些讲解视频中的概念记录,图示.图示中的补充文字.总结.分析.小结部分均是个人理解.如有错误观点,请多指教! PS.实验操作会在提交到MOOC网站的博客中写.
- LINUX内核分析第七周学习总结——可执行程序的装载
LINUX内核分析第六周学习总结——进程的描述和进程的创建 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- LINUX内核分析第七周学习总结:可执行程序的装载
LINUX内核分析第七周学习总结:可执行程序的装载 韩玉琪 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/cours ...
- LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程
LINUX内核分析第八周学习总结——进程的切换和系统的一般执行过程 张忻(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/c ...
随机推荐
- Sprint第二个冲刺(第十天)
一.Sprint 计划会议: 现在总结一下情况,正在做的3个功能的完成程度已经达到了80%,过几天就可以完成了.也把之前做的修改界面放入fragment中,方便修改管理.效果图如下: 二.Sprint ...
- 黑马程序员——JAVA基础之标准输入输出流
------- android培训.java培训.期待与您交流! ---------- 标准输入输出流: System中的基本字段,in,out 它们各代表了系统标准的输入和输出设备. 默认输入设备是 ...
- 为重负网络优化 Nginx 和 Node.js --引用自https://linux.cn/article-1314-1.html
为重负网络优化 Nginx 和 Node.js 在搭建高吞吐量web应用这个议题上,NginX和Node.js可谓是天生一对.他们都是基于事件驱动模型而设计,可以轻易突破Apache等传统web服务器 ...
- Python paramiko 模块
paramiko模块机遇SSH用于连接远程服务器并执行相关操作 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: import paramiko # 创建SSH对象 ssh ...
- IOCP简单实现
本人工作是服务端性能测试,因工作需要开发机器人框架,选用底层的时候看到网上满大街的IOCP介绍,还有说IOCP比WSAAsyncSelect复杂等等,所以只好转WSAAsyncSelect实现. 因并 ...
- zookeeper 笔记
http://www.biaodianfu.com/zookeeper.html ======= ---- zookeeper这种数据结构有如下这些特点: 1,每个子目录如NameService都被作 ...
- PHP函数getopt详解
短参数 它返回一个包含命令行参数的数组.比如,要获得-a -b 和-c的值,可以这么做: $arguments = getopt("a:b:c:"); 可以用下面的方式运行脚本(有 ...
- Delphi制作DLL
一.开使你的第一个DLL专案 1.File->Close all->File->New﹝DLL﹞ 代码: //自动产生Code如下 library Project2; //这有段废话 ...
- [家里蹲大学数学杂志]第056期Tikhonov 泛函的变分
设 $\scrX$, $\scrY$ 是 Hilbert 空间, $T\in \scrL(\scrX,\scrY)$, $y_0\in\scrY$, $\alpha>0$. 则 Tikhonov ...
- chrome设置可以跨域访问
右键chrome的快捷方式->属性 修改目标属性:添加--args --disable-web-security --user-data-dir=F:\MyChromeDevUserData, ...