深度解析Linux内核中fork工作原理和实现

news2024/11/24 12:10:40

      Linux内核中的fork()系统调用是用来创建新进程的核心机制。它的主要工作是为新创建的子进程复制当前进程(父进程)的数据结构和内存空间,从而产生一个几乎完全相同的副本。fork()的实现涉及到操作系统内核中许多重要部分的交互和协作,过程比较复杂。

fork()的基本原理

      当一个进程调用fork()时,内核会为新创建的子进程分配必要的资源,如进程控制块(task_struct)、内存空间等。然后,内核会将当前进程的数据(代码段、数据段、堆、栈等)复制到新进程中,使得父子进程之间存在相同的内存映像。在复制结束后,内核会为子进程创建新的独立执行环境,并决定父子进程谁先获得CPU执行权。

需要注意的是,为了提高效率,Linux采用了写时复制(Copy-on-Write,COW)技术。真正的复制工作并不是在fork()时进行,而是延迟到父子进程中有一方第一次试图修改某个内存页时才执行。这个技术避免了大量不必要的数据复制,从而提高了fork()的性能。

进程的关键数据结构

      理解fork()的实现,需要先了解Linux进程相关的重要数据结构,下图描述的是进程相关的主要数据结构。

图 1  Linux进程相关数据结构图

  • - 进程描述符task_struct:每个进程都在内核中有一个对应的task_struct结构体,它记录了该进程的所有相关信息,如进程id、状态、内存映射区域、文件描述符表等。
  • - 进程内存管理描述符mm_struct: 管理每个进程的虚拟内存和物理内存。
  • - 虚拟内存描述符vm_area_struct:描述一个进程的虚拟内存区域,包括起始和结束地址、访问权限、映射的物理页框号等信息。

fork()的实现过程

Linux内核中fork()系统调用的实现过程具体如下。

  • 进入内核态

当一个进程在用户态调用fork()时,会通过软件中断(如int 0x80或sysenter指令)进入内核态,进入内核的sys_fork()系统调用处理函数。

  • 获取新进程ID(PID)和创建进程描述符task_struct

内核会先获取一个可用的PID,作为新创建的子进程的进程ID。接下来,内核会调用copy_process()函数,为子进程分配和初始化一个新的进程描述符task_struct。copy_process()主要完成以下工作:

- 为task_struct分配内核内存

- 从父进程的task_struct复制大部分内容,包括文件系统相关数据(如打开的文件描述符表)、信号处理函数表、命名空间、进程状态等

- 设置新进程的状态为TASK_UNINTERRUPTIBLE(不可中断睡眠状态)

- 为新进程分配一个独立的内核栈

- 初始化计时器、信号等数据结构

  • 复制虚拟内存映射区域vm_area_struct

在copy_process()中,会调用dup_mmap()函数来复制父进程的内存映射区域。dup_mmap()会遍历父进程的所有vm_area_struct,并为子进程创建相应的内存映射区域,但这时只是简单地让父子进程共享同一组页表项,实际的物理内存页还未复制。

  • 写时复制(Copy-on-Write)设置

在复制完vm_area_struct后,dup_mmap()会调用pud_mkwrite等函数,将父子进程共享的所有页表项都标记为只读(设置页表项的权限位为非可写)。这是为了启用写时复制机制,当父子进程中有一方试图写入共享的内存页时,CPU会触发页保护异常,从而引发内核的异常处理程序执行写时复制操作。

  • 信号处理程序设置

在copy_process()中,会复制父进程的信号处理程序表,确保子进程也能正确响应不同的信号。另外,还会为子进程设置SIGCHLD信号的默认处理程序,以便父进程能够捕获子进程的结束信号。

  • 内核线程设置

如果新创建的进程是一个内核线程,copy_process()会进行一些额外的设置,如禁止内核线程加载执行用户空间代码、禁止访问用户态内存等。

  • 调度策略设置

copy_process()会复制父进程的调度策略、优先级等相关信息,并为子进程分配新的运行时统计数据结构,用于CPU调度。

  • 进程链表挂载

新创建的子进程会被加入相应的进程链表中,如任务队列、反馈优先级链表等,以便内核进行进程调度和管理。

  • 写时复制异常处理

