20222817《Linux内核原理与分析》第七周作业
分析 Linux 内核创建一个新进程的过程
1.实验过程
2.实验分析及总结
do_fork关键代码分析
long do_fork(unsigned long clone_flags,unsigned long stack_start,unsigned long stack_size,int __user *parent_tidptr,int __user *child_tidptr)
{//创建进程描述符指针struct task_struct *p;//……//复制进程描述符,copy_process()的返回值是一个 task_struct 指针。p = copy_process(clone_flags, stack_start, stack_size,child_tidptr, NULL, trace);if (!IS_ERR(p)) {struct completion vfork;struct pid *pid;trace_sched_process_fork(current, p);//得到新创建的进程描述符中的pidpid = get_task_pid(p, PIDTYPE_PID);nr = pid_vnr(pid);if (clone_flags & CLONE_PARENT_SETTID)put_user(nr, parent_tidptr);//如果调用的 vfork()方法,初始化 vfork 完成处理信息。if (clone_flags & CLONE_VFORK) {p->vfork_done = &vfork;init_completion(&vfork);get_task_struct(p);}//将子进程加入到调度器中,为其分配 CPU,准备执行wake_up_new_task(p);//fork 完成,子进程即将开始运行if (unlikely(trace))ptrace_event_pid(trace, pid);//如果是 vfork,将父进程加入至等待队列,等待子进程完成if (clone_flags & CLONE_VFORK) {if (!wait_for_vfork_done(p, &vfork))ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);}put_pid(pid);} else {nr = PTR_ERR(p);}return nr;
}
dup_task_struct关键代码分析
static struct task_struct *dup_task_struct(struct task_struct *orig)
{struct task_struct *tsk;struct thread_info *ti;int node = tsk_fork_get_node(orig);int err;// 分配一个task_struct结点tsk = alloc_task_struct_node(node);if (!tsk)return NULL;// 分配一个thread_info结点,其实内部分配了一个union,包含进程的内核栈// 此时ti的值为栈底,在x86下为union的高地址处。ti = alloc_thread_info_node(tsk, node);if (!ti)goto free_tsk;err = arch_dup_task_struct(tsk, orig);if (err)goto free_ti;// 将栈底的值赋给新结点的stacktsk->stack = ti;.../** One for us, one for whoever does the "release_task()" (usually* parent)*/// 将进程描述符的使用计数器置为2atomic_set(&tsk->usage, 2);
#ifdef CONFIG_BLK_DEV_IO_TRACEtsk->btrace_seq = 0;
#endiftsk->splice_pipe = NULL;tsk->task_frag.page = NULL;account_kernel_stack(ti, 1);// 返回新申请的结点return tsk;free_ti:free_thread_info(ti);
free_tsk:free_task_struct(tsk);return NULL;
}
copy_thread关键代码分析
// 初始化子进程的内核栈
int copy_thread(unsigned long clone_flags, unsigned long sp,unsigned long arg, struct task_struct *p)
{// 取出子进程的寄存器信息struct pt_regs *childregs = task_pt_regs(p);struct task_struct *tsk;int err;// 栈顶 空栈p->thread.sp = (unsigned long) childregs;p->thread.sp0 = (unsigned long) (childregs+1);memset(p->thread.ptrace_bps, 0, sizeof(p->thread.ptrace_bps));// 如果是创建的内核线程if (unlikely(p->flags & PF_KTHREAD)) {/* kernel thread */memset(childregs, 0, sizeof(struct pt_regs));// 内核线程开始执行的位置p->thread.ip = (unsigned long) ret_from_kernel_thread;task_user_gs(p) = __KERNEL_STACK_CANARY;childregs->ds = __USER_DS;childregs->es = __USER_DS;childregs->fs = __KERNEL_PERCPU;childregs->bx = sp; /* function */childregs->bp = arg;childregs->orig_ax = -1;childregs->cs = __KERNEL_CS | get_kernel_rpl();childregs->flags = X86_EFLAGS_IF | X86_EFLAGS_FIXED;p->thread.io_bitmap_ptr = NULL;return 0;}// 将当前进程的寄存器信息复制给子进程*childregs = *current_pt_regs();// 子进程的eax置为0,所以fork的子进程返回值为0childregs->ax = 0;if (sp)childregs->sp = sp;// 子进程从ret_from_fork开始执行p->thread.ip = (unsigned long) ret_from_fork;task_user_gs(p) = get_user_gs(current_pt_regs());p->thread.io_bitmap_ptr = NULL;tsk = current;err = -ENOMEM;// 如果父进程使用IO权限位图,那么子进程获得该位图的一个拷贝if (unlikely(test_tsk_thread_flag(tsk, TIF_IO_BITMAP))) {p->thread.io_bitmap_ptr = kmemdup(tsk->thread.io_bitmap_ptr,IO_BITMAP_BYTES, GFP_KERNEL);if (!p->thread.io_bitmap_ptr) {p->thread.io_bitmap_max = 0;return -ENOMEM;}set_tsk_thread_flag(p, TIF_IO_BITMAP);}...return err;
}
Linux通过复制父进程来创建一个新进程,通过调用do_ fork来实现并为每个新创建的进程动态地分配一个task_ struct结构。进程是处于执行期程序以及其相关资源的总称。在Linux系统中,对于进程和线程并没有明显的区分,线程是一种特殊的进程。Linux系统常用fork()创建子进程。fork()由父进程来进行调用并且由sys_clone系统调用实现,最后通过exit()退出执行。
Linux的进程创建由fork()与exec()来完成,前者拷贝当前进程创建子进程,后者负责读取可执行文件并将其载入地址空间开始运行。
fork只会被调用一次,却能够返回两次,它可能有三种不同的返回值:
在父进程中,fork返回新创建子进程的进程ID;
在子进程中,fork返回0;
如果出现错误,fork返回一个负值;
在进程描述符PID中,state描述了进程当前的状态,TASK_RUNNING标识该进程正在运行或等待运行,是否在运行取决于它是否取得了内核的控制权,这是进程在用户空间执行的唯一可能状态。
新进程是从哪里开始执行的?为什么从那里能顺利执行下去,执行起点与内核堆栈如何保证一致?
dup_task_struct为新进程分配了新的堆栈,copy_process调用sched_fork将新进程的state置为TASK_RUNNING,copy_thread中执行语句*childregs = *current_ pt_ regs()将父进程保存的寄存器上下文复制给子进程,保证了父子进程堆栈信息的一致,从而保证了执行起点与内核堆栈的一致。最后将ret_from_fork的地址设置为eip寄存器的值,新进程即从这里开始执行。
20222817《Linux内核原理与分析》第七周作业相关推荐
- 2017-2018-1 20179215《Linux内核原理与分析》第二周作业
20179215<Linux内核原理与分析>第二周作业 这一周主要了解了计算机是如何工作的,包括现在存储程序计算机的工作模型.X86汇编指令包括几种内存地址的寻址方式和push.pop.c ...
- 2022-2023-1 20222809《Linux内核原理与分析》第一周作业
Linux内核原理与分析第一周作业 配置环境 1.参考Linux(Ubuntu)系统安装图文教程中第二种借助virtualbox成功配置Ubuntu环境 2.升级更新软件包 可以通过调节分辨率和虚拟机 ...
- 实验楼 linux内核原理与分析,《Linux内核原理与分析》第一周作业 20189210
实验一 Linux系统简介 这一节主要学习了Linux的历史,Linux有关的重要人物以及学习Linux的方法,Linux和Windows的区别.其中学到了LInux中的应用程序大都为开源自由的软件, ...
- 《Linux内核原理与分析》第二周作业
反汇编一个简单的C程序 1.实验要求 使用: gcc –S –o test.s test.c -m32 命令编译成汇编代码,对汇编代码进行分析总结.其中test.c的具体内容如下: int g(int ...
- 2018-2019-1 20189218《Linux内核原理与分析》第九周作业
进程调度的时机 进程调度时机就是内核调用schedule函数的时机.当内核即将返回用户空间时,内核会检查need_resched标志是否设置.如果设置,则调用schedule函数,此时是从中断(或者异 ...
- 2021-2022-1 20212820《Linux内核原理与分析》第一周作业
声明:本文是基于Linux 基础入门_Linux - 蓝桥云课 (lanqiao.cn)这门课学习所写的课程笔记. 实验1 Linux系统简介 Linux主要包括是系统调用和内核两部分 Linux与W ...
- 20189220 余超《Linux内核原理与分析》第一周作业
实验一 Linux系统简介 通过实验一主要是学习到了Linux 的历史简介,linux与windows之间的区别,主要是免费和收费,软件和支持,安全性,使用习惯,可制定性,应用范畴等.linux具有稳 ...
- 2018-2019-1 20189201 《LInux内核原理与分析》第九周作业
那一天我二十一岁,在我一生的黄金时代.我有好多奢望.我想爱,想吃,还想在一瞬间变成天上半明半暗的云.那一年我二十一岁,在我一生的黄金时代.我有好多想法.我思索,想象,我不知该如何行动,我想知道一个城市 ...
- 2018-2019-1 20189208《Linux内核原理与分析》第九周作业
活动 main函数编译有问题,div 函数和系统中某个函数重名,浮点输出有问题,scanf也有问题 修改如下 scanf_s("%d %d", &a, &b); p ...
- 2021-2022-1 20212808《Linux内核原理与分析》第一周作业
一.实验中出现的问题 理解不清二进制数字表示和加减赋值表示文件权限.比如 chmod 600 test.txt 中600是如何计算的. chmod abc file chmod 600 text.tx ...
最新文章
- 数据清洗指南完整分享
- 【079】用代码来创建 Android 控件
- 计算机缺失wininet.dll,xp系统开机提示wininet.dll文件丢失怎么解决
- android 如何调用 隐藏的 API 接口
- 文献记录(part44)--Skeletonisation algorithms with theoretical guarantees for unorganised point ...
- Vision Transformer 论文解读
- Ubuntu关闭防火墙
- 每个Java程序员必须知道的5个JVM命令行标志
- C# 值类型和引用类型
- 51Nod 1046 A^B Mod C(日常复习快速幂)
- 【使用R语言两行语句将搜狗词库转为csv格式】
- 推荐一个项目管理工具:TAPD
- 八皇后问题(回溯算法)
- 五子棋的实现 Java课程设计
- 移动apn接入点哪个快_千兆交换机和快速以太网交换机哪个更好呢?
- 转载:深入浅出的讲解傅里叶变换
- tsc HPET kvm-clock
- Vue packages version mismatch: - vue@2.6.11 vue-template-compiler@2.6.10 的解决办法
- 《这么慢,那么美》------ 听见
- 敏捷教练的八种失败角色
热门文章
- horizon部署linux桌面,7-horizon仪表盘服务部署
- linux find 递归搜索文件名
- 有一种虫叫蠓虫,蚊子在它面前不值一提
- 评委打分(JAVA代码)
- 网易考拉等巨头的“电商+直播”模式,或是找到了新的突破口?
- codemirror mysql_Angular6 CodeMirror在线编辑sql 智能提示
- Trojan/Android.GDownload.jw[exp,gen] 病毒报警解决方案
- 制作自己的第一个网页
- Android 开发日记 - Bold-Italic在TextView中,最后的字会被截掉
- 希捷银河企业级硬盘,智能高效首选 1