Linux-0.11 kernel目录fork.c详解
Linux-0.11 kernel目录fork.c详解
fork.c中主要实现内核对于创建新的进程的行为。其中copy_process是其最核心的函数。
copy_process
int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,long ebx,long ecx,long edx,long fs,long es,long ds,long eip,long cs,long eflags,long esp,long ss)
该函数的作用是从old进程中复制出一个new进程。 该函数在system_call.s中的sys_fork函数中执行。
copy_process从INT 0x80中断触发system_call系统调用,进而调用sys_fork。此时内核栈的状态如下所示:
这与copy_process的参数是一致的。
该函数首先在内存中分配了一个空闲页用于存储进程的PCB,即task_struct结构。并将该PCB放入了PCB的数组中。
最后将old进程的PCB内容先直接拷贝给new进程。
p = (struct task_struct *) get_free_page();
if (!p)return -EAGAIN;
task[nr] = p;
*p = *current;
下面这段就是将继承来的PCB结构进行适当的修改,详细解释见注释。
p->state = TASK_UNINTERRUPTIBLE;//设置进程状态为不可被中断
p->pid = last_pid;//last_pid为find_empty_process找到的没有被使用的pid值, 将其设置给新的进程
p->father = current->pid;//设置该进程的父进程
p->counter = p->priority;//设置该进程的时间片, 值等于其优先级的值。
p->alarm = 0; //alarm定时的时间
p->leader = 0; //是否是进程组的leader
p->utime = p->stime = 0; //用户态运行时间和和核心态运行时间
p->cutime = p->cstime = 0;//子进程用户态运行时间和核心态运行时间。
p->start_time = jiffies;//进程的开始时间设置为系统的滴答数。
下面一段是设置PCB中有关TSS寄存器的值。下面也通过注释进行详解。
首先设置了内核栈的栈
p->tss.back_link = 0;
p->tss.esp0 = PAGE_SIZE + (long) p;//进程的内核栈栈顶指针
p->tss.ss0 = 0x10;//内核栈的段选择符
接下来是设置tss寄存器关于其他cpu寄存器的值。
p->tss.eip = eip;
p->tss.eflags = eflags;
p->tss.eax = 0;
p->tss.ecx = ecx;
p->tss.edx = edx;
p->tss.ebx = ebx;
p->tss.esp = esp;
p->tss.ebp = ebp;
p->tss.esi = esi;
p->tss.edi = edi;
p->tss.es = es & 0xffff; //段寄存器取16位
p->tss.cs = cs & 0xffff;
p->tss.ss = ss & 0xffff;
p->tss.ds = ds & 0xffff;
p->tss.fs = fs & 0xffff;
p->tss.gs = gs & 0xffff;
下面这里,设置tss中ldt的值。
p->tss.ldt = _LDT(nr);
p->tss.trace_bitmap = 0x80000000;
GDT表中每一项是8个字节,每个进程拥有一个TSS和LDT,因此每个进程占用字节是16字节, 因此序号为n的进程的LDT在GDT表中的偏移量就是n*16 + 5*8
#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
如对上述知识遗忘,可以通过下面这张图进行温故。
下面这里进程内存的拷贝, 实际上确定进行进程新的线性地址, 并进行页表的拷贝。详见本文中copy_mem的讲解。
if (copy_mem(nr,p)) {task[nr] = NULL;free_page((long) p);return -EAGAIN;
下面主要处理对进程打开的文件的引用计数增加1。
for (i=0; i<NR_OPEN;i++)if ((f=p->filp[i]))f->f_count++;
if (current->pwd)current->pwd->i_count++;
if (current->root)current->root->i_count++;
if (current->executable)current->executable->i_count++;
这里设置GDT表中tss和ldt描述符的内容。
set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss));
set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&(p->ldt));
p->state = TASK_RUNNING; /* do this last, just in case */
copy_mem
int copy_mem(int nr,struct task_struct * p)
该函数的作用是复制进程的页表。
code_limit=get_limit(0x0f);//根据代码段选择符获取代码段的长度
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");
//确立新进程的代码段地址, Linux-0.11的线性地址是按照64M划分的,所以进程号nr的线性地址的起始位置是nr* 0x4000000
new_data_base = new_code_base = nr * 0x4000000;
p->start_code = new_code_base; // 设置该位置到PCB中
set_base(p->ldt[1],new_code_base); //设置代码段的地址
set_base(p->ldt[2],new_data_base); //设置数据段的地址
下面这段代码是将数据段所属的页表的进行。
if (copy_page_tables(old_data_base,new_data_base,data_limit)) {printk("free_page_tables: from copy_mem\n");free_page_tables(new_data_base,data_limit);return -ENOMEM;
}
copy_page_tables在memory.c中定义。
verify_area
void verify_area(void * addr,int size)
该函数用于在进程空间进行写操作时进行地址验证的函数。
addr是指在进程线性地址中相对于起始位置的偏移量, size指的是大小。
由于检测判断是以4K页为单位进行操作的,因此程序需要找出addr所在页的起始地址,如下图所示。
下面这段代码就是去寻找addr所在的内存页的起始地址, 即start。
unsigned long start;start = (unsigned long) addr;
size += start & 0xfff; //size 加上页内偏移
start &= 0xfffff000; //start为逻辑地址的以4K为划分的起始地址
start += get_base(current->ldt[2]);//获取当前进程在线性地址中数据段的起始地址, 加起来就是该逻辑地址转化到了线性地址
下面进行写保护验证, 如果页面不可以写,则进行页面复制。
while (size>0) {size -= 4096;write_verify(start);start += 4096;
}
write_verify函数详解可以参考memory.c文件的讲解。
find_empty_process
int find_empty_process(void)
该函数的作用是在全局的task数组中找到一个空闲的项,并返回其下标。其在system_call.s中的sys_fork函数中被调用。
首先是寻找一个pid值
repeat:if ((++last_pid)<0) last_pid=1;for(i=0 ; i<NR_TASKS ; i++)if (task[i] && task[i]->pid == last_pid) goto repeat;
接着是去task数组中寻找可用的位置
for(i=1 ; i<NR_TASKS ; i++)if (!task[i])return i;
相关文章:

