《linux内核完全剖析》笔记03-进程创建
来源:互联网 发布:org.apache.http.wire 编辑:程序博客网 时间:2024/06/07 20:11
根据一下问题来看笔记
- 进程占多大的线形地址空间
- 进程实际分配多少物理内存
- 创建进程的开销在哪里
一. 从fork系统调用开始
kernel/sys_call.s第222行
_sys_fork: call _find_empty_process #为新进程分配id testl %eax,%eax #若为负数则返回 js 1f push %gs #压入copy_process需要的参数 pushl %esi pushl %edi pushl %ebp pushl %eax call _copy_process #调用copy_process函数 addl $20,%esp #丢弃压栈内容1: ret
二. copy_process函数分析
作用: 复制当前进程的代码段和数据段以及环境
这里需要说明的是每个任务的线性地址为64M,每个任务的线性地址不重叠。
1. copy_mem函数重点
上面代码重点分析copy_mem函数中get_base函数的意思,首先来看段描述符的格式如下图:
#define _get_base(addr) ({\unsigned long __base; \#段描述符有两个32位,%3代表 addr+7的内容,也就是上图第一行的基地址31~24的内容放到dh寄存器__asm__("movb %3,%%dh\n\t" \ #%2代表addr+4的内容,上图第一行基地址的内容放到dl寄存器 "movb %2,%%dl\n\t" \ #上面两行构成dx的内容,右移16位空出低16位 "shll $16,%%edx\n\t" \ #将addr+2的内容,上图第二行31~16的内容放到%dx,edx中构成了完整的段基址 "movw %1,%%dx" \ :"=d" (__base) \ :"m" (*((addr)+2)), \ "m" (*((addr)+4)), \ "m" (*((addr)+7))); \__base;})
- copy_mem函数的get_limit(0x0f)中0x0f的意思,段选择子的格式如下:
get_limit(0x0f)中的0x0f是段选择子,0x0f为 0000 0000 0000 1111,指定了LDT表中具有RPL=3,索引值为1,T1位为1,指定LDT表
- copy_mem函数代码分析:
- 拷贝当前进程的页目录和页表给新进程
- 设置好新进程的ldt表
int copy_mem(int nr,struct task_struct * p){ unsigned long old_data_base,new_data_base,data_limit; unsigned long old_code_base,new_code_base,code_limit; //0x0f为代码段选择子 //下面有对段选择子的说明 code_limit=get_limit(0x0f); //0x17为数据段选择子 data_limit=get_limit(0x17); //下面有重点分析 old_code_base = get_base(current->ldt[1]); old_data_base = get_base(current->ldt[2]); if (old_data_base != old_code_base) panic("We don't support separate I&D"); if (data_limit < code_limit) panic("Bad data_limit"); //进程线形地址的基地址为 64M X 进程号 new_data_base = new_code_base = nr * TASK_SIZE; p->start_code = new_code_base; //设置ldt[1]代码段的线性地址 set_base(p->ldt[1],new_code_base); //设置ldt[2]数据段的线性地址 set_base(p->ldt[2],new_data_base); //拷贝页表,在内存管理中详细说明 if (copy_page_tables(old_data_base,new_data_base,data_limit)) { free_page_tables(new_data_base,data_limit); return -ENOMEM; } return 0;}
2. copy_process函数重点
- 函数中新进程的状态改变,创建时设置为TASK_UNINTERRUPTIBLE,完成创建后,态设置为task_running
- 新进程的内核堆栈的设置以及新进程的返回值
p->tss.ep0 = PAGE_SIZE+ (long)p; //设置新进程的内核堆栈p->tss.ss0 = 0x10; //内核数据段选择子 ...p->tss.eax = 0; //新进程的返回值为0
下表是任务状态段(tss)的字段表格,这里可以参考任务状态段的描述,tss是task_struct中的一个字段.
进程的内核堆栈和用户堆栈的区别,内核堆栈分配在分配给task_struct结构的一页内存的顶端,也就是地址(long)p + PAGE_SIZE的位置,
进程的内核堆栈示意如图:
进程的用户堆栈示意图:
- 设置进程的tss段和ldt段
代码参考fork.c第130行
//gdt为gdt表的首地址,nr<<1表示每个任务有两项状态段和局部段//p->tss表示tss在task_struct中的偏移//p->ldt表示ldt在task_struct中的偏移set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
每个任务都有一个tss段和ldt段,存放在gdt表中,如下图所示:
三. 进程管理(创建)依赖内存管理子系统
copy_process的第77行,用来分配一页物理内存(通常是4k)给新进程
struct task_struct* p;...p = (struct task_struct*)get_free_page();
0 0
- 《linux内核完全剖析》笔记03-进程创建
- 《Linux内核完全剖析》阅读笔记
- 《Linux内核完全剖析》阅读笔记
- 《Linux内核完全剖析》阅读笔记
- 《Linux内核完全剖析》阅读笔记
- linux内核完全剖析0.12笔记--第一章,概述
- 《linux 内核完全剖析》 笔记 CODE_SPACE 宏定义分析
- 《linux 内核完全剖析》 signal.c 代码分析笔记
- 《linux 内核完全剖析》 exit.c 代码分析笔记
- 《linux 内核完全剖析》 fork.c 代码分析笔记
- 《linux 内核完全剖析》 vsprintf.c 代码笔记
- linux内核完全剖析 学习笔记 打字太累 截图
- 《linux内核完全剖析》笔记01-启动分析
- 《linux内核完全剖析》笔记02-中断处理
- 《linux内核完全剖析》笔记04-任务调度
- 《linux内核完全剖析》笔记05-任务退出
- 《linux内核完全剖析》笔记06-内存管理
- 《Linux内核完全剖析》读书笔记
- maven于eclipse集成-2
- openssl: error while loading shared libraries: libssl.so.1.1
- 实现Freemarker生成word文档,内容可二次写入
- 【Android开发】问答机器人,聊天类App的开发制作过程记录
- 手势冲突,设置优先级
- 《linux内核完全剖析》笔记03-进程创建
- Shell - 23
- SparkR (R on Spark)
- Android中的asset和raw文件夹
- Docker命令使用详解
- 【webbench】socket中close()和shutdown()区别
- 常用正则表达式
- 简单跨域请求和带预检的跨域请求
- OkHttp 基础(1)