1、进程生命周期:
某个进程通过系统调用fork,创建一个用于执行程序的进程。生成此进程的进程称为父进程,被生成的进程称为子进程。子进程通过复制父进程的数据得以创建;
父进程执行系统调用wait,等待子进程结束;
子进程通过系统调用exec将程序读取到内存并开始执行;
当程序执行完毕后,子进程通过系统调用exit结束自身的运行并进入僵尸状态;
父进程得到子进程的执行结果后清理子进程。
2、创建进程:
进程的复制:通过将父进程的数据复制到子进程,以此创建新的进程,被复制的数据有:proc[]数组元素、复制数据段
系统调用fork:用户程序在执行fork时会首先调用C语言的库函数fork(),在此库函数中再执行sys fork来访问系统调用fork()
子进程的处理:在内核的fork() 处理中,子进程从newproc()返回处开始执行;newproc()是实际创建进程的函数,他负责将proc[]中代表执行进程的元素和执行进程的数据段复制到子进程中,代码段不属于复制对象,子进程和执行进程共享相同的代码段
3、切换执行进程:
中断执行进程:执行进程在执行内核函数sleep() 后进入休眠并中断当前处理,此后,由于swtch()被调用,执行进程发生切换
内核函数sleep()一般在下述情况下被调用:用户程序访问了系统调用wait、等待周边设备处理完毕、等待使用中的资源被释放
选择执行进程的算法:swtch()用来选择下一个将被执行的进程。他从起始位置遍历proc[],并将满足下列条件的进程选择为执行进程
处于可执行状态(SRUN)
拥有最高的执行优先级(proc.p_pri的值最小)
setpri()函数用来随时调整各进程的执行优先级
上下文切换:执行进程被中断时,将当前执行状态保存于user结构体中。当被中断的进程再次执行时,通过user结构体恢复以前的执行状态,这个处理被称作上下文切换
系统调用wait:wait具有以下两个功能:终端当前进程等待子进程执行结束,以及清理执行结束的子进程
sleep() :sleep()接受两个参数:chan和pri。chan为任意变量的地址,其值将被赋给执行进程的proc.p_wchan。wchan代表waiting channel,表示此进程正在等待proc.p_wchan所指向的资源
wakeup()将进程从休眠状态唤醒至可执行状态;系统利用sleep()和wakeup()实现多个进程等待同一资源时的同步处理;
setrun()将由参数指定的进程设定为可执行状态
4、执行程序:执行程序时,首先需要将该程序的执行文件从块设备读取到内存,并将其配置到执行进程的虚拟地址空间;
系统调用exec用于执行程序执行文件的读入处理和分配内存的处理,它不会改变已打开文件和当前目录的数据。父进程的数据按原状保留。
执行文件的格式:程序执行文件从文件头开始依次由下述部分构成:文件头、代码、数据、符号表、重定位比特
系统调用exec:用户程序调用exec后将执行下述处理:
- 将传递给执行程序的参数存入缓冲区
- 将程序从块设备读取到内存
- 更新进程的虚拟地址空间
- 将存入缓冲区的参数压入栈
- 对SUID、SGID进行处理
- 对寄存器和信号进行初始化
5、进程的终止
系统调用exit的主要功能如下所示:
- 关闭打开的文件
- 将当前目录的参照计数器减1
- 释放代码段
- 将user结构体复制到交换空间
- 释放数据段
- 使进程进入僵尸状态
- 唤醒父进程或init进程
- 如果当前进程存在子进程,则将其设置为init进程的子进程
在进程的最后阶段执行swtch()切换执行进程
6、数据区域的扩展
系统调用break用来扩展或缩小数据段中数据区域的长度,供用户程序调用的C语言库函数malloc()等使用break实现对堆区域的扩展等操作
7、管理内存和交换空间
map结构体:内核利用map结构体对物理内存和交换空间的未使用区域进行管理
coremap[]用来管理物理内存,swapmap[]用来管理交换空间
mfree()用来释放物理内存和交换空间