免费预览已结束,剩余20页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Linux 的 fork exec wait 函数分析 I 数学与计算机学院 课程设计说明书 课 程 名 称 操作系统原理 课程设计 课 程 代 码 8404061 题 目 Linux的fork exec wait函数的分析 年级 专业 班 学 生 姓 名 学 号 3 开 始 时 间 2010 年 12 月 12 日 完 成 时 间 2011 年 01 月 09 日 课程设计成绩 学习态度及平 时成绩 30 技术水平与实际 能力 20 创新 5 说明书撰写质量 45 总 分 100 指导教师签名 年 月 日 Linux 的 fork exec wait 函数分析 II 目 录 1 引 言 1 1 1 问题的提出 1 1 2 国内外研究的现状 1 1 3 任务与分析 1 2 代码分析结果 1 2 1 数据结构 1 2 1 1 struct task struct 1 2 1 2 task 3 2 1 3 tarray freelist 3 2 1 4 struct linux binprm 3 2 1 5 进程状态 4 2 2 常量和出错信息的意义 4 2 3 调用关系图 4 2 4 各模块 函数的功能及详细框图 4 2 4 1 do fork 模块 4 2 4 2 get pid 模块 8 2 4 3 do execve 模块 10 3 4 4 do exit 模块 14 3 4 5 sys wait4 模块 17 3 总结与体会 20 4 参考文献 20 Linux 的 fork exec wait 函数分析 III Linux 的 fork exec wait 函数分析 1 1 引引 言言 1 1 问题的提出问题的提出 如何有效合理的调用各个进程是每一个操作系统所必需面对的问题 对于数 量庞大的计算机用户来说 越来越多的人使用了 Linux 促进了技术支持和新功 能需求的日益增长 这样一来 越来越多的程序员发现自己对 Linux 内核的内幕 感兴趣 于是 就开始了对 Linux 内核源代码进行剖析 以此来实现对 Linux 操 作系统的基本功能和实现方式有一个全面的了解 才能够适应不同的体系结构是 种类繁多的新设备 正因为如此 Linux 受到越来越多的重视 基于 Linux 的各 种研究开发项目日益增多 所以对 Linux 源代码的研究也就显得非常重要 1 2 国内外研究的现状国内外研究的现状 国外来讲 大型 IT 公司都有比较健全和专业的解决方案 国内做目录服务的软件 公司几乎都没有以这个为主业的 产品主要由政府机关或相关部门采购 国内事业单位 采购国内产品 一是因为便宜 二就是政府倡导的自主知识产权等因素 行业性很强 一般没有特定的通用性产品 大都是项目定制的 研究内容除了与应 用层逻辑密切相关的 其余就是容量 检索速度 并发能力等方面的研究了 1 3 任务与分析任务与分析 本课题的目的是对 Linux 的 fork exec wait 函数代码的分析 学习和掌握多 个操作系统进程的创建 执行 等待 退出的过程 理解进程表示和模态转换 状态 转换 掌握进程上下文切换机制 掌握软中断机制的实现的机理和作用 掌握进程调 度的机理 熟练应用进程相关的系统调用 重点放在进程的创建与结束 进程的调度 与切换 软中断机制 数据结构 函数间调用关系 以及相关的框图 Linux 的 fork exec wait 函数分析 2 2 代码分析结果 2 12 1 数据结构数据结构 2 1 12 1 1 structstruct task structtask struct 进程的内核数据结构是 task struct 结构 它使用两个指针 next task 和 prev task 将各个进程连成一个循环双链表 相应的指针 p opptr p pptr p cptr p ysptr 和 p osptr 来表示进程之间的家族关系 struct task struct 进程描述符 long state 任务的运行状态 1 不可运行 0 可运行 就绪 0 已停止 long counter 任务运行时间计数 递减 滴答数 运行时间片 long priority 运行优先数 任务开始运行时 counter priority 越大运行越长 long signal 信号 是位图 每个比特位代表一种信号 信号值 位偏移值 1 struct sigaction sigaction 32 信号执行属性结构 对应信号将要执行的操作和标 志信息 long blocked 进程信号屏蔽码 对应信号位图 int exit code 任务执行停止的退出码 其父进程会取 unsigned long start code 代码段地址 unsigned long end code 代码长度 字节数 unsigned long end data 代码长度 数据长度 字节数 unsigned long brk 总长度 字节数 unsigned long start stack 堆栈段地址 long pid 进程标识号 进程号 long father 父进程号 long pgrp 父进程组号 long session 会话号 long leader 会话首领 unsigned short uid 用户标识号 用户 id unsigned short euid 有效用户 id unsigned short suid 保存的用户 id unsigned short gid 组标识号 组 id unsigned short egid 有效组 id unsigned short sgid 保存的组 id long alarm 报警定时值 滴答数 long utime 用户态运行时间 滴答数 long stime 系统态运行时间 滴答数 long cutime 子进程用户态运行时间 long cstime 子进程系统态运行时间 long start time 进程开始运行时刻 unsigned short used math 标志 是否使用了协处理器 int tty 进程使用 tty 的子设备号 1 表示没有使用 unsigned short umask 文件创建属性屏蔽位 Linux 的 fork exec wait 函数分析 3 struct m inode pwd 当前工作目录 i 节点结构 struct m inode root 根目录 i 节点结构 struct m inode executable 执行文件 i 节点结构 unsigned long close on exec 执行时关闭文件句柄位图标志 参见 include fcntl h struct file filp NR OPEN 进程使用的文件表结构 struct desc struct ldt 3 本任务的局部表描述符 0 空 1 代码段 cs 2 数据和 堆栈段 ds 本进程的任务状态段信息结构 2 1 22 1 2 tasktask task 定义为指向 struct task struct 结构的指针数组 这个数组的每个项代表系统 中的一个任务 数组的大小是 NR TASKS 它规定了系统中同时可以运行的任务的数 量 extern struct task struct task NR TASKS 2 1 32 1 3 tarray freelisttarray freelist 自由时间片列表 tarray freelist 拥有一个说明 task 数组中自由位置的列表 即当 前没有被使用的空位置 struct task struct tarray freelist 2 1 42 1 4 struct linux binprmstruct linux binprm 内核中为可执行程序的装入定义了一个数据结构 linux binprm 以便将运行一个 可执行文件时所需的信息组织在一起 usr src linux include linux binfmts h struct linux binprm char buf BINPRM BUF SIZE struct page page MAX ARG PAGES struct mm struct mm unsigned long p current top of mem int sh bang struct file file int e uid e gid kernel cap t cap inheritable cap permitted cap effective void security int argc envc char filename Name of binary as seen by procps Linux 的 fork exec wait 函数分析 4 char interp Name of the binary really executed Most of the time same as filename but could be different for binfmt misc script unsigned interp flags unsigned interp data unsigned long loader exec ifdef KERNEL define MAX ARG PAGES 32 linux binprm page 每个参数的最大长度为一个物理页面 所以 linux binprm 中有个页面指针数 组 数组的大小为允许的最大参数个数 MAX ARG PAGES 目前这个常数定义为 32 2 1 52 1 5 进程状态进程状态 TASK RUNNING 运行状态 TASK INTERRUPTIBLE 等待状态可以让其他进程唤醒 TASK UNINTERRUPTIBLE 等待状态但不让其他进程唤醒 TASK ZOMBIE 进程已经结束执行但尚未消亡 TASK STOPPED 进程暂停用其他进程的信号才能唤醒 TASK SWAPPING 被换出的进程 2 22 2 常量和出错信息的意义常量和出错信息的意义 define NR TASKS 64 系统中同时最多任务 进程 数 define HZ 100 定义系统时钟滴答频率 1 百赫兹 每个滴答 10ms define FIRST TASK task 0 任务 0 比较特殊 所以特意给它单独定义一个符 号 define LAST TASK task NR TASKS 1 任务数组中的最后一项任务 define TASK RUNNING 0 进程正在运行或已准备就绪 define TASK INTERRUPTIBLE 1 进程处于可中断等待状态 define TASK UNINTERRUPTIBLE 2 进程处于不可中断等待状态 主要用于 I O 操作等待 define TASK ZOMBIE 3 进程处于僵死状态 已经停止运行 但父进程 还没发信号 define TASK STOPPED 4 进程已停止 Linux 的 fork exec wait 函数分析 5 2 32 3 调用关系图调用关系图 2 42 4 各模块各模块 函数的功能及详细框图函数的功能及详细框图 2 4 12 4 1 do forkdo fork 模块模块 当进程调用 fork 时 该进程从概念上被分成两部分 祖先和子孙可以自由选择不 同飞路径 在 fork 之后 祖先进程和其子进程几乎是等同的 它们所有的变量都有相 同的值 它们打开的文件都相同 等等 但是如果祖先进程改变了一个变量的值 子 进程看不到这个变化 反之亦然 子进程是祖先进程的一个拷贝 但它们并不共享内 存内容 linux 保留了传统的 fork 并增加了一个更加通用的函数 clone 鉴于 fork 创建一个新 进程的子孙进程后 子孙进程虽然是祖先进程的拷贝 但是它们并不共享内容 clone 允许你定义祖先进程和子进程所应该共享的内容 如果你没有给 clone 提供 它所能识别的五个标志 子孙进程和祖先进程就不会共享任何内容 这就和传统 fork 类似 如果你提供了全部的五个标志 子孙进程就可以和祖先进程共享任何内容 这 就和传统的线程类似 其他标记的不同组合可以使你完成介于两者之间的功能 图 2 1 do fork 函数流程图 long do fork unsigned long clone flags unsigned long stack start struct pt regs regs unsigned long stack size int user parent tidptr 分配新的进程控制快并给新的进程控制快赋值 给新进程一个 PID 设置进程之间的家族信息 把新进程放到 Pidhash 表中 把进程设置为 TASK RUNNING 状态 Linux 的 fork exec wait 函数分析 6 int user child tidptr struct task struct p int trace 0 long nr if unlikely clone flags 如果在 clone flags 中设置了 CLONE PID 标志 就返回一个错误 EPERM 因为 CLONE PID 有特殊的作用 当这个标志为 1 时 父 子进程 线程 共用一个 进程号 即子进程虽然有自己的 task struct 结构 却使用父进程的 pid 但是只有 0 号进程 即系统中的空线程 才允许使用这个标志 if count 0 count printk KERN INFO fork process s used deprecated clone flags 0 x lx n get task comm comm current clone flags When called from kernel thread don t do user tracing stuff if likely user mode regs trace tracehook prepare clone clone flags p copy process clone flags stack start regs stack size child tidptr NULL trace copy process 函数申请 PCB 空间 并赋值 if IS ERR p Linux 的 fork exec wait 函数分析 7 struct completion vfork nr task pid vnr p if clone flags if clone flags init completion tracehook report clone trace regs clone flags nr p 根据该文件中别处定义的辅助函数 根据所提供的 clone flags 参数的值为子孙进程 建立祖先进程的数据结构中子孙进程部分的拷贝 如果 clone flags 指明相关的部分应 该是共享 而不是拷贝 这是辅助函数就简单地增加引用计数接着返回 否则 它就创 建新进程所独有的新拷贝 p flags if unlikely clone flags set tsk thread flag p TIF SIGPENDING set task state p TASK STOPPED else wake up new task p clone flags tracehook report clone complete trace regs clone flags nr p if clone flags wait for completion Linux 的 fork exec wait 函数分析 8 freezer count tracehook report vfork done p nr else nr PTR ERR p return nr 2 4 22 4 2 get pidget pid 模块模块 PID 是使用 get pid 函数生成的 该函数能够返回一个没有使用的 PID 它从 last pid 开始 这是最近分配的 PID 内核中使用的 get pid 的版本是内核复杂性和速度频繁折中的一个例子 这里速度 更为重要一些 get Pid 经过了高度优化 它比直接向前的实现方法要复杂得多 但 是速度也要快得多 最直接的实现方法将遍历执行整个任务列表 典型的情况可能 有几十项 有时候也可能成百上千项 对每一个可能的 PID 进程检测并找出适当的 值 但是在人多数情况下都可以跳过 如果我们所需要的只是要为每一个运行进程都快速计算一个各不相同的整数 那么 这里已经有现实可用的方法 只要取在 task 数组中进程的索引就可以了 这肯定要比 现在的 get Pid 速度要快 毕竟 这无须遍历任务列表 但是 很多现存的应用程序 都假定在一个 PID 可以再重用之前都需要等待一段时间 这种假定在任何情况下都是 不安全的 但是 如果为了这些程序的问题而将内核牵涉进去可能仍然是不好的 现 存的 PID 分配策略速度仍然很快 并且它偶尔还有可以暴露这些应用程序中的潜在的 缺陷 static int get pid unsigned long flags static int next safe PID MAX 静态 next safe 初始时让它等于最大的 pid 值 next safe 变量是一个为加快系统运行速度而设定的变量 它保持记录了可能保留 的次最低的候选 PID 当 last pid 递增并超过这个范围时 系统应该检测整个任务列表 来保证这个候选 PID 是否仍在被保留若 原来保留这个 PID 的进程现在可能已经运行 完了 由于遍历这个任务列表可能会很慢 所以 只要可能就应该避免执行这样的操 作 因此 在执行这个遍历的过程中 get Pid 要重新计算 next safe 如果有些进程 已经死掉了 这个数字可能现在更大了 因此 get pid 可以避免一些将来对任务列表的 Linux 的 fork exec wait 函数分析 9 遍历 next safe 是静态的 因此其值在下次 get Pid 需要分配 PID 时就会保留下来 如 果新的进程要和其祖先共享 PID 就返回祖先进程的 PID struct task struct p int pid if flags spin lock 开始搜寻候选 PID 寻找未使用的值 位与运算只是通过测试低 15 位是否置位来简 单测试 last pid 的新值是否超过了 32767 最大允许的 PID 我怀疑这些内核开发者 真的需要通过这样做来获得微小的速度优势 但是你永远也不会知道 至少在这段代 码编写期间 gcc 还不够敏锐到足以注意到它们的等价性 并在生成的代码中选择稍 微快速的形式 if last pid Skip daemons etc goto inside 显然 大于了 8000 就不需要判断 last pid next safe 了 if last pid next safe 当准备分配的 last pid 大于了 next safe 那么这个值就 unsafe 了 inside next safe PID MAX 先把 next safe 拉到最后 然后再一步一步的寻找最佳位 置 read lock repeat for each task p if p pid last pid p pgrp last pid p tgid last pid p session last pid if last pid next safe if last pid Linux 的 fork exec wait 函数分析 10 next safe PID MAX goto repeat if p pid last pid if p pgrp last pid if p session last pid 这是为了找到 last pid 到 next safe 的最好空间 read unlock pid last pid spin unlock return pid 2 4 3 do execve 模块模块 用 search binary hander 找到要执行的程序 struct linux binprm 初始化参数和环境 文件是否存在 Y 用 copy strings 把参数和环境变量拷贝到次进程 填充 bprm 的 argc 和 argv 出错 N Linux 的 fork exec wait 函数分析 11 图 2 2 do execve 函数流程图 如果我们能够进行的所有工作只是 fork 或者 clone 那么我们就一次次建立 同一个进程的拷贝就可以了 这样我们的 Linux 系统就只能运行在系统中第一个创 建的用户进程 init 了 init 是很有用的 但是功能还没有如此强大 我们也还需要处 理其他事情 在我们创建新的进程以后 它通过调用 exec 就能够变成独立于其他进程的进程了 因此创建一个 真正 的新进程 与其祖先不同的程序运行镜像 任务分为两 步 一步是 fork 另一步是 exec do execve 处理三种工作 1 把一些定义信息从文件读入内存 2 准备新的参数和环境 这是 C 应用程序将它作为 argc argv 和 cnvp 使用的内 容 3 装载可以解析可执行文件的二进制处理程序 并让它处理剩余的修改内核数据的 工作 int do execve 准备新的参数和环境 char filename char user user argv char user user envp struct pt regs regs struct linux binprm bprm 建立 struct linux binprm struct file file struct files struct displaced int retval retval unshare files if retval goto out ret retval ENOMEM bprm kzalloc sizeof bprm GFP KERNEL Linux 的 fork exec wait 函数分析 12 if bprm goto out files file open exec filename retval PTR ERR file if IS ERR file 判断可执行文件是否存在 goto out kfree sched exec bprm file file bprm filename filename bprm interp filename retval bprm mm init bprm if retval goto out file bprm argc count argv MAX ARG STRINGS if retval bprm argc envc count envp MAX ARG STRINGS if retval bprm envc 0 goto out mm retval security bprm alloc bprm if retval goto out retval prepare binprm bprm if retval filename bprm 用 copy strings 来把参数 Linux 的 fork exec wait 函数分析 13 和环境变量拷贝到次年进程 if retval exec bprm p retval copy strings bprm envc envp bprm if retval argc argv bprm if retval flags retval search binary handler bprm regs 用 search binary hander 来找 到 要执行的二进制处理程序 if retval 0 execve success security bprm free bprm acct update integrals current free bprm bprm if displaced put files struct displaced return retval out if bprm security 判断 bprm 是否安全 security bprm free bprm 如果安全则释放它 out mm if bprm mm mmput bprm mm Linux 的 fork exec wait 函数分析 14 out file if bprm file allow write access bprm file 如果该文件有写权限则访问 fput bprm file out kfree free bprm bprm out files if displaced reset files struct displaced out ret return retval 3 4 43 4 4 do exitdo exit 模块模块 exit 用来让进程结束它在内核中是通过 sys exit 实际是采用 do exit 实现的当进 程退出的时候内和会释放所有相关资源内存文件等等并停止给它 CPU 的机会但是这个 时候进程并没有结束需要保留进程的 task struct 结构等待它的父进程调用 wait 来查询 子孙进程的退出状态所以内和必须保留子孙进程的 PID 直到 wait 发生为止这个时候的 进程 是僵进程 退出信号 释放信号量和 IPC 内存 文件 文件系统数据 信号量处理程序表 进入 TASK ZOMBIE 状态 同 时记录退出代码 调用 exit notify 告知进程已经退 出 释放 CPU Linux 的 fork exec wait 函数分析 15 图 2 3 do exit 函数流程图 NORET TYPE void do exit long code 设置退出代码函数的参数 struct task struct tsk current int group dead profile task exit tsk WARN ON atomic read if unlikely in interrupt panic Aiee killing interrupt handler if unlikely tsk pid panic Attempted to kill the idle task tracehook report exit 让进程进入 TASK ZOMBIE 状态 并记录它的退出代码 if unlikely tsk flags tsk flags PF EXITPIDONE if tsk io context exit io context set current state TASK UNINTERRUPTIBLE schedule exit signals tsk 设置 PF EXITING smp mb spin unlock wait if unlikely in atomic Linux 的 fork exec wait 函数分析 16 printk KERN INFO note s d exited with preempt count d n current comm task pid nr current preempt count acct update integrals tsk if tsk mm update hiwater rss tsk mm update hiwater vm tsk mm group dead atomic dec and test if group dead hrtimer cancel exit itimers tsk signal acct collect code group dead ifdef CONFIG FUTEX 定义 CONFIG FUTEX if unlikely tsk robust list exit robust list tsk ifdef CONFIG COMPAT 定义 CONFIG COMPAT if unlikely tsk compat robust list compat exit robust list tsk endif endif if group dead tty audit exit if unlikely tsk audit context audit free tsk tsk exit code code taskstats exit tsk group dead exit mm tsk if group dead acct process Linux 的 fork exec wait 函数分析 17 exit sem tsk exit files tsk 结束文件任务 exit fs tsk check stack usage 检查堆栈使用情况 exit thread cgroup exit tsk 1 exit keys tsk if group dead module put task thread info tsk exec domain module if tsk binfmt module put tsk binfmt module proc exit connector tsk exit notify tsk group dead 调用 exit notify 告知它的祖先进程这个进程已经退 出 ifdef CONFIG NUMA mpol put tsk mempolicy tsk mempolicy NULL endif ifdef CONFIG FUTEX if unlikely list empty if unlikely current pi state cache kfree current pi state cache endif debug check no locks held tsk tsk flags PF EXITPIDONE if tsk io context exit io context if tsk splice pipe free pipe info tsk splice pipe preempt disable causes final put task struct in finish task switch tsk state TASK DEAD schedule 调用 Shedule 释放 CPU Linux 的 fork exec wait 函数分析 18 BUG Avoid noreturn function does return for cpu relax For when BUG is null 3 4 53 4 5 sys wait4sys wait4 模块模块 和 exec 一样 wait 是一组函数 而不是一个函数 wait 家族中的其他函数最终 都是使用一个系统调用 sys wait4 实现的 这个系统调用的名字反映出它实现了 wait 家族中最通用的函数 wait4 标准 c 库 libc 的实现必须重新组织对于其他 wait 函数调用的参数 并调用 sys
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 基于改进MRAS与SM-ADRC的永磁同步电机无位置传感器控制研究
- 基于深度强化学习的交通信号灯控制优化算法研究
- 海钓鲈鱼活动方案策划
- 自建房屋面垫层施工方案
- 职业技能竞赛货运岗位实战技巧解析
- 三年级乘法应用题测验及解析
- 高应力隧道围岩声发射及岩爆破坏特性试验研究
- 目的论指导下的《忠于自己惠泽他人》(节选)韩中翻译实践报告
- 小学语文经典故事说课设计与教学反思
- 光缆敷设施工日志填写规范及案例
- 《TCSUS69-2024智慧水务技术标准》
- 2025年医师定期考核临床专业知识考试试题+答案
- 交通银行2025秋招无领导小组面试案例库吉林地区
- 孵化器行业培训课件
- 造纸厂成品库管理细则
- 角膜捐献接受管理办法
- 《宪法是根本法》课件
- 吊篮考试试卷及答案
- 国有企业十五五人力资源规划框架
- 医院护理人文关怀实践规范专家共识
- 2025金融工作会议考试题及答案
评论
0/150
提交评论