posix-process
posix-process主要提供了POSIX中要求的大部分关于进程、线程管理的结构体与函数。
文件结构
1 | posix-process/ |
数据结构
该结构体位于musl-imported/include/sys/resource.h中
该结构体主要定义了对资源的使用限制
1 | struct rusage { |
- ru_utime : 在用户态下执行程序的总时间,以timeval结构体表示。
- ru_stime : 在内核态下执行程序的总时间,以timeval结构体表示。
- ru_maxrss : 使用的最大驻留集大小(以KB为单位)。
- ru_ixrss : TODO:在Linux中未使用,在Unikraft中未知。
- ru_idrss : TODO:在Linux中未使用,在Unikraft中未知。
- ru_isrss : TODO:在Linux中未使用,在Unikraft中未知。
- ru_minflt : minor page fault(次要的缺页错误)。没有任何IO服务的缺页异常。即请求的页面已在内存中,但是没有向MMU注册,此时需要MMU建立映射关系。(注释中提到,没有IO的异常服务,应是指,不需要从外存读取到物理内存中)。
- ru_majflt : major page fault(主要的缺页错误)。即请求的页面不在物理内存中,此时指示CPU从外存读取对应内容到物理内存中。
- ru_nswap : 向主存交换的次数
- ru_inblock : 文件系统需要输入操作的次数
- ru_oublock : 文件系统需要输出操作的次数
- ru_msgsnd : 发送消息的次数
- ru_msgrcv : 接受消息的次数
- ru_nsignals : 接受信号量的次数
- ru_nvcsw : 自愿的上下文切换
- ru_nivcsw : 非自愿的上下文切换
- __reserved :
该结构体定义了对资源数量的限制
1 | struct rlimit { |
- rlim_cur : 软限制,允许程序在一定时间内超过该限制。
- rlim_max : 硬限制,在任何情况都不允许程序超过该限制。
该结构体定义了对线程在内存区域的限制
1 | struct prctl_mm_map { |
具体可以参考手册prctl
提供的接口
prctl
在Linux中,prctl提供了一系列操作线程/进程的方法。
1 |
|
调用prctl()时,第一个参数决定做什么,后面的参数依赖于第一个参数。参数说明如下所示(以缩进代表参数次序)。下面举几个例子加以说明。
- PR_CAP_AMBIENT : 根据arg2的值改变或者读取thread的环境能力集(the ambient capability set)。
- PR_CAP_AMBIENT_RAISE : arg3指定的能力被添加到环境能力集中,指定的功能必须在已经存在于进程允许且可继承的集合中。
- PR_CAP_AMBIENT_LOWER : arg3指定的能力将从集合中删除。
- PR_CAP_AMBIENT_IS_SET: 判断arg3指定的能力是否在环境集中。
- PR_CAP_AMBIENT_CLEAR_ALL :所有能力从环境集中删除。
arg4与arg5需要设置为0。
- PR_SET_CHILD_SUBREAPER : 用于收养孤儿线程,让当前进程充当init线程的功能,使其收养该线程树下的所有线程。
- PR_SET_FP_MODE : 允许用户从用户空间操控浮点模式。
- PR_SET_NO_NEW_PRIVS: 将调用线程的no_new_privs属性设置为arg2。如果no_new_privs设置为1时,禁止调用系统调用execve()。且该选项一旦设置,无法被取消;还会通过clone和fork传递给子进程。
- PR_SET_PDEATHSIG : 将调用进程的父线程死亡信号设置为arg2(范围为1~MaxSig, 0代表清除信号)。对于Linux而言,父指的是创建该进程的父线程,对于Unikraft还需再深入了解。
- PR_SET_NAME : 设定线程的名字。
exec函数族
在Unikraft中,提供了六个以exec开头的函数,以及两个对参数进行处理的函数。以及一个系统调用execve。查阅后发现,exec函数基本是尚未实现的。
1 | int execvpe(const char *file, char *const argv[], char *const envp[]); |
其中在exec函数族中大量调用了以下两个函数,但是分析发现,以下函数仅仅是在调用内部的print函数。
1 |
|
声明但未实现的函数
除了prctl以及exec函数族以外,笔者整理了posix-process中提供了声明但是未实现的函数。以供日后参考。
1 | int system(const char *command); |
已实现的函数
1 | // 由于Unikraft特性导致实现很简单或者是无法实现。 |
页面管理
MMU
MMU(Memory Management Unit),又叫内存管理单元,MMU是分页技术的硬件实现。CPU通过MMU,将虚拟地址VA转化为物理地址PA。
至于MMU采取的地址翻译规则取决于虚拟内存采用的组织机制,包括:分段机制和分页机制。CPU、MMU、主存的交互过程如下图所示,cache并未在图中画出。
TLB是MMU的一部分,TLB的本质就是cache,MMU在进行地址翻译前,会去查询TLB。如果TLB命中,那么就直接获取VA对应的PA,然后访问主存。否则进行地址翻译过程。
因此缺页中断也就分为了两种
- 软缺页中断:此时进程所需要的页面已经在物理内存中,Page Fault Handler会让MMU建立对应的映射关系。
- 硬缺页中断:此时进程所需要的页面不在物理内存中,此时将从磁盘中读取对应的页面,同时建立映射关系。
缺页中断发生后,Page Fault Handler会判断缺页类型,然后进行缺页处理。与其他中断不同的是,Page Fault Handler在处理完后,会重新执行发生缺页中断的语句。