Linux-0.11 kernel目录fork.c详解
Linux-0.11 kernel目录fork.c详解 fork.c中主要实现内核对于创建新的进程的行为。其中copy_process是其最核心的函数。 copy_process int copy_process(int nr,long ebp,long edi,long esi,long gs,long none,long ebx,long ecx,long edx,long fs,long es,long ds,long eip,…...

如何或者无插件Web页面监控播放软件LiveNVR的固定视频流地址,实现大屏上墙、播放、视频分析等目的
1、LiveNVR介绍 LiveNVR的安防监控的视频直播,可以按标准的Onvif/RTSP协议接入监控设备,也可以通过海康、大华、天地伟业等厂家私有SDK接入监控,实现web页面的播放和录像回放。 可以分发HTTP-FLV、WS-FLV、WebRTC、RTMP、HLS(M3U8)、RTSP等多…...
postman断言脚本(2)
https://learning.postman.com/docs/writing-scripts/script-references/test-examples/#parsing-response-body-data状态码pm.test("Status code is 200",function(){pm.response.to.have.status(200);});pm.test("Status code is 200",()>{pm.expect(…...

js中?.、??的具体用法
1、?. (可选链运算符) 在javascript中如果一个值为null、undefined,直接访问下面的属性, 会报 Uncaught TypeError: Cannot read properties of undefined 异常错误。 而在真实的项目中是会出现这种情况,有这个值就…...

刷题笔记1 | 704. 二分查找,27. 移除元素
704. 二分查找 给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。 输入: nums [-1,0,3,5,9,12], target 9 输出: 4 …...

柔性电路板的优点、分类和发展方向
柔性电路板是pcb电路板的一种,又称为软板、柔性印刷电路板,主要是由柔性基材制作而成的一种具有高可靠性、高可挠性的印刷电路板,具有厚度薄、可弯曲、配线密度高、重量轻、灵活度高等特点,主要用在手机、电脑、数码相机、家用电器…...

OpenCV入门(二)快速学会OpenCV1图像基本操作
OpenCV入门(一)快速学会OpenCV1图像基本操作 不讲大道理,直接上干货。操作起来。 众所周知,OpenCV 是一个跨平台的计算机视觉库, 支持多语言, 功能强大。今天就从读取图片,显示图片,输出图片信息和简单的…...

Redis源码---有序集合为何能同时支持点查询和范围查询
目录 前言 Sorted Set 基本结构 跳表的设计与实现 跳表数据结构 跳表结点查询 跳表结点层数设置 哈希表和跳表的组合使用 前言 有序集合(Sorted Set)是 Redis 中一种重要的数据类型,它本身是集合类型,同时也可以支持集合中…...

从计费出账加速的设计谈周期性业务的优化思考
1号恐惧症 你有没有这样的做IT的朋友?年纪轻轻,就头发花白或者秃顶,然后每个月周期性的精神不振,一到月底,就有明显的焦虑。如果有,他可能就是运营商行业做计费运营的,请对他好点,特…...

垃圾回收的概念与算法(第四章)
《实战Java虚拟机:JVM故障诊断与性能优化 (第2版)》 第4章 垃圾回收的概念与算法 目标: 了解什么是垃圾回收学习几种常用的垃圾回收算法掌握可触及性的概念理解 Stop-The-World(STW) 4.1. 认识垃圾回收 - 内存管理清洁工 垃圾…...

让您的客户了解您的制造过程“VR云看厂实时数字化展示”
一、工厂云考察,成为市场热点虚拟现实(VR)全景技术问世已久,但由于应用范围较为狭窄,一直未得到广泛应用。国外客户无法亲自到访,从而导致考察难、产品取样难等问题,特别是对于大型制造企业来说…...

CV——day80 读论文:DLT-Net:可行驶区域、车道线和交通对象的联合检测
DLT-Net:可行驶区域、车道线和交通对象的联合检测I. INTRODUCTIONII. ANALYSIS OF PERCEPTIONIV. DLT-NETA. EncoderB. Decoder1) Drivable Area Branch(可行驶区域分支)2) Context Tensor(上下文张量)3) Lane Line Branch(车道线分支)4) Traffic Object Branch(目标检测对象分…...

工具篇4.5数据可视化工具大全
1.1 Flourish 数据可视化不仅是一项技术,也是一门艺术。当然,数据可视化的工具也非常多,仅 Python 就有 matplotlib、plotly、seaborn、bokeh 等多种可视化库,我们可以根据自己的需要进行选择。但不是所有的人都擅长写代码完成数…...
京东前端二面常考手写面试题(必备)
实现发布-订阅模式 class EventCenter{// 1. 定义事件容器,用来装事件数组let handlers {}// 2. 添加事件方法,参数:事件名 事件方法addEventListener(type, handler) {// 创建新数组容器if (!this.handlers[type]) {this.handlers[type] …...

如何用AST还原某音的JSVMP
1. 什么是JSVMP vmp简单来说就是将一些高级语言的代码通过自己实现的编译器进行编译得到字节码,这样就可以更有效的保护原有代码,而jsvmp自然就是对JS代码的编译保护,具体的可以看看H5应用加固防破解-JS虚拟机保护方案。 如何区分是不是jsv…...

【蓝桥杯试题】 递归实现指数型枚举例题
💃🏼 本人简介:男 👶🏼 年龄:18 🤞 作者:那就叫我亮亮叭 📕 专栏:蓝桥杯试题 文章目录1. 题目描述2. 思路解释2.1 时间复杂度2.2 递归3. 代码展示最后&#x…...

【用Group整理目录结构 Objective-C语言】
一、接下来,我们看另外一个知识点,怎么用Group把这一堆乱七八糟的文件给它整理一下,也算是封装一下吧, 1.这一堆杂乱无章的文件: 那么,哪些类是属于模型呢,哪些类是属于视图呢,哪些类是属于控制器呢, 我们接下来通过Group的方式,来给它们分一下类, 这样看起来就好…...

JavaScript高级程序设计读书分享之8章——8.1理解对象
JavaScript高级程序设计(第4版)读书分享笔记记录 适用于刚入门前端的同志 创建自定义对象的通常方式是创建 Object 的一个新实例,然后再给它添加属性和方法。 let person new Object() person.name Tom person.age 18 person.sayName function(){//示 this.name…...

代码随想录算法训练营第四十天 | 343. 整数拆分,96.不同的二叉搜索树
一、参考资料整数拆分https://programmercarl.com/0343.%E6%95%B4%E6%95%B0%E6%8B%86%E5%88%86.html 视频讲解:https://www.bilibili.com/video/BV1Mg411q7YJ不同的二叉搜索树https://programmercarl.com/0096.%E4%B8%8D%E5%90%8C%E7%9A%84%E4%BA%8C%E5%8F%89%E6%90…...

数据结构与算法系列之顺序表的实现
这里写目录标题顺序表的优缺点:注意事项test.c(动态顺序表)SeqList.hSeqList.c各接口函数功能详解void SLInit(SL* ps);//定义void SLDestory(SL* ps);void SLPrint(SL* ps);void SLPushBack(SL* ps ,SLDataType * x );void SLPopBack(SL* ps…...

SpringBoot-17-MyBatis动态SQL标签之常用标签
文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...

盘古信息PCB行业解决方案:以全域场景重构,激活智造新未来
一、破局:PCB行业的时代之问 在数字经济蓬勃发展的浪潮中,PCB(印制电路板)作为 “电子产品之母”,其重要性愈发凸显。随着 5G、人工智能等新兴技术的加速渗透,PCB行业面临着前所未有的挑战与机遇。产品迭代…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...

前端导出带有合并单元格的列表
// 导出async function exportExcel(fileName "共识调整.xlsx") {// 所有数据const exportData await getAllMainData();// 表头内容let fitstTitleList [];const secondTitleList [];allColumns.value.forEach(column > {if (!column.children) {fitstTitleL…...

srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...

Java面试专项一-准备篇
一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如:…...
Swagger和OpenApi的前世今生
Swagger与OpenAPI的关系演进是API标准化进程中的重要篇章,二者共同塑造了现代RESTful API的开发范式。 本期就扒一扒其技术演进的关键节点与核心逻辑: 🔄 一、起源与初创期:Swagger的诞生(2010-2014) 核心…...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...