fork,execve,_exit从第一个程序到所有程序

操作系统启动后到底做了什么

  • CPU Reset → Firmware → Loader → Kernel _start() → 第一个程序 /bin/init → 程序 (状态机) 执行 + 系统调用

  • 操作系统会加载 “第一个程序”

    • 寻找启动程序代码

    • if (!try_to_run_init_process("/sbin/init") ||
      	    !try_to_run_init_process("/etc/init") ||
      	    !try_to_run_init_process("/bin/init") ||
      	    !try_to_run_init_process("/bin/sh"))
      		return 0;
      
      	panic("No working init found.  Try passing init= option to kernel. "
      	      "See Linux Documentation/admin-guide/init.rst for guidance.");
      
    • linux中的pstree的systemd的来历

    • 在这里插入图片描述

fork()

  • 操作系统:状态机的管理者
    • C 程序 = 状态机
      • 初始状态:main(argc, argv)
      • 程序可以直接在处理器上执行
    • 虚拟化:操作系统在物理内存中保存多个状态机
      • 通过虚拟内存实现每次 “拿出来一个执行”
      • 中断后进入操作系统代码,“换一个执行”
  • int fork();
    • 立即复制状态机 (完整的内存)
    • 新创建进程返回 0
    • 执行 fork 的进程返回子进程的进程号
  • 因为状态机是复制的,因此总能找到 “父子关系”
    • 因此有了进程树 (pstree)
    • 在这里插入图片描述

execve()

  • 状态机管理:替换状态机
    • int execve(const char *filename, char * const argv, char * const envp);
      • 执行名为 filename 的程序
      • 允许对新状态机设置参数 argv (v) 和环境变量 envp (e)
      • 刚好对应了 main() 的参数!
  • 环境变量:“应用程序执行的环境”
    • 使用env命令查看
      • PATH: 可执行文件搜索路径
      • PWD: 当前路径
      • HOME: home 目录
      • DISPLAY: 图形输出
      • PS1: shell 的提示符
    • export: 告诉 shell 在创建子进程时设置环境变量
  • _exit()
    • 状态机管理:终止状态机
      • void _exit(int status)
        • 销毁当前状态机,并允许有一个返回值
        • 子进程终止会通知父进程
    • 结束程序执行的三种方法
      • exit(0) - stdlib.h 中声明的 libc 函数
        • 会调用 atexit(清理空间,安全退出)
      • _exit(0) - glibc 的 syscall wrapper
        • 执行 “exit_group” 系统调用终止整个进程 (所有线程)
        • 不会调用 atexit
      • syscall(SYS_exit, 0)
        • 执行 “exit” 系统调用终止当前线程
        • 不会调用 atexit
  • 程序的创建执行和销毁过程
    系统初始化的程序,通常是 init(在一些现代系统如 Fedora、Ubuntu 上通常是 systemd),负责进一步初始化操作系统并启动其他服务或进程。下面,我们将详细探讨在操作系统启动第一个程序后,如何使用 fork, execve, _exit 来创建、执行和销毁程序的过程。

程序的创建、执行和销毁

  1. 初始化和启动首个进程

    • 操作系统通过加载并执行 init 程序(或者在一些系统中是 systemd)开始。这个程序成为系统中的第一个进程(通常是进程号为1)。
  2. 进程的创建 (使用 fork)

    • 当系统需要创建一个新的进程时,init(或任何正在运行的进程)会调用 fork() 系统调用。fork() 创建一个与父进程几乎完全相同的子进程,拥有相同的内存映像和运行状态,但有一个新的唯一进程标识符。
    • 父进程中 fork() 返回新创建的子进程的进程ID,而在子进程中 fork() 返回0。
  3. 进程的执行 (使用 execve)

    • 通常在 fork() 之后,子进程需要运行与父进程不同的代码。为此,子进程会调用 execve() 系统调用,这个调用加载一个新的程序到当前进程的地址空间,并开始执行这个程序,从其 main 函数开始。
    • execve() 需要指定程序的路径、传递给程序的参数列表(argv),以及环境变量列表(envp)。这意味着执行后,子进程的原有代码和数据将被新程序替换。
  4. 进程的终止 (使用 _exit)

    • 当程序执行完成后,它可以通过调用 _exit() 系统调用来终止。这个调用立即结束进程的执行,并将一个状态码返回给操作系统,这个状态码可以被父进程通过 wait() 系列的调用来检索。
    • 使用 _exit() 而不是标准的 exit() 函数,因为后者还会执行标准库注册的各种清理函数(如由 atexit() 注册的函数),这在某些情况下可能不是必需或期望的。