在完成上述所有设置后,进入copy_process()的最后阶段。此时,内核会设置写时复制异常处理程序,以响应子进程对共享内存区域的写操作而发生的页保护异常。

写时复制异常处理程序do_cow_fault()的主要工作是:

- 为发生写操作的内存页分配新的内核页框(物理内存页)

- 将原有的内存页内容复制到新的页框中

- 修改相应的页表项,使其指向新分配的物理内存页框,并设置为可写

- 在原有的物理内存页上设置写保护,避免不必要的复制

通过写时复制机制,父子进程最终会拥有各自独立的物理内存副本,从而可以进行自身的数据写入而不会相互影响。

  • 执行切换和系统调用返回

      最后,内核会决定父进程和子进程的执行顺序。一般情况下,内核会先让子进程执行,因为子进程的执行状态被设置为TASK_UNINTERRUPTIBLE。在子进程执行时,会执行一些额外的初始化工作,如清理上下文、设置执行计数器等。

fork()系统调用在父子进程中的返回值不同:

- 在子进程中,fork()返回0

- 在父进程中,fork()返回新创建子进程的PID

通过这种方式,父子进程可以区分不同的执行路径。

结论

      Linux内核中fork()系统调用的实现过程十分复杂,需要内核中多个子系统的通力合作,包括进程管理、内存管理、CPU调度等。写时复制(COW)技术的应用是fork()实现中的一大亮点,极大地提高了系统性能。在现代操作系统中,fork()作为创建新进程的核心机制,对于理解内核原理有着非常重要的意义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1797712.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ThinkPHP发邮件配置教程?群发功能安全吗?

ThinkPHP发邮件的注意事项?如何优化邮件发送的性能? 无论是用户注册、密码重置还是消息提醒,发送邮件都是一个常见的需求。AokSend将详细介绍如何在ThinkPHP框架中配置和发送邮件,帮助开发者轻松实现邮件功能。 ThinkPHP发邮件&…

【全开源】同城招聘SAAS信息前程无忧直聘达小程序

招聘SAAS:数字化转型中的招聘新助力 基于ThinkPHP和原生微信小程序开发的招聘平台系统,包含微信小程序求职者端、微信小程序企业招聘端、PC企业招聘端、PC管理平台端​ 🌟 一、招聘SAAS简介 在人力资源领域,数字化转型已成为不…

铁塔、烟囱建筑倾斜监测的倾角仪的分类以及工作原理

前言 倾角传感器是一种用于测量物体相对平面倾斜角度的仪器。倾角传感器又称作倾角仪、倾斜仪、测斜仪、水平仪、倾角计,经常用于物体的水平角度变化的精确测量,用它可测量被测平面相对于水平位置的倾斜度、两部件相互平行度和垂直度;已成为桥…

南京代理记账公司,为您提供专业服务,助力企业发展

在当今社会,企业的经营情况需要通过各种方式来进行监督和管理,记账是企业日常运营中不可或缺的一部分,对于非专业的财务人员来说,如何进行正确、有效的记账呢?这就需要找一家专业的代理记账公司来帮助您。 南京代理记账…

工程力学 - 课程导论

工程力学是工程学科中的核心基础课程,专注于研究物体在外力作用下的运动规律和受力情况。它涵盖了静力学、运动学、动力学和材料力学等关键领域,为工程结构的安全性、稳定性和功能性提供理论支撑。通过理论分析、实验测定和计算机模拟等方法,…

Hikyuu教程:简单波动率(EMV)择时交易系统的构建与实现

今日,我们将探讨如何借助 hikyuu 框架实现简单波动指标 EMV 的择时系统。与以往稍有不同的是,本次我们将采用策略部件仓库的写法来完成示例代码,以便大家进一步了解和熟悉仓库的使用方法。 什么是简易波动指标(EMV) …

[ubuntu]docker 卡登录 You‘ve been signed out

Setting->Resources->Proxies设置当前使用的proxies即可 参考:https://github.com/docker/for-mac/issues/7160#issuecomment-2061040813

香蕉派BPI-F3 进迭时空(SpacemiT)K1RISC-V开发板软件下载链接

香蕉派BPI-F3是一款工业级 8核RISC-V开源硬件开发板,它采用进迭时空(SpacemiT) K1 8核RISC-V芯片设计,CPU集成2.0 TOPs AI计算能力。4G DDR和16G eMMC。2个GbE以太网接口,4个USB 3.0和PCIe M.2接口,支持HDM…

Sylar C++高性能服务器学习记录21 【ByteArray模块-知识储备篇】

早在19年5月就在某站上看到sylar的视频了,一直认为这是一个非常不错的视频。 由于本人一直是自学编程,基础不扎实,也没有任何人的督促,没能坚持下去。 每每想起倍感惋惜,遂提笔再续前缘。 为了能更好的看懂sylar&…

HTML静态网页成品作业(HTML+CSS)—— 金宝贝儿童教育机构介绍网页(2个页面)

🎉不定期分享源码,关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 🏷️本套采用HTMLCSS,未使用Javacsript代码,共有2个页面。 二、作品演示 三、代…

社交创新:Facebook的技术与产品发展

在当今数字化时代,社交网络已经渗透到我们生活的方方面面,成为了人们日常交流、信息获取和社交互动的主要方式。而在这个众多社交平台中,Facebook作为其中的佼佼者,其技术与产品的发展历程也是一个社交创新的缩影。本文将探索Face…

从写简历到谈薪资的最全教程

从写简历到谈薪资的最全教程 目录简历注意事项举个例子写简历投递简历也有技巧模拟面试的重要性面试经验怎么刷不断迭代达越来越强斗智斗勇谈薪资拿到offer就结束了吗?我能给你的帮助 目录 大家好,我是一名普通本科毕业的学生,工作数年&#…

git根据历史某次提交创建新分支

有时候项目在做版本管理的时候,忘记了创建某次版本的分支,而直接在主分支上进行开发了,这个时候,想要对某次提交单独拉出来一个版本分支,就需要用到这个功能: git checkout -b 新分支名 某次提交的id 找到…

最新 Navicat Data Modeler 4 | 产品介绍

在过去的几周里,我们已经介绍了 Navicat 版本 17,现在我们来把注意力转移到另外两个值得关注的产品上,即 Navicat Data Modeler 和 Navicat BI(之前称为 Navicat Chart Creator)。今天的博客将介绍 Navicat Data Model…

VS2022+Qt雕刻机单片机马达串口上位机控制系统

程序示例精选 VS2022Qt雕刻机单片机马达串口上位机控制系统 如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助! 前言 这篇博客针对《VS2022Qt雕刻机单片机马达串口上位机控制系统》编写代码,代码整洁&a…

pypi 发布自己的包

注册pypi个人用户 网址:https://pypi.org 目录结构dingtalk_utils 必须-pkgs- __init__.py .gitignore LICENSE 必须 README.md 必须 requirements.txt setup.py 必须安装依赖 pip install setuptools wheel安装上传工具 pip install twinesetup.py i…

深度学习(三)

5.Functional API 搭建神经网络模型 5.1利用Functional API编写宽深神经网络模型进行手写数字识别 import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom sklearn.datasets import load_irisfrom sklearn.model_selection import train_test_splitfrom…

蒋耀锴:剑桥毕业,硅谷敲代码8年,回国创业做低代码

这是《开发者说》的第10期,本期我们邀请的开发者是蒋耀锴,曾在意大利、英国、美国读书,专长高性能计算、高容错分布式系统与软件工程,毕业后在硅谷的Medallia写了8年代码,19年回国创业做低代码,喜欢半夜里一…

常见Rabbitmq面试题及答案总结

1、 什么是 rabbitmq 釆用AMQP高级消息队列协议的一种消息队列技术撮大的特点就是消费并不需要 确保提供方存在,实现了服务之间的高度解耦 2、 为什么要使rabbitmq (1) 在分布式系统下具备异步,削峰,负载均衡等一系列高级功能&…

汽车MCU虚拟化--对中断虚拟化的思考(2)

目录 1.引入 2.TC4xx如何实现中断虚拟化 3.小结 1.引入 其实不管内核怎么变,针对中断虚拟化无非就是上面两种,要么透传给VM,要么由Hypervisor统一分发。汽车MCU虚拟化--对中断虚拟化的思考(1)-CSDN博客 那么,作为车规MCU龙头…