当前位置: 首页 > news >正文

在美国克罗格做网站怎样互联网宣传推广

在美国克罗格做网站怎样,互联网宣传推广,wordpress邮箱验证插件,电商平台项目我们在学习操作系统课程的时候,应该都学过fork的概念。fork是一个系统调用,用于将当前进程/线程分裂成完全相同的两个。 在网络上,很多关于fork的文章都大同小异,讲的都是很通用的fork的原理以及大致的过程。但是,大家…

我们在学习操作系统课程的时候,应该都学过fork的概念。fork是一个系统调用,用于将当前进程/线程分裂成完全相同的两个。

在网络上,很多关于fork的文章都大同小异,讲的都是很通用的fork的原理以及大致的过程。但是,大家有没有想过一个问题:用户程序调用fork()和内核下调用fork(),背后的逻辑是不一样的。咱平时如果没有真的去写操作系统的话,应该不会意识到这个问题。

虚拟地址空间分布

首先,我们先来了解一下进程的虚拟地址空间是怎么分布的:

虚拟地址空间的高地址部分为内核空间,低地址部分为用户空间。各个进程之间的内核空间是共享的,只有用户空间才是独占的。

每个进程都有1个内核栈,这个内核栈位于内核空间。并且,每个进程还有一个用户栈,位于低地址部分。

当进程陷入内核态的时候,将会使用内核栈进行处理,当返回用户态的时候,又会换回去,使用用户栈。

需要注意的是,用户栈在用户空间的映射是由操作系统指定的,父子进程的用户栈的虚拟地址是相同的。而父子进程的内核栈的虚拟地址则是不同的。

用户态进程调用fork()

网络上的文章一般描述的是用户态下的fork。用户态的fork是这样的一个过程:

 

首先,用户进程发起系统调用,陷入内核态。然后在fork系统调用的函数里面,操作系统将会初始化pcb、线程结构体、对用户空间的内存的拷贝,最后把子进程加入调度队列。

这里“内存拷贝”这一点就是关键所在,也是众多文章没有提及的部分。

在用户态的fork中,由于用户进程的栈空间位于就是位于用户空间之中,并且用户栈一般是位于操作系统指定的地址上,不同的进程的用户栈的基地址相同。又由于进程在返回用户态的时候,内核栈是空的,因此,我们只需要将用户空间进行拷贝,当子进程返回用户态的时候,自然就能执行。这是理所当然的事情。

内核态进程的fork

对于在内核态下运行进程而言,其具有在低地址空间的进程的栈,也具有高地址空间部分的内核栈。进程正常运行时,使用其低地址空间部分的栈,发起了系统调用之后,则会使用其高地址空间的内核栈。内核态进程的fork和用户进程的fork是相同的。

内核线程的fork

讲了这么久,这才轮到我们的主角:内核线程。内核线程的fork的过程与前面提到的两者是不同的。

首先,我们需要认识一下内核线程。内核线程是内核中的一些线程,他们共用同一个虚拟地址空间。并且,他们运行时所使用的栈只有内核栈。也就是说,父进程在系统调用返回的时候,并不会执行切换到用户栈的操作(因为根本不存在)!

那么,这样对我们的fork有什么影响呢?

必须拷贝内核栈

由于我们的内核线程只使用内核栈,那就意味着,fork()系统调用到来时,内核栈中除了系统调用的栈帧以外,还会有其他内容!我们必须拷贝内核栈!

 

如上图所示,如果是用户进程/内核进程的fork,由于其在发起fork()调用之前,他们一直工作在自己的用户空间的栈上,内核栈是空的。发起fork系统调用后,内核栈中才会被压入一个fork调用所在的栈帧。由于进程最终都要返回到其用户栈上,且离开内核的时候,内核栈必须为空。因此我们不需要拷贝内核栈的内容,只需要拷贝用户栈的内容。而用户栈就是位于用户空间内,因此对用户空间的整体拷贝就能完成整个操作。

而内核线程不存在用户栈,其所有运行操作都是在内核栈上进行的,因此在发起fork调用之后,fork调用所在的栈帧不是位于内核栈的底部。由于fork返回后,计算机需要执行内核栈中已有栈帧的内容,因此我们需要拷贝内核栈。

必须重写子进程的栈帧

看了上面之后,可能很多人就会觉得,那不就是直接拷贝内核栈,然后子进程返回的时候直接切换到新的内核栈不就好了吗?这就是一个很大的误区。

如果真的是直接拷贝栈,然后换栈的话,就必然会出错。

再回到文章开头的“虚拟地址空间分布”部分讲的,“父子进程的内核栈的虚拟地址是不同的”。这句话非常重要。内核栈一般是从slab分配器中分配得来的一块内存地址,而且我们也不能仿照对用户进程的操作那样,将每个内核线程的内核栈映射到相同的地址处(这显然是不可行的)。

父子进程的内核栈的虚拟地址的不同,使得我们必须重写栈帧中的内容。这是为什么呢?首先我们需要理解栈帧的结构:

 当发生函数调用时,处理器会把当前当前函数的返回地址、栈基址寄存器的值压入栈中。返回地址指的是,被调用的函数返回时,将会从哪个位置开始执行。栈基址寄存器值则指的是当前栈帧的基地址。注意,不是内核栈的基地址,这是很多人的一个误区。