实例:简单的 shell

假设 init 系统已经启动,并且我们需要从一个简化的 shell 启动一个程序,如 ls 命令。以下是这个过程的概述:

  1. Shell 进程调用 fork(),创建一个子进程。
  2. 子进程使用 execve() 调用来加载并运行 ls 命令。
  3. ls 命令执行完成后,子进程调用 _exit() 来结束执行,返回执行结果状态。
  4. Shell 进程使用 wait() 等待子进程结束,并获取其终止状态。

这样,我们就看到了一个完整的程序生命周期:创建、执行和终止,都是通过操作系统提供的系统调用来管理的。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

3D人体展示仪

网址 https://3dbodyvisualizer.com/ 可以根据身高体重之类的在线生成人体的3D模型,感兴趣的可以试试

(图论)最短路问题合集(包含C,C++,Java,Python,Go)

不存在负权边: 1.朴素dijkstra算法 原题: 思路:(依然是贪心的思想) 1.初始化距离:dis[1]0,dis[i]INF(正无穷) 2.循环n次: 找到当前不在s中的dis最小的点&…

three.js 效果细节提升

1. three.js 效果细节提升 加载模型时,给模型设置接受阴影,反射阴影 gltfLoader.load("./model/court-transformed.glb", (gltf) > {gltf.scene.traverse(child > {if (child.isMesh) {child.castShadow true; // 设置阴影可以投射阴…

c++笔记——概述运算符重载——解析运算符重载的难点

前言:运算符重载是面向对象的一个重要的知识点。我们都知道内置类型可以进行一般的运算符的运算。但是如果是一个自定义类型, 这些运算符就无法使用了。那么为了解决这个问题, 我们的祖师爷就在c中添加了运算符重载的概念。 本篇主要通过实例的实现来讲述…

【时序大模型总结】学习记录(1)

1.TimeGPT-1 思路:在来自不同领域的大量数据上训练模型,然后对未见过的数据产生零样本的推断。 作者对TimeGPT进行了超过1000亿个数据点的训练,这些数据点都来自开源的时间序列数据。该数据集涵盖了广泛的领域,从金融、经济和天气…

YOLOv8原理解析[目标检测理论篇]

接下来是我最想要分享的内容,梳理了YOLOv8预测的整个流程,以及训练的整个流程。 关于YOLOv8的主干网络在YOLOv8网络结构介绍-CSDN博客介绍了,为了更好地介绍本章内容,还是把YOLOv8网络结构图放在这里,方便查看。 1.YOL…

AI讲师大模型培训老师叶梓:大模型应用的方向探讨

大模型应用的关键方向及其落地案例可以从多个角度进行探讨,结合最新的研究和实际应用案例,我们可以更全面地理解这些技术如何推动社会和经济的发展。 Agent(数字代理): 方向说明:Agent方向的AI技术旨在创建能够独立执行任务、做出…

对于SOMP算法的测试

刚开始只上传了SOMP算法的代码,并没有过多介绍。 所以本篇文章对SOMP算法用法进行一个介绍 SOMP算法代码 function [X_hat] MMV_SOMP(Y, PHI, s)% SOMP:同时正交匹配追踪 simultaneous orthogonal matching pursuit% 论文:J. Determe, J. Lo…

若依plus 某些接口(用户信息等)响应突然变慢

今天一大早起来发现我的接口突然响应变慢了! 就什么都没动,啥也没改,但是一些接口又很快。 百度了很多,都说叫我改sql查询方式,又怀疑是过滤器的问题,很遗憾都不是! 一个响应40秒!…

[译文] 恶意代码分析:1.您记事本中的内容是什么?受感染的文本编辑器notepad++

这是作者新开的一个专栏,主要翻译国外知名安全厂商的技术报告和安全技术,了解它们的前沿技术,学习它们威胁溯源和恶意代码分析的方法,希望对您有所帮助。当然,由于作者英语有限,会借助LLM进行校验和润色&am…

IOT-9608I-L ADC端口的使用(连续采样ADC值)

目录 概述 1 硬件介绍 1.1 认识硬件 1.2 引脚信号定义 2 软件功能实现 2.1 查看iio:device0下的接口信息 2.2 实现连续采样ADC 2.2.1 功能描述 2.2.2 代码实现 2.2.3 详细代码 3 测试 概述 本文主要讲述IOT-9608I-L ADC端口的使用方便,其内容包括板卡上的…

密室逃脱游戏-第12届蓝桥杯省赛Python真题精选

[导读]:超平老师的Scratch蓝桥杯真题解读系列在推出之后,受到了广大老师和家长的好评,非常感谢各位的认可和厚爱。作为回馈,超平老师计划推出《Python蓝桥杯真题解析100讲》,这是解读系列的第58讲。 密室逃脱游戏&…

2024年第九届数维杯数学建模B题思路分享

文章目录 1 赛题思路2 比赛日期和时间3 竞赛信息4 建模常见问题类型4.1 分类问题4.2 优化问题4.3 预测问题4.4 评价问题 5 建模资料 1 赛题思路 (赛题出来以后第一时间在CSDN分享) https://blog.csdn.net/dc_sinor?typeblog 2 比赛日期和时间 报名截止时间:2024…

分布式模式让业务更高效、更安全、更稳定

​🌈 个人主页:danci_ 🔥 系列专栏:《设计模式》 💪🏻 制定明确可量化的目标,坚持默默的做事。 🚀 转载自热榜文章🔥:探索设计模式的魅力:分布式模…

Ubuntu添加网络映射路径

参考资料 linux挂在阿里云盘(webdav协议)给服务器扩容、备份数据等_davfs2-CSDN博客 Linux将WebDAV为本地磁盘 - 夏日冰菓 (lincloud.pro) systemd系统开机运行rc.local_rc-local.service: failed to execute command: exec -CSDN博客 系统版本&#xff…

word格式技巧

文章目录 论文格式技巧论文交叉引用怎么弄论文的页码怎么弄 论文格式技巧 论文交叉引用怎么弄 1.取消文献原有的编号 2.定义新编号 3.具体编号设置 4.在引用的地方插入,具体引用选项卡–>交叉引用–>选择后插入 2. 4. 论文的页码怎么弄 假设我们有这样一…

List的两种实现

前置知识: 数组 baseAddress:数组的首地址 dataTypeSize:数组中元素类型的大小,如int为4字节 为什么数组索引从0开始,假如从1开始不行吗? 在根据数组索引获取元素的时候,会用索引和寻址公式来计…

HBase 读写流程

HBase 读写流程 1. 读流程 Client先访问zookeeper,从zookeeper获取meta region的位置从meta region中读取meta表中的数据,meta中存储了用户表的region信息;根据namespace、表名和rowkey在meta表中找到对应的region信息;找到这个r…

[Kotlin]创建一个私有包并使用

1.创建Kotlin项目 创建项目: 在Android Studio或其他IDE中选择“Create New Project”。选择Kotlin和Gradle作为项目类型和构建系统。指定项目名称和位置,完成设置。 添加依赖: 如果你的库需要额外的依赖,可以在 build.gradle (Module: app…

文件各种上传,离不开的表单 [html5]

作为程序员的我们,经常会要用到文件的上传和下载功能。到了需要用的时候,各种查资料。有木有..有木有...。为了方便下次使用,这里来做个总结和备忘。 利用表单实现文件上传 最原始、最简单、最粗暴的文件上传。 前端代码: //方…