合肥网站网站建设,电子商务网站开发教程,徐州有哪些制作网站的公司,中国设计之家官网文章目录 前言其他篇章参考链接0. 前置准备1. System call tracing (moderate)1.1 简单分析1.2 Hint 11.3 Hint 21.4 Hint 31.5 Hint 41.6 Hint 51.7 测试 2. Sysinfo (moderate)2.1 声明2.2 实现2.2.1 框架2.2.2 用户态与内核态交互2.2.3 计算空闲内存的大小2.2.4 计算非UNUSE… 文章目录 前言其他篇章参考链接0. 前置准备1. System call tracing (moderate)1.1 简单分析1.2 Hint 11.3 Hint 21.4 Hint 31.5 Hint 41.6 Hint 51.7 测试 2. Sysinfo (moderate)2.1 声明2.2 实现2.2.1 框架2.2.2 用户态与内核态交互2.2.3 计算空闲内存的大小2.2.4 计算非UNUSED进程的数量 2.3 测试 3. 总测试 前言
这个lab主要介绍了用户态到内核态的系统调用做了什么并让我们照猫画虎完成了两个系统调用的实现。
其他篇章
环境搭建 Lab1: Utilities Lab2: System calls
参考链接
官网链接 xv6手册链接这个挺重要的建议做lab之前最好读一读。 xv6手册中文版这是几位先辈们的辛勤奉献来的呀再习惯英文文档阅读我还是更喜欢中文一点开源无敌 OSTEP对OS不熟悉的同学做之前可以看一下这本经典书籍写得很好也有中文版实体书。 官方文档
0. 前置准备
很惭愧以前github用得少这一步折腾了老半天我再说一遍我个人的开发流程——先在windows下git一个本地仓库然后用VS编辑写完后git push上去在WSL的对应地方git pull下来然后编译运行。
前面环境配置中我为了连接到我个人的远程仓库是直接把原本的远程仓库删了的然后lab1做完做到lab2发现这个lab整体不是循序渐进的而是彼此分离的每个实验需要选择相应的分支因此就要重新弄一下 git remote add base git://g.csail.mit.edu/xv6-labs-2022git fetch basegit checkout syscallgit push --set-upstream origin syscall当然别忘了加.gitignore
1. System call tracing (moderate)
1.1 简单分析
gdb教学我就不说了看看这个task。 先简单研究一下我们需求的这个trace是干什么的吧trace顾名思义tracing追踪、寻迹的意思比如ray tracing就是光线追踪这个命令接受一个传参mask内涵是一个掩码每一位对应一个系统调用的一个序号比如传入32代表 32 1SYS_read2147483647 代表追踪所有syscall具体的这些值定义在了kernel/syscall.h里我们待会也会写 初步了解之后就写实现吧这个task按照hint的步骤来很清晰
1.2 Hint 1 Add $U/_trace to UPROGS in Makefile 首先添加makefile司空见惯了。
1.3 Hint 2 Run make qemu and you will see that the compiler cannot compile user/trace.c, because the user-space stubs for the system call don’t exist yet: add a prototype for the system call to user/user.h, a stub to user/usys.pl, and a syscall number to kernel/syscall.h. The Makefile invokes the perl script user/usys.pl, which produces user/usys.S, the actual system call stubs, which use the RISC-V ecall instruction to transition to the kernel. Once you fix the compilation issues, run trace 32 grep hello README; it will fail because you haven’t implemented the system call in the kernel yet. 然后说这个时候make会找不到trace我们要在用户态user/user.h里加上trace的声明根据原文 It should take one argument, an integer “mask”, whose bits specify which system calls to trace. 可知这玩意应该接受一个int然后返回也是一个int返回值其实不影响来着 然后我们在user/usys.pl下添加这么一行这是个Perl脚本即使没有用过Perl的同学应该也能看出来这里的意思是声明了一个trace系统调用的入口再通过上文展开为我们在usys.S中生成一段汇编代码。 然后在内核syscall.h中给它注册一个number
1.4 Hint 3 Add a sys_trace() function in kernel/sysproc.c that implements the new system call by remembering its argument in a new variable in the proc structure (see kernel/proc.h). The functions to retrieve system call arguments from user space are in kernel/syscall.c, and you can see examples of their use in kernel/sysproc.c. 然后模仿着添加原型 这里简单解释一下后面这个syscalls数组可能很多人没有看懂这首先这是个static的不用说然后这是个函数指针的数组我一向很反感那些什么数组指针指针数组混着说的直接说成装指针的数组不就一目了然了吗函数返回值为uint64参数为void显然是为上面extern的那些函数准备的东西这些都比较简单后面的是个小feature了它本身叫作指派初始化器Designated Initializers来自C99意思就是给方括号里的那一位初始化为右边的值 但是可以看到C99的指派初始化器的形式是[N] expr的中间需要一个等号连接这里没有它是来自GCC私货原文出现在介绍指定初始化器的时候An alternative syntax for this that has been obsolete since GCC 2.5 but GCC still accepts is to write ‘[index]’ before the element value, with no ‘’. 意味着大家在自己使用时加个等号是更符合standard的写法。
然后叫我们仿照着kernel/sysproc.c里的其他函数给trace写一个定义进去
uint64
sys_trace(void)
{return 0;
}使用argint从寄存器取出用户传入的参数 int mask;argint(0, mask); // 保存用户传入的参数然后我们要把接到的这个mask保存到进程的元数据中根据原文Add a sys_trace() function in kernel/sysproc.c that implements the new system call by remembering its argument in a new variable in the proc structure (see kernel/proc.h). T 我们在kernel/proc.h中可以找到一个结构体struct proc 很显然这个结构体记录着一些元数据我们在这个基础上再添加一条承载mask的 int traceMask; // 用于接收trace的mask显然每一个进程都有一个独属于自己的proc对象我们可以通过myproc()来获取这个对象的指针就此我们可以完成我们的sys_trace定义
uint64
sys_trace(void)
{argint(0, myproc()-mask); // 尝试从用户空间读取参数return 0;
}1.5 Hint 4 Modify fork() (see kernel/proc.c) to copy the trace mask from the parent to the child process. 我们知道fork出的子进程会复制父进程的内存空间根据hint我们可以找到它的实现 可以看到这里明显是要做一个p到np的拷贝p指向的是父进程的proc对象np则应该是new proc的缩写了 我们这个mask的修改不需要持有锁因此只需要在alloc之后的合适时机将父进程的值赋出即可 既然提到了alloc这里刚好就可以想到一个问题——资源的分配与释放呢我们知道C语言访问未初始化变量的行为是UB那么我们默认状态下的mask进行初始化了吗在上面那张图里我们可以清晰地看到或者说猜到内核依赖allocproc分配内存依赖freeproc释放内存因此我们可以直接F12进去看一看实现 如图我们可以很容易地为mask初始化以及释放时赋0值。
1.6 Hint 5 Modify the syscall() function in kernel/syscall.c to print the trace output. You will need to add an array of syscall names to index into. 然后我们为syscall这个总体的函数实现我们的功能也就是前文中的那些打印 我们分析一下需要做的事情当我们进行了trace调用时我们应当追踪mask标记的所有调用并打印出4: syscall close - 0这样的内容不难看出打印内容分为三部分PID、系统调用的名称与系统调用的返回值其中pid我们可以通过读取proc来获取返回值实际在框架中都告诉你了 // and store its return value in p-trapframe-a0p-trapframe-a0 syscalls[num]();可以看到系统调用的返回值被保存在了寄存器a0中至于系统调用的名称呢C语言中没有反射我们就只好提前建立一张syscall的名称表再根据mask去寻址
// 系统调用的名称
static const char *syscallnames[] {
[SYS_fork] fork,
[SYS_exit] exit,
[SYS_wait] wait,
[SYS_pipe] pipe,
[SYS_read] read,
[SYS_kill] kill,
[SYS_exec] exec,
[SYS_fstat] fstat,
[SYS_chdir] chdir,
[SYS_dup] dup,
[SYS_getpid] getpid,
[SYS_sbrk] sbrk,
[SYS_sleep] sleep,
[SYS_uptime] uptime,
[SYS_open] open,
[SYS_write] write,
[SYS_mknod] mknod,
[SYS_unlink] unlink,
[SYS_link] link,
[SYS_mkdir] mkdir,
[SYS_close] close,
[SYS_trace] trace,
};搞清楚并完成了所有前置工作我们就可以开始写逻辑了最后的syscall函数代码很简单
void
syscall(void)
{int num;struct proc *p myproc();num p-trapframe-a7;if(num 0 num NELEM(syscalls) syscalls[num]) {// Use num to lookup the system call function for num, call it,// and store its return value in p-trapframe-a0p-trapframe-a0 syscalls[num]();if ((p-mask num) 1) { // 判断系统调用是否被跟踪printf(%d: syscall %s - %d\n,p-pid, syscallnames[num], p-trapframe-a0);}} else {printf(%d %s: unknown sys call %d\n,p-pid, p-name, num);p-trapframe-a0 -1;}
}
1.7 测试
到这里就基本完成了还是老规矩我们make qemu编译然后试一试文档中的几个命令
trace 32 grep hello READMEtrace 2147483647 grep hello READMEgrep hello READMEtrace 2 usertests forkforkfork # 这一条输入之后貌似要等一会才会出一大坨…
最后跑一下总体批分./grade-lab-syscall trace 成功通过
2. Sysinfo (moderate)
然后让我们来完成一下task2这个是也是添加一个系统调用叫sysinfo 我们先搞清楚这个调用是干啥的从介绍可以看到这个sysinfo接收一个struct sysinfo的指针我们就是要写这个指针指向的对象怎么写呢就是将空闲的字节数存到对象里的freemem字段将state不为UNUSED的进程数量写到nproc字段。
有一个初步的印象后就可以去写实现了整体思路和上文trace的步骤差不多
首先是增加$U/_sysinfotest\到Makefile:
2.1 声明
在user/user.h里加声明 syscall.h中 syscall.c中第三个是上面的那个名称表
2.2 实现
2.2.1 框架
写完了声明就可以写实现了实现我们依旧写在sysproc.c下
#include sysinfo.h // 由于要接收sysinfo类型的结构体我们先include一下uint64
sys_sysinfo(void)
{// TODO: 从用户态到内核态// TODO: 计算空闲内存的大小// TODO: 计算内存中非UNUSED的进程的数量// TODO: 从内核态到用户态return 0;
}关于具体实现文档提供了三个hint我们还是按照这三个hint的步骤去做就行了
2.2.2 用户态与内核态交互 sysinfo needs to copy a struct sysinfo back to user space; see sys_fstat() (kernel/sysfile.c) and filestat() (kernel/file.c) for examples of how to do that using copyout(). 首先依旧是获取入参hint给了我们两个参考范例我们可以看一看 可以看猜到这两个文件以struct stat类型为例子分别向我们展示了获取类型指针的方法以及将既存对象写入获取到的指针的方法分别使用argaddr与copyout函数实现因此我们可以依葫芦画瓢写出以下代码
uint64
sys_sysinfo(void)
{uint64 addr; // 指向sysinfo结构体的指针struct sysinfo info;argaddr(0, addr); // 尝试从用户空间读取参数// TODO: 计算空闲内存的大小// TODO: 计算内存中非UNUSED的进程的数量if (copyout(myproc()-pagetable, addr, (char *)info, sizeof(info)) 0) // 将内核空间的sysinfo结构体复制到用户空间return -1;return 0;
}2.2.3 计算空闲内存的大小 To collect the amount of free memory, add a function to kernel/kalloc.c hint提示我们想要计算空闲内存的大小需要在kalloc.c下添加一个函数通过观察该文件的内容我们不难发现这个文件主要负责维护一个名为kmem的对象这个名称应该是kernel memory的缩写这个结构体内部有一个一看就是一把自旋锁的lock字段和一个一看就是负责记录空闲page的链表的freelist字段通过综合观察我们可以知道freelist确实维护的是空闲页的数量因此我们想要找到空闲内存的总大小只需要遍历整个freelist就可以找到总共空闲页的数量而每个页有PGSIZE即4096个字节因此我们只需要将获得的页面数乘以PGSIZE即可于是不难写出以下代码
// 计算空闲内存大小
uint64
kfree_mem_cnt(void)
{struct run *r;uint64 cnt 0;acquire(kmem.lock); // 由于kmem.freelist是全局变量所以需要加锁r kmem.freelist;while(r) {cnt;r r-next;}release(kmem.lock);return cnt * PGSIZE;
}值得一提的是由于kmem是一个全局变量属于临界资源因此我们在访问时需要加锁。然后我们需要再kernel/defs.h下添加这个函数的声明才能为我们所调用 然后在我们的sysinfo中调用它
uint64
sys_sysinfo(void)
{uint64 addr; // 指向sysinfo结构体的指针struct sysinfo info;argaddr(0, addr); // 尝试从用户空间读取参数info.freemem kfree_mem_cnt(); // 获取内存中空闲的内存大小// TODO: 计算内存中非UNUSED的进程的数量if (copyout(myproc()-pagetable, addr, (char *)info, sizeof(info)) 0) // 将内核空间的sysinfo结构体复制到用户空间return -1;return 0;
}2.2.4 计算非UNUSED进程的数量 To collect the number of processes, add a function to kernel/proc.c 这个函数提醒我们写在kernel/proc.c中这个文件我们上一个task其实已经接触过了再来看一看吧。前文我们已经知道了每个进程的信息依赖proc结构体维护进一步阅读不难发现这里用一个全局数组来维护了我们的所有进程因此我们只需要遍历一遍这个数组然后给其中非空闲的进程计数即可。 同样值得一提的是我们翻阅struct proc的定义可以发现注释中提示了我们state属于临界资源访问需要加锁 综合上面的内容我们就可以比较轻松地写出如下代码
// 计算非空闲进程的数量
uint64
get_free_proc_num(void)
{uint64 num 0;for(struct proc* p proc; p proc[NPROC]; p){acquire(p-lock); // state是临界资源需要加锁if (p-state ! UNUSED)num;release(p-lock);}return num;
}我们同样需要为它在defs.h中添加声明以供外部调用 最后我们在sysinfo的实现中调用这个函数完成了最终步骤
uint64
sys_sysinfo(void)
{uint64 addr; // 指向sysinfo结构体的指针struct sysinfo info;argaddr(0, addr); // 尝试从用户空间读取参数info.freemem kfree_mem_cnt(); // 获取内存中空闲的内存大小info.nproc get_free_proc_num(); // 获取内存中非UNUSED的进程的数量if (copyout(myproc()-pagetable, addr, (char *)info, sizeof(info)) 0) // 将内核空间的sysinfo结构体复制到用户空间return -1;return 0;
}2.3 测试
同样的make qemu后按照文档中的提示运行sysinfotest成功 退出终端后运行./grade-lab-syscall sysinfo本地测试成功
3. 总测试
同样的我们需要在根目录下创建一个time.txt里面写上本次lab用时比如我这个lab不算写博客花了差不多4个小时我就写个4然后运行make grade跑到这一步的时候我发现gdb也叫我填一个东西在answers-syscall.txt里答案是usertrap()弄好后又出了个错误 Timeout! trace children: FAIL (30.7s) … 8: syscall fork - -1 7: syscall fork - -1 6: syscall fork - -1 9: syscall fork - -1 qemu-system-riscv64: terminating on signal 15 from pid 6958 (make) MISSING ‘^ALL TESTS PASSED’ QEMU output saved to xv6.out.trace_children 这个主要是由于WSL性能损失的原因之前文档也强调过这个问题了解决方法是自己手动改测试脚本gradelib.py放宽时间话说上面单独跑测试都25s过了总的测试居然过不了还得看运气呀 然后再跑make grade 搞定 文章转载自: http://www.morning.qdzqf.cn.gov.cn.qdzqf.cn http://www.morning.gxtbn.cn.gov.cn.gxtbn.cn http://www.morning.fqcdh.cn.gov.cn.fqcdh.cn http://www.morning.tthmg.cn.gov.cn.tthmg.cn http://www.morning.rfzbm.cn.gov.cn.rfzbm.cn http://www.morning.txysr.cn.gov.cn.txysr.cn http://www.morning.jjnry.cn.gov.cn.jjnry.cn http://www.morning.nrydm.cn.gov.cn.nrydm.cn http://www.morning.lsfrc.cn.gov.cn.lsfrc.cn http://www.morning.dfckx.cn.gov.cn.dfckx.cn http://www.morning.cpmfp.cn.gov.cn.cpmfp.cn http://www.morning.qfwzm.cn.gov.cn.qfwzm.cn http://www.morning.rjhts.cn.gov.cn.rjhts.cn http://www.morning.dkbgg.cn.gov.cn.dkbgg.cn http://www.morning.lkhfm.cn.gov.cn.lkhfm.cn http://www.morning.ktpzb.cn.gov.cn.ktpzb.cn http://www.morning.qrcxh.cn.gov.cn.qrcxh.cn http://www.morning.lmfmd.cn.gov.cn.lmfmd.cn http://www.morning.kpcdc.cn.gov.cn.kpcdc.cn http://www.morning.mlfgx.cn.gov.cn.mlfgx.cn http://www.morning.bpmtj.cn.gov.cn.bpmtj.cn http://www.morning.dygqq.cn.gov.cn.dygqq.cn http://www.morning.cyjjp.cn.gov.cn.cyjjp.cn http://www.morning.bybhj.cn.gov.cn.bybhj.cn http://www.morning.jbtlf.cn.gov.cn.jbtlf.cn http://www.morning.wwwghs.com.gov.cn.wwwghs.com http://www.morning.wfjrl.cn.gov.cn.wfjrl.cn http://www.morning.wnhsw.cn.gov.cn.wnhsw.cn http://www.morning.qdmdp.cn.gov.cn.qdmdp.cn http://www.morning.pbsqr.cn.gov.cn.pbsqr.cn http://www.morning.hxmqb.cn.gov.cn.hxmqb.cn http://www.morning.fmznd.cn.gov.cn.fmznd.cn http://www.morning.gqjwz.cn.gov.cn.gqjwz.cn http://www.morning.srnth.cn.gov.cn.srnth.cn http://www.morning.wqwbj.cn.gov.cn.wqwbj.cn http://www.morning.mrccd.cn.gov.cn.mrccd.cn http://www.morning.xstfp.cn.gov.cn.xstfp.cn http://www.morning.qsy36.cn.gov.cn.qsy36.cn http://www.morning.rbjth.cn.gov.cn.rbjth.cn http://www.morning.bfrff.cn.gov.cn.bfrff.cn http://www.morning.bprsd.cn.gov.cn.bprsd.cn http://www.morning.ylpwc.cn.gov.cn.ylpwc.cn http://www.morning.wpqcj.cn.gov.cn.wpqcj.cn http://www.morning.xzrbd.cn.gov.cn.xzrbd.cn http://www.morning.yzzfl.cn.gov.cn.yzzfl.cn http://www.morning.wtwhj.cn.gov.cn.wtwhj.cn http://www.morning.dxhdn.cn.gov.cn.dxhdn.cn http://www.morning.xmyrn.cn.gov.cn.xmyrn.cn http://www.morning.dzfwb.cn.gov.cn.dzfwb.cn http://www.morning.bzkgn.cn.gov.cn.bzkgn.cn http://www.morning.ymwnc.cn.gov.cn.ymwnc.cn http://www.morning.zlwg.cn.gov.cn.zlwg.cn http://www.morning.hghhy.cn.gov.cn.hghhy.cn http://www.morning.youprogrammer.cn.gov.cn.youprogrammer.cn http://www.morning.zlxrg.cn.gov.cn.zlxrg.cn http://www.morning.wkgyz.cn.gov.cn.wkgyz.cn http://www.morning.dhyqg.cn.gov.cn.dhyqg.cn http://www.morning.lthpr.cn.gov.cn.lthpr.cn http://www.morning.jjwt.cn.gov.cn.jjwt.cn http://www.morning.fdsbs.cn.gov.cn.fdsbs.cn http://www.morning.tnkwj.cn.gov.cn.tnkwj.cn http://www.morning.zzjpy.cn.gov.cn.zzjpy.cn http://www.morning.qyjqj.cn.gov.cn.qyjqj.cn http://www.morning.bqxxq.cn.gov.cn.bqxxq.cn http://www.morning.rzbcz.cn.gov.cn.rzbcz.cn http://www.morning.lchtb.cn.gov.cn.lchtb.cn http://www.morning.c7623.cn.gov.cn.c7623.cn http://www.morning.gwjnm.cn.gov.cn.gwjnm.cn http://www.morning.rknjx.cn.gov.cn.rknjx.cn http://www.morning.fbdtd.cn.gov.cn.fbdtd.cn http://www.morning.knwry.cn.gov.cn.knwry.cn http://www.morning.znnsk.cn.gov.cn.znnsk.cn http://www.morning.nhlyl.cn.gov.cn.nhlyl.cn http://www.morning.nytpt.cn.gov.cn.nytpt.cn http://www.morning.xxwfq.cn.gov.cn.xxwfq.cn http://www.morning.aishuxue.com.cn.gov.cn.aishuxue.com.cn http://www.morning.rtsd.cn.gov.cn.rtsd.cn http://www.morning.hkpn.cn.gov.cn.hkpn.cn http://www.morning.tngdn.cn.gov.cn.tngdn.cn http://www.morning.3jiax.cn.gov.cn.3jiax.cn