本系列文章为MIT6.S081的学习笔记,包含了参考手册、课程、实验三部分的内容,前面的系列文章链接如下
操作系统MIT6.S081:[xv6参考手册第1章]->操作系统接口
操作系统MIT6.S081:P1->Introduction and examples
文章目录
一、sleep
1.1 实验描述
实验目的
为xv6系统实现UNIX的sleep程序。你的sleep程序应该使当前进程暂停指定的时钟周期数,时钟周期数由用户指定。例如执行sleep 100,则当前进程暂停,等待100个时钟周期后才继续执行。时钟周期是xv6内核定义的时间概念,来自计时器芯片的两次中断之间的时间。你的解决方案包含应该在文件user/sleep.c中。
实验提示
1、在开始编程之前,阅读配套手册的第一章。
2、可以参考/user目录下的其他程序(如echo.c、grep.c和rm.c),了解如何获取和传递给程序相应的命令行参数.
3、如果用户传入参数有误,即没有传入参数或者传入多个参数,程序应该能打印出错误信息。
4、通过字符串传递命令行参数。可以通过atoi(详情见user/ulib.c)函数将字符串转换为整数
5、使用系统调用sleep。
6、有关实现sleep系统调用的xv6内核代码(sys_sleep),请参考kernel/sysproc.c。有关可从用户程序调用sleep的C 定义在user/user.h中,以及有关汇编代码的user/usys.S 从用户代码跳转到内核进行睡眠。
7、确保main函数调用exit()以退出程序。
4、实现的程序应该命名为sleep.c并最后放入user目录下。
8、将你的sleep程序添加到Makefile的UPROGS中。只有这步完成后,make qemu才能编译你写的程序,你才能在shell中运行这个程序。
9、通过Kernighan和Ritchie’s的The C programming language(第2版)学习C语言
测试条件
①在xv6的shell中运行该程序
②如果通过上述命令使程序停止10个时钟周期,则说明你的方案是正确的。运行make grade查看你是否通过了测试。
注:make grade会运行所有测试程序,如果你只想测试当前程序,可以指定要运行的程序,通过以下命令:
你也可以通过下面这条命令测试当前程序
1.2 实验思路
头文件
系统调用sleep的声明在user/user.h中。
user.h中的一些系统调用函数声明使用了一些数据类型,这些数据类型在kerner/type.h中声明。
命令行参数判断
如果命令行参数有错误,则通过write或fprintf输出错误信息
然后通过exit退出
执行sleep操作
①通过atoi将argv[1]参数转换为整数
②调用系统调用函数sleep执行中断操作
③通过exit退出
1.3 实验代码
整体代码如下
#include "kernel/types.h" //一些数据类型声明
#include "user/user.h" //用户可以使用的系统调用声明
int main(int argc, char* argv[])
{
if (argc != 2){
//命令行参数不为2
//也可以调用write
fprintf(2, "Usage: sleep <num> \n"); //将提示信息写入标准错误端
exit(1); //退出,参数1表示非正常退出
}
int number = atoi(argv[1]); //将字符串转为整数
sleep(number); //调用系统调用sleep
exit(0); //正常退出
}
测试
①首先在makefile文件中添加
$U/_sleep\
②然后sudo make qemu进入xv6
③在终端中测试sleep
④退出xv6,在shell中通过./grade-lab-util sleep测试
注: 如果运行命令./grade-lab-util sleep报/usr/bin/env: ‘python’: No such file or directory错误,可能是因为没装python2或者装的是python3,使用命令vim grade-lab-util,把第一行的python改为python3。如果系统没装python3,则通过命令sudo apt-get install python3安装python3。
二、pingpong
2.1 实验描述
实验目的
使用UNIX系统调用编写一个程序pingpong,在一对管道上实现两个进程之间的通信。父进程通过第一个管道给子进程发送一个信息“ping”,子进程接收父进程的信息后打印
"<pid>: received ping",其中pid是子进程的ID。然后子进程通过另一个管道发送一个信息“pong”给父进程,父进程接收子进程的信息然后打印"<pid>: received pong",其中pid是父进程的ID,然后退出。
实验提示
1、通过
pipe创建一个管道
2、通过fork创建一个子进程
3、通过read从管道中读取数据,通过write向管道中写入数据
4、通过getpid获取当前进程的pid
5、将程序添加到Makefile文件中的UPROGS中
6、xv6上的用户程序拥有一些库函数可供使用,你可以在user/user.h中查看这些函数对应的列表。除系统调用外其他函数的源代码位于user/ulib.c、user/printf.c和user/umalloc.c中。
测试条件
在shell中运行程序并将得到以下结果
如果你的程序在两个进程间传递信息并产生以上结果,则说明你的方案正确。
2.2 实验思路
初始化
创建父进程、子进程的文件描述符数组
父进程、子进程创建管道
创建缓冲区字符数组buf,存放要传递的信息
通过fork创建子进程
父进程
①关闭父进程管道的读取端
②将"ping"通过父进程管道的写入端进行写入
③关闭子进程管道的写入端
④从子进程管道的读取端读取信息到buf中
⑤打印收到的信息
子进程
①关闭父进程管道的写入端
②子进程从父进程管道的读取端读取数据
③打印收到的信息
④关闭子进程管道的读取端
⑤将子进程管道的写入端信息写入buf中
2.3 实验代码
整体代码如下
#include "kernel/types.h"
#include "user/user.h"
int main()
{
int pfd[2]; //父进程的文件描述符数组
int cfd[2]; //子进程的文件描述符数组
pipe(pfd); //父进程创建管道
pipe(cfd); //子进程创建管道
char buf[10]; //缓冲区字符数组,存放传递的信息
int pid = fork(); //创建子进程
if(pid < 0){
fprintf(0, "fork error\n");
exit(1); //创建子进程错误
}
else if(pid == 0){
//子进程
close(pfd[1]); //关闭父进程管道的写入端
read(pfd[0], buf, 4); //将父进程管道的读取端数据读取到buf中
printf("%d: received %s\n", getpid(), buf); //打印收到的信息
close(cfd[0]); //关闭子进程管道的读取端
write(cfd[1],"pong", 4); //将"pong"写入子进程管道的写入端
}else{
//父进程
close(pfd[0]); //关闭父进程管道的读取端
write(pfd[1], "ping", 4); //将"ping"写入父进程管道的写入端
close(cfd[1]); //关闭子进程管道的写入端
read(cfd[0], buf, 4); //将子进程管道的读取端信息读取到buf中
printf("%d: received %s\n", getpid(), buf); //打印收到的信息
}
exit(0); //正常退出
return 0;
}
测试
①首先在makefile文件中添加
$U/_pingpong\
②然后sudo make qemu进入xv6
③在终端中测试pingpong

本文介绍MIT6.S081操作系统课程的五个实验:sleep、pingpong、primes、find和xargs。详细阐述每个实验的目的、思路及代码实现。









最低0.47元/天 解锁文章
2350

被折叠的 条评论
为什么被折叠?



