当前位置:首页 > 黑客服务 > 正文内容

程序编程代码大全(c代码检查工具)

访客3年前 (2021-12-30)黑客服务770

前面两节简要地从C语言源代码层面讨论了Linux系统中进程的基本概念,我们知道了Linux内核如何描述和记录进程的资源,以及进程的五种基本状态和进程的家族树。事实上,就进程管理而言,Linux还是有一些独特之处的。

Linux 是如何创建进程的呢?

Linux 系统中的进程创建

许多操作系统都提供了专门的进程产生机制,比较典型的过程是:首先在内存新的地址空间里创建进程,然后读取可执行程序,装载到内存中执行。

Linux 系统创建线程并未使用上述经典过程,而是将创建过程拆分到两组独立的函数中执行:fork() 函数和 exec() 函数族。

基本流程是这样的:首先,fork() 函数拷贝当前进程创建子进程。产生的子进程与父进程的区别仅在与 PID 与 PPID 以及某些资源和统计量,例如挂起的信号等。准备好进程运行的地址空间后,exec() 函数族负责读取可执行程序,并将其加载到相应的位置开始执行。

fork() 函数和 exec() 函数族

Linux 系统创建进程使用的这两组函数效果与其他操作系统的经典进程创建方式效果是相似的,可能有读者会觉得这么做会让进程创建过于繁琐,其实不是的,Linux 这么做的其中一个原因是为了提高代码的复用率,这得益于 Linux 高度概括的抽象,无需再额外设计一套机制用于创建进程。

“写时拷贝”

早期 Linux 中的 fork() 函数直接把父进程的所有资源赋值给创建出的子进程,这样的机制自然是简单的,但是效率却比较低下。

原因是显而易见的:子进程并不一定要使用父进程的资源,或者子进程可能仅需以只读的方式访问父进程的资源,这时“拷贝一份资源”就纯属多余的开销了。

针对这样的问题,Linux 后续版本中的 fork() 函数开始采用“写时拷贝”机制。写时拷贝技术可以将拷贝需求延迟,甚至免除拷贝,减小开销。

“写时拷贝”机制

具体来说就是,Linux 在调用 fork() 创建子进程时,并不着急拷贝整个进程地址空间,而是暂时让父子进程以只读的方式共享同一个拷贝。拷贝动作只在子进程需要写入时才会发生,以确保各个进程有自己独立的内存空间。

如果子进程用不到或者只需要读取共享空间数据,那么拷贝动作就被省去了,Linux 就减小了开销。例如,系统调用 fork() 后立即调用 exec(),此时 exec() 会加载新的映像覆盖 fork() 的地址空间,拷贝动作完全可以省去。

事实上,fork() 函数的实际开销就是复制父进程的页表以及给子进程创建唯一的进程描述符。在大多数情况下,Linux 创建进程后都会马上运行新的可执行程序,因此“写时拷贝”机制可以避免相当多的数据拷贝。创建进程速度快是 Linux 系统的一个特征,因此“写时拷贝”是一种相当重要的优化。

创建进程时,内存地址空间里常常包含数十 MB 的数据,如果每创建一次进程,就拷贝一次数据,开销显然是非常大的。

fork() 函数

Linux 中的 fork() 函数其实是基于 clone() 实现的,clone() 函数可以通过一系列参数标志指定父子进程需要共享的资源,在 Linux 中输入 man 命令可以查看 clone() 函数的C语言原型:

clone() 函数的C语言原型

以及相关的参数标志:

相关的参数标志

在Linux中,fork() 函数最终调用了 do_fork() 函数,它的C语言代码如下,请看(do_fork() 函数的C语言代码比较长,下面面只列出了一部分):

do_fork() 函数的C语言代码

do_fork() 函数完成了进程创建的大部分工作,从相关的C语言源代码可以看出,它调用了 copy_process() 函数,copy_process() 函数的C语言源代码如下,请看:

copy_process() 函数的C语言源代码

copy_process() 函数的代码也是比较长的,在我手上的Linux系统中,达到了近 400 行,不过代码的整体逻辑是清晰的:

(1)copy_process() 函数首先检查了一些标志位,接着调用 dup_task_struct() 函数为新进程创建内核栈,以及上一节提到的 thread_info 和 task_struct 结构:

调用 dup_task_struct() 函数为新进程创建内核栈

创建后,接下来的 arch_dup_task_struct() 函数会将 orig 结构拷贝给新创建的结构,查看相关C语言代码,这一过程是清晰的:

拷贝给新创建的结构

此时子进程和父进程的描述符是完全相同的。

(2)接下来,需要检查一些标志位和统计信息,相关的C语言代码如下,请看:

检查一些标志位和统计信息

(3)将一些统计量清零,以及初始化一些区别成员,此时虽然新进程的 task_struct 结构体大多成员未被修改,但是父子进程已经有所区别。这一过程的相关C语言代码片段如下,请看:

将一些统计量清零,以及初始化一些区别成员

(4)将新创建的子进程状态设置为 TASK_UNINTERRUUPTIBLE,确保其暂时不会被投入运行,这一过程的C语言代码相对简单。

(5)调用 alloc_pid() 函数为新进程分配一个独一无二的 pid,相关C语言代码如下,请看:

为新进程分配一个独一无二的 pid

(6)根据 clone() 函数的参数标志位,拷贝或共享已经打开的文件、文件系统、信号处理函数、进程地址空间等资源,例如下面这段C语言代码:

拷贝或共享已经打开的资源

(7)将为新进程创建的 task_struct 结构体的指针返回给调用者,也即 do_fork() 函数。此时新创建的进程还没有被投入运行。

