- 以fork和execve系统调用为例分析中断上下文的切换
- 分析execve系统调用中断上下文的特殊之处
- 分析fork子进程启动执行时进程上下文的特殊之处
- 以系统调用作为特殊的中断,结合中断上下文切换和进程上下文切换分析Linux系统的一般执行过程
一、以fork和execve系统调用为例分析中断上下文的切换
fork系统调用:fork由父进程创建一子进程,新创建的子进程几乎但是不完全与父进程相同。
子进程得到与父进程用户级虚拟地址空间相同(但是独立)的一份拷贝,包括文本,数据和bss段、堆以及用户栈。
子进程还获得与父进程任何打开文件描述符相同的拷贝。这就是意味着当父进程调用fork时候,子进程还可以读写父进程中打开的任何文件。
父进程和新创建的子进程之间最大区别在于他们有着不同的PID。
fork系统调用通过do_fork函数来创建新进程,_do_fork函数主要完成了调?copy_process()复制?进程、获得pid、调?wake_up_new_task将?进程加?就绪队列等待调度执?等。
copy_process()是创建进程过程中的主要部分。其主要完成了:
调?dup_task_struct复制当前进程(?进程)描述符task_struct、
信息检查、
初始化、
把进程状态设置为TASK_RUNNING(此时?进程置为就绪态)、
采?写时复制技术逐?复制所有其他进程资源、
调?copy_thread_tls初始化?进程内核栈、
设置?进程pid等。
其中最关键的就是dup_task_struct,其复制当前进程(?进程)描述符task_struct和copy_thread_tls用于初始化?进程内核栈。
copy_thread_tls负责构造fork系统调用在子进程的内核堆栈,子进程的内核函数调用堆栈需要特殊构建,为子进程的运行准备好上下文环境。
execve系统调用的主要作用:
分配进程新的地址空间,将环境变量、main参数等拷贝到新地址空间的推栈中;
解析可执行文件,将代码、数据装入/映射到内存
进程新环境的设置,如关闭设置FD_CLOEXEC的文件等
设置execve函数返回到用户态时的执行地址;解析器入口地址或程序的入口地址
execve系统调用主要通过do_execve函数来实现
do_execve函数具体流程如下:
进程分配并使用自己的文件描述符表,不再使用共享的文件描述符表
分配进程新的地址空间mm_struct,并复制老mm_struct的context,并分配一页大小的堆栈内存区。
打开可执行文件;检查可执行文件权限,并预读可执行文件的前BINPRM_BUF_SIZE=128字节数据到buf中
计算环境变量、main参数个数;并将这些参数复制到新地址空间的堆栈中
根据可执行文件的格式,查找对应的handler作后续处理;
二、分析execve系统调用中断上下文的特殊之处
execve系统调用在保持进程ID不变的情况下,使用新的上下文环境“覆盖”原上下文环境,也即原来的上下文环境不再保存,相关的环境数据直接被丢弃。
三、分析fork子进程启动执行时进程上下文的特殊之处
fork子进程的进程上下文需要借由copy_thread_tls函数特殊构建:子进程的复制了父进程所有的上下文环境信息,但二者的PID不同,各自作为独立的进程被调度。
四、以系统调用作为特殊的中断,结合中断上下文切换和进程上下文切换分析Linux系统的一般执行过程
以32位x86系统结构linux-3.18.6为例,以系统调?作为特殊的中断简要总结如下。
(1)正在运?的?户态进程X。
(2)发?中断(包括异常、系统调?等),CPU完成以下动作。
• save cs:eip/ss:esp/eflags:当前CPU上下?压?进程X的内核堆栈。
• load cs:eip(entry of a specific ISR) and ss:esp(point to kernel stack):加载当前进程内核堆栈相关信息,跳转到中断处理程序,即中断执?路径的起点。
(3)SAVE_ALL,保存现场,此时完成了中断上下?切换,即从进程X的?户态到进程X的内核态。
(4)中断处理过程中或中断返回前调?了schedule函数,其中的switch_to做了关键的进程上下?切换。将当前进程X的内核堆栈切换到进程调度算法选出来的next进程(本例假定为进程Y)的内核堆栈,并完成了进程上下?所需的EIP等寄存器状态切换。
(5)标号1,即前述3.18.6内核的swtich_to代码第50?“”1:\t“ ”(地址为switch_to中的“$1f”),之后开始运?进程Y(这?进程Y曾经通过以上步骤被切换出去,因此可以从标号1继续执?)。
(6)restore_all,恢复现场,与(3)中保存现场相对应。注意这?是进程Y的中断处理过程中,?(3)中保存现场是在进程X的中断处理过程中,因为内核堆栈从进程X切换到进程Y了。
(7)iret - pop cs:eip/ss:esp/eflags,从Y进程的内核堆栈中弹出(2)中硬件完成的压栈内容。此时完成了中断上下?的切换,即从进程Y的内核态返回到进程Y的?户态。
(8)继续运??户态进程Y。