每个栈帧的大小是不相同的,处理器是通过这个值来区分不同的栈帧的。当要弹出一个栈帧时,处理器把这个值赋值给栈指针寄存器,这样就找到了上一个栈帧的起始地址。同样的,上一个栈帧的起始地址部分存的值,就是再上一个栈帧的起始的值。

明白了处理器是如何在栈帧之间跳转之后,我们就能明白为什么必须重写内核栈的栈帧了:直接拷贝内核栈后,新的内核栈中的每个栈帧内的“栈基址寄存器值”的内容仍然是父进程的内核栈的地址。因此我们需要重写这个值,让它指向新的内核栈中的对应地址,这样才是正确的。

重写的方法不难,但是有点绕口:

计算子线程栈帧中某个位置A栈基址寄存器值B相对于父线程的栈底的偏移量delta,然后使用子线程的栈底的地址C减去delta,得到子线程的该栈帧中的栈基址寄存器值D,并将D填写到位置A中。

然后,将D赋值给A,重复上述过程,直到子线程中的所有的栈基址寄存器值被重写。

最后,把子线程的fork()栈帧中的栈指针进行重写,子线程的内核栈就处理完成了。剩余的步骤就和普通的fork没有区别了。

重写的部分,比较拗口,因此在这里放对应的代码,帮助理解:

代码的对应链接在这里:DragonOS/process.c at aa7dc4daa5e7f1cc165a9985773e2d2cb23a7281 · fslongjin/DragonOS · GitHub


/*** @brief 重写内核栈中的rbp地址** @param new_regs 子进程的reg* @param new_pcb 子进程的pcb* @return int*/
static int process_rewrite_rbp(struct pt_regs *new_regs, struct process_control_block *new_pcb)
{uint64_t new_top = ((uint64_t)new_pcb) + STACK_SIZE;uint64_t old_top = (uint64_t)(current_pcb) + STACK_SIZE;uint64_t *rbp = &new_regs->rbp;uint64_t *tmp = rbp;// 超出内核栈范围if ((uint64_t)*rbp >= old_top || (uint64_t)*rbp < (old_top - STACK_SIZE))return 0;while (1){// 计算deltauint64_t delta = old_top - *rbp;// 计算新的rbp值uint64_t newVal = new_top - delta;// 新的值不合法if (unlikely((uint64_t)newVal >= new_top || (uint64_t)newVal < (new_top - STACK_SIZE)))break;// 将新的值写入对应位置*rbp = newVal;// 跳转栈帧rbp = (uint64_t *)*rbp;}// 设置内核态fork返回到enter_syscall_int()函数内的时候,rsp寄存器的值new_regs->rsp = new_top - (old_top - new_regs->rsp);return 0;
}

小结

小结一下,内核线程由于其在fork返回之后,仍然使用内核栈,而父子线程的内核栈的地址不同,导致拷贝栈帧后,需要重写子进程内核栈中每个栈帧内保存的栈基址寄存器值,使其能够正常运行。

用户进程/内核进程的fork不需要这样操作的原因则是,他们在fork返回后,内核栈是空的。并且,平时运行的时候,具有独立的用户地址空间,运行时的用户栈都被映射到了相同的虚拟地址处,因此不需要重写也能正常运行。

欢迎加入DragonOS的开发

我发起了DragonOS操作系统项目,目前还处于起步阶段,欢迎感兴趣的朋友们加入!

项目官网:http://DragonOS.orgicon-default.png?t=M666http://dragonos.org/

GitHub地址:GitHub - fslongjin/DragonOS: 一个64位的操作系统。An x86_64 operating system.一个64位的操作系统。An x86_64 operating system. Contribute to fslongjin/DragonOS development by creating an account on GitHub.https://github.com/fslongjin/DragonOS

开发交流群:115763565

转载请注明来源:内核线程的fork与普通的fork的区别 | | 龙进的博客

欢迎关注我的公众号“灯珑”,让我们一起了解更多的事物~

http://www.hkea.cn/news/55185/

相关文章:

  • 增值税怎么算免费seo快速排名系统
  • 响应式电商网站制作全网
  • 国内b2b网站a片长春做网站推广的公司
  • 网页制作视频的网站建设引擎优化seo怎么做
  • 吉林省建设厅证件查询网站今日热搜
  • 做熟食的网站美食网站搜索引擎推广方案案例
  • 企业模板网站推广优化平台
  • 赣州做网站的网站优化技术
  • 设计网站大全网公司推广咨询
  • 北京网站建设价格上海关键词排名优化公司
  • 浙江华临建设集团有限公司网站seo优化网站词
  • 服装网站建设规划书范文免费的行情网站
  • 合肥企业自助建站seo课程培训班
  • 企业网站建设总结什么软件可以免费引流
  • 个人博客网站如何做SEO雅诗兰黛网络营销策划书
  • 唐山自助建站软件seo软件优化工具软件
  • 推广电子商务网站的案例网站推广策划书模板
  • 前端外包网站网站优化快速排名软件
  • 凡客做网站cba最新消息
  • 郑州做网站好的公搜索引擎优化好做吗
  • 网站 预算白度
  • 中国电商建站程序信息推广
  • 网站开发教程 布局优化技术
  • 做外贸网站需要请外贸文员吗网站seo诊断分析和优化方案
  • 百度网站怎么做的赚钱吗seo中文含义
  • 做网站界面的软件互联网培训
  • 电子商务网站建设与维护李建忠高级搜索引擎技巧
  • 做地产网站全网搜索软件
  • 网站开发培训班百度网站推广关键词怎么查
  • 东莞市做网站公司seo怎样