现在回到 do_fork() 函数。如果调用 clone() 函数时,没有传递 CLONE_STOPPED 参数,新创建的进程将被唤醒,并投入运行,这一过程的C语言代码如下:

唤醒,并投入运行

到这里,一个新的进程就被 Linux 创建完毕了。

Linux 内核有意让新创建的子进程先运行,因为子进程常常会立即调用 exec() 函数加载新的程序到内存中运行,这样就避免了写时拷贝的额外开销。如果父进程首先执行,显然极有可能开始往地址空间写入操作,导致拷贝动作发生。

小结

本节详细的从C语言代码层面分析了Linux内核创建进程的过程,可见,即使是复杂的操作系统代码,也是通过一系列基本C语言语法和函数实现的。那么,Linux 是如何创建线程的呢?之前我们曾经提到,Linux 系统并不特别区分进程和线程,线程其实是一种特殊的进程,Linux 是如何实现这一“特殊”过程的呢?限于篇幅,下一节再说了,敬请关注。

点个赞再走吧

欢迎在评论区一起讨论,质疑。文章都是手打原创,每天最浅显的介绍C语言、linux等嵌入式开发,喜欢我的文章就关注一波吧,可以看到最新更新和之前的文章哦。

扫描二维码推送至手机访问。

版权声明:本文由黑客接单发布,如需转载请注明出处。

本文链接:https://therlest.com/30655.html

分享给朋友:

“程序编程代码大全(c代码检查工具)” 的相关文章

约茶app约茶APP

最新约茶app都是哪些?整理了30本这篇文章主要介绍了约茶app,包括约茶app ios下载,下面小编整理了约茶app的图文教程,看看约茶app苹果版详细步骤吧! 觉得网上的一些答 据新快网2021年10月20日03:31:27的新闻报道,微博网友@R卜傲晴 爆料。 平安夜来临之际,事件,在网上...

身份证信息被黑客盗取(黑客能把手机内身份证信息盗取吗)

一、身份证信息被黑客盗取(黑客能把手机内身份证信息盗取吗)方法总结 1、黑客通过手身份姓名能否窃取别人银行卡里。朋友你好,这个问题不是这样理解的的,黑客是通过你的这些信息,破易你的银行卡号支付密码来盗取你的财物的,一般你只要不乱点链接,不轻易在手机。黑客控制了手机,窃取了身份证号码手机号姓名等所有...

铁盖子可以放入高压锅蒸吗?装酱料的铁盖子,外面的涂层有些剥落,好

铁盖子可以放入高压锅蒸吗?装酱料的铁盖子,外面的涂层有些剥落,好 铁盖子可以放入高压锅蒸吗? 装酱料的铁盖子,外面的涂层有些剥落,好象也没锈,可以拿它盖严瓶子入高压锅蒸吗? 绝对不行!既危险又不卫生。盖住的瓶子在高压锅中加热,很容易形成压力差而爆炸;铁在高压锅中的水蒸汽作用下极易变成四氧化三...

中国水产养殖网官网_中国水产价格网

只能告诉你名称了,这个,像南京就要三十几,南京六合沪江水产市场甲鱼价格就应声下落。 1-2两的黄鳝批发价格是25元/斤,19-20元/斤,水产养殖网总浏览量达100万人次,价格在35-40元一斤。按照商品鱼进行销售的话,元旦刚过。 生甲鱼200-500/斤,我这边有一个,水产养殖品,战略合作 现在市...

西安电脑黑客接单_怎么能找入侵蚊香社的黑客

sudo apt install g++-4.4SplashData剖析的这500万被走漏的暗码主要是北美和西欧的用户,成人网站走漏的暗码不包含在剖析陈述中。 支撑(V4增强)所谓0day缝隙的在野运用,一般是进犯活动被捕获时,发现其运用了某些0day缝隙(进犯活动与进犯样本剖析自身也是0day缝隙...

怎样偷偷查他在酒店宾馆的开房登记记录

智能机的出现虽然提高我们的生活质量,但是也存在一些问题。一方面我们可以进行网上购物,聊天等其他休闲活动,另一方面,我们也会担心智能手机内存溢出,所以我们不得不去对手机进行垃圾清除。在清除手机垃圾的同时我们可能会因为一些小的失误,导致微信聊天记录被误删了。那么问题来了:微信聊天记录删除了怎么恢复呢?下...

评论列表

性许时窥
3年前 (2022-05-31)

函数首先检查了一些标志位,接着调用 dup_task_struct() 函数为新进程创建内核栈,以及上一节提到的 thread_info 和 task_struct 结构:调用 dup_task_struct() 函数为新进程创建内核栈创建后,接下来的 arch_dup_t

依疚野の
3年前 (2022-05-31)

建出的子进程,这样的机制自然是简单的,但是效率却比较低下。原因是显而易见的:子进程并不一定要使用父进程的资源,或者子进程可能仅需以只读的方式访问父进程的资源,这时“拷贝一份资源”就纯属多余的开销了。针对这样的问题,Linux 后续版本中的 fork() 函数开始采用“写时拷贝”机制。写时拷贝技术可以

语酌清引
3年前 (2022-05-31)

贝”机制具体来说就是,Linux 在调用 fork() 创建子进程时,并不着急拷贝整个进程地址空间,而是暂时让父子进程以只读的方式共享同一个拷贝。拷贝动作只在子进程需要写入时才会发生,以确保各个进程有自己独立的内存空间。如果子进程用不到或者只需要读取共享空间

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。