linux进程上下文切换的具体过程,Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程...
fork系统调?创建?进程,也就?个进程变成了两个进程,两个进程执?相同的代码,只是fork系统调?在?进程和?进程中的返回值不同。
打开linux-5.4.34/arch/x86/entry/syscalls/syscall_64.tbl 文件,56、 57、 58号系统调?__x64_sys_clone、 __x64_sys_fork、__x64_sys_vfork,即如下kernel/fork.c代码。
进入linux-5.4.34/kernel/fork.c 查看 fork 源代码:
/** Create a kernel thread.*/pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned longflags)
{return _do_fork(&args);
}
SYSCALL_DEFINE0(fork)
{return _do_fork(&args);
}
SYSCALL_DEFINE0(vfork)
{return _do_fork(&args);
}
SYSCALL_DEFINE5(clone, unsignedlong, clone_flags, unsigned long, newsp,
{return _do_fork(&args)
}
通过上?的代码可以看出fork、vfork和clone这3个系统调?,以及do_fork和kernel_thread内核函数都可以创建?个新进程,?且都是通过_do_fork函数来创建进程的,只不过传递的参数不同。
_do_fork函数主要完成了调?copy_process()复制?进程、获得?wake_up_new_task将?进程加?就绪队列等待调度执?等。
//_do_fork关键部分代码
long _do_fork(struct kernel_clone_args *args)
{//复制进程描述符和执?时所需的其他数据结构
p =copy_process(NULL, trace, NUMA_NO_NODE, args);
wake_up_new_task(p);//将?进程添加到就绪队列
return nr;//返回?进程pid(?进程中fork返回值为?进程的pid)
}
copy_process()是创建?个进程的主要的代码。如下是copy_process()函数的关键代码,完整代码?kernel/fork.c
static __latent_entropy struct task_struct *copy_process(struct pid *pid,inttrace,intnode,struct kernel_clone_args *args)
{//复制进程描述符task_struct、创建内核堆栈等
p =dup_task_struct(current, node);/*copy all the process information*/shm_init_task(p);
…//初始化?进程内核栈和thread
retval = copy_thread_tls(clone_flags, args->stack, args->stack_size, p,
args->tls);
…return p;//返回被创建的?进程描述符指针
}
copy_process函数主要完成了:
调?dup_task_struct复制当前进程(?进程)描述符task_struct
信息检查、初始化、把进程状态设置为TASK_RUNNING(此时?进程置为就绪态)、采?写时复制技术逐?复制所有其他进程资源
调?copy_thread_tls初始化?进程内核栈
设置?进程pid等。
接下来具体看dup_task_struct和copy_thread_tls
dup_task_struct作用:
在专业高速缓冲内存上分配task_struct,并完成初始化
在普通内存中分配thread_info及连续的两个页面,完成初始化
将task_struct和thread_info联系起来
主要代码:
static struct task_struct *dup_task_struct(struct task_struct *orig, intnode)
{…//实际完成进程描述符的拷?,具体做法是*tsk = *orig
err =arch_dup_task_struct(tsk, orig);
…
tsk->stack =stack;
...//实际完成进程描述符的拷?,具体做法是*tsk = *orig
setup_thread_stack(tsk, orig);
clear_user_return_notifier(tsk);
clear_tsk_need_resched(tsk);
set_task_stack_end_magic(tsk);…
}
copy_thread_tls作用:
负责构造fork系统调?在?进程的内核堆栈,也就是fork系统调?在??进程各返回?次,?进程中和其他系统调?的处理过程并??致,?在?进程中的内核函数调?堆栈需要特殊构建,为?进程的运?准备好上下?环境。
主要代码:
int copy_thread_tls(unsigned long clone_flags, unsigned longsp,
unsignedlong arg, struct task_struct *p, unsigned longtls)
{
frame->ret_addr = (unsigned long) ret_from_fork;
p->thread.sp = (unsigned long) fork_frame;*childregs = *current_pt_regs();
childregs->ax = 0;
.../** Set a new TLS for the child thread?*/
if (clone_flags &CLONE_SETTLS) {
err= do_arch_prctl_64(p, ARCH_SET_FS, tls);
do_fork 总结
进程的创建过程?致是?进程通过fork系统调?进?内核_do_fork函数,如下图所示复制进程描述符及相关进程资源(采?写时复制技术)、分配?进程的内核堆栈并对内核堆栈和thread等进程关键上下?进?初始化,最后将?进程放?就绪队列, fork系统调?返回;??进程则在被调度执?时根据设置的内核堆栈和thread等进程关键上下?开始执?。
2 execve系统调用
execve(执行文件)在父进程中fork一个子进程,在子进程中调用exec函数启动新的程序。exec函数一共有六个,其中execve为内核级系统调用,其他(execl,execle,execlp,execv,execvp)都是调用execve的库函数。
表头文件:
#include
定义函数:
int execve(const char * filename,char * const argv[ ],char * const envp[ ]);
execve()用来执行参数filename字符串所代表的文件路径,第二个参数是利用指针数组来传递给执行文件,并且需要以空指针(NULL)结束,最后一个参数则为传递给执行文件的新环境变量数组。成功无返回值,失败返回-1。
execve系统调过程:
sys_execve-->do_execve-->do_execveat_common-->__do_execve_file-->search_binary_handler-->load_elf_binary-->start_thread
execve陷入内核,传入命令行参数和shell上下文环境
sys_execve调用do_execve封装命令行参数和shell上下文
调用do_execveat_common,do_execveat_common调用__do_execve_file,打开ELF文件并把信息的装入linux_binprm结构体
__do_execve_file中调用search_binary_handler,寻找解析ELF文件的函数
search_binary_handler找到ELF文件解析函数load_elf_binary,解析ELF文件,把ELF文件装入内存,修改进程的用户态堆栈,修改进程的数据段代码段
load_elf_binary调用start_thread修改进程内核堆栈
返回用户态,此时ip指向ELF文件的main函数地址
三 Linux的一般执行过程
1) 正在运?的?户态进程X。
2) 发?中断(包括异常、系统调?等), CPU完成load cs:rip(entry of a specific ISR),即跳转到中断处理程序??。
3) 中断上下?切换,具体包括如下?点:
swapgs指令保存现场,可以理解CPU通过swapgs指令给当前CPU寄存器状态做了?个快照。
rsp point to kernel stack,加载当前进程内核堆栈栈顶地址到RSP寄存器。快速系统调?是由系统调???处的汇编代码实现?户堆栈和内核堆栈的切换。
save cs:rip/ss:rsp/rflags:将当前CPU关键上下?压?进程X的内核堆栈,快速系统调?是由系统调???处的汇编代码实现的。
此时完成了中断上下?切换,即从进程X的?户态到进程X的内核态。
4) 中断处理过程中或中断返回前调?了schedule函数,其中完成了进程调度算法选择next进程、进程地址空间切换、以及switch_to关键的进程上下?切换等。
5) switch_to调?了__switch_to_asm汇编代码做了关键的进程上下?切换。将当前进程X的内核堆栈切换到进程调度算法选出来的next进程(本例假定为进程Y)的内核堆栈,并完成了进程上下?所需的指令指针寄存器状态切换。之后开始运?进程Y(这?进程Y曾经通过以上步骤被切换出去,因此可以从switch_to下??代码继续执?)。
6) 中断上下?恢复,与(3)中断上下?切换相对应。注意这?是进程Y的中断处理过程中,?(3)中断上下?切换是在进程X的中断处理过程中,因为内核堆栈从进程X切换到进程Y了。
7) 为了对应起?中断上下?恢复的最后?步单独拿出来(6的最后?步即是7) iret - pop cs:rip/ss:rsp/rflags,从Y进程的内核堆栈中弹出(3)中对应的压栈内容。此时完成了中断上下?的切换,即从进程Y的内核态返回到进程Y的?户态。注意快速系统调?返回sysret与iret的处理略有不同。
8) 继续运??户态进程Y。
linux进程上下文切换的具体过程,Linux实验三 结合中断上下文切换和进程上下文切换分析Linux内核一般执行过程...相关推荐
- (75)内核APC执行过程,分析 KiDeliverApc 函数
一.内核APC执行过程 通过分析 SwapContext ,KiSwapContexgt , KiSwapThread ,我们得出一个结论:切换线程后会执行内核APC,调用的函数是 KiDeliver ...
- 使用SystemTap分析lvextend命令的执行过程
使用SystemTap分析lvextend命令的执行过程 1)在SUSE12sp3系统上安装systemstap工具,lvm的debuginfo和debugsource对应的rpm包. 2)准备测试用 ...
- linux内核make执行过程
本篇基于上一篇<<linux内核make menuconfig执行过程>>基础上,追溯make执行过程. make 1. 与make menuconfig相同的部分 这部分内容 ...
- 4.内核APC执行过程
APC函数的执行与插入并不是同一个线程: 在A线程中向B线程插入一个APC,插入的动作是在A线程中完成的,但什么时候执行则由B线程决定!,所以叫"异步过程调用" 内核APC函数与用 ...
- 【正点原子Linux连载】第二十三章 DDR3实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0
1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...
- 【正点原子Linux连载】第二十七章 SPI实验 -摘自【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.0
1)实验平台:正点原子阿尔法Linux开发板 2)平台购买地址:https://item.taobao.com/item.htm?id=603672744434 2)全套实验源码+手册+视频下载地址: ...
- linux执行class文件_深入理解linux内核——可执行文件执行过程(2)
接上篇.. 13.调用do_mmap()函数创建一个新线性区来对可执行文件正文段(即代码)进行映射.这个线性区的起始线性地址依赖于可执行文件的格式,因为程序的可执行代码通常是不可重定位的.因此,这个函 ...
- linux 文件可执行_深入理解linux内核——可执行文件执行过程(2)
接上篇.. 13.调用do_mmap()函数创建一个新线性区来对可执行文件正文段(即代码)进行映射.这个线性区的起始线性地址依赖于可执行文件的格式,因为程序的可执行代码通常是不可重定位的.因此,这个函 ...
- <<linux教程>>第五版 实验三 实验四 ----linux 关于 shell跟vi编辑器,简单命令,刚需上
进入vi. :wq 文件名 \2. 建立一个文件,如file.co进入插入方式,输入一个C语言程序的各行内容,故 意制造几处错误.最后,将该文件存盘.回到shell状态下. 制造头文件不存在的问题 运 ...
最新文章
- 不要依赖代码中的异常
- mockito_Mockito – JAXB的RETURNS_DEEP_STUBS
- cmd命令大全 DOS窗口命令
- ftpwebrequest 无法加载或初始化请求的服务提供程序_jvm之类加载机制
- 将Linux下编译的warning警告信息输出到文件中
- 支持向量机: Maximum Margin Classifier
- MySQL的前缀索引及Oracle的类似实现
- 3d打印机 form3_桌面SLA卖掉5万台后,Formlabs发布新机型Form3和Form 3L
- 如何升级mysql-libs_MySQL升级教程(CentOS)
- FishC笔记—33 讲 异常处理:你不可能总是对的2
- 招商银行/招银网络科技面经、答案
- UE4材质(六):不透明度Opacity——玻璃
- 为什么闹钟设置了却不响_手机闹钟不响是怎么回事 怎么设置闹钟【图文】
- XAMPP下安装微博模板
- 计算机中的数学【费马大定理】 数学史上最著名的定理: x^n + y^n = z^n(n 2时,没有正整数解)...
- python tkinter.Text 高级用法 -- 设计功能齐全的文本编辑器
- biogeme-nest_logit-cnblog
- PS-第四天-矢量形状与路径
- 【虚幻引擎UE】UE4/UE5 GIS辅助类插件推荐及使用介绍
- Python处理unicode字符
热门文章
- 08.Numpy数组迭代
- P2548 [AHOI2004]智能探险车
- 项目管理中的沟通管理(转)
- Migrate Instance 操作详解 - 每天5分钟玩转 OpenStack(40)
- java-设计模式(结构型)-【代理模式】
- POJ 2075 Tangled in Cables (c++/java)
- 陆奇给工程师们的5个建议
- 你应该知道为什么需要内核
- 电信无线网服务器是什么,怎样使用路由器共享电信天翼无线网络
- gps84转换gcj02公式_百度坐标(BD09)、国测局坐标(火星坐标,GCJ02)、和WGS84坐标系之间的转换...