学号后三位:144
文中参考代码出处:https://github.com/mengning/linuxkernel/
本文主要针对进程创建、可执行文件的加载和进程间切换三大部分进行实验并分析。
实验环境:Ubuntu 16虚拟机、VMware 14
1 进程创建
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
1.1 描述进程的数据结构
在操作系统中,进程也需要一个数据结构来保存内核对进程状态等信息,此数据结构我们一般将其称作进程控制块(Process Control Block)。PCB在linux内核中定义为task_struct结构体,并在/include/linux/sched.h源文件中实现。
由于源代码较多,在此处只给出部分常用代码:
volatile long state; //表示进程状态
void *stack; //进程所属堆栈指针
unsigned int rt_priority;//进程优先级
int exit_state;//退出时状态
pid_t pid;//进程号,作为进程的全局标识符
pid_t tgid;//进程组号
struct task_struct __rcu *real_parent;//父进程
struct list_head children;//子进程
struct list_head sibling;//兄弟进程
struct task_struct *group_leader;//所属进程组的主进程
1.2 fork函数对应的内核处理过程do_fork
传统的UNIX中用于复制进程的系统调用是fork。但它并不是Liunx为此实现的唯一的调用,实际上Linux实现了3个:
(1)fork是重量级调用,它建立了父进程的一个完整副本,然后为子进程执行。
(2)vfork类似于fork,但并不创建父进程数据的副本。相反,父子进程之间共享数据。
(3)clone产生线程,可以对父子进程之间的共享、复制进行精确控制。
fork、vfork和close系统调用的入口分别是sys_fork、sys_vfork和sys_clone函数。以上函数从寄存器中取出由用户定义的信息,并调用与体系结构无关的do_fork函数进行进程的复制。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,
int __user *child_tidptr)
所有3个fork机制最终都调用了kernel/fork.c中的do_fork,其代码流程图如下(图片出处为《深入Linux内核架构》人民邮电出版社):
在do_fork中大多数工作是由copy_process函数完成的,其代码流程如下图所示(图片出处为《深入Linux内核架构》人民邮电出版社):