前言
本实验需要编写一些用户程序,执行系统调用来达成目标。作为第一个实验,本次实验内容比较简单,主要内容是展示用户如何调用操作系统的接口,即system call,在下一个实验中将详细展示系统调用的工作流程。
本次实验的学习目标是:
-
学习并理解用户使用shell执行命令时的具体过程
- 命令的参数如何被进程使用
-
对Unix的进程间通信方式之一pipe有基础了解
- 为什么用户进程要使用OS提供的IPC进行通信?
-
了解Unix中的file description,理解Unix中”一切皆文件“的理念
-
初步了解make项目以及Makefile
实验原文:Lab: Xv6 and Unix utilities (mit.edu)
前置工作
进入工作文件夹下,输入以下命令
git checkout util #切换到util分支,对应本实验
git clean -xfd #清除无关文件(未追踪的、忽略的文件和文件夹)
git checkout -b solveutil #新建一个solveutil分支,来记录自己的编程过程
sleep (easy)
任务
写一个用户程序sleep,执行系统调用来实现休眠。
$ make qemu
...
init: starting sh
$ sleep 10
(nothing happens for a little while)
$
提示
- 观察
user/grep.c
等文件来学习命令行参数如何传入程序。 - 将
sleep.c
添加进Makefile
中的UPROGS。(添加完后点击Makefile
右上角图标重新加载make项目才能将sleep.c
加入索引) - 在用户没有给出sleep的参数时打印错误信息。
- 使用
atoi
函数将命令行参数由字符串转为整形。 - 确保
main
函数调用了exit
函数来退出程序。
源码
//sleep.c
#include "kernel/types.h"
#include "user/user.h"
int
main(int argc,char* argv[]){
if(argc != 2){
fprintf(2, "Usage: sleep ticks\n");//stderr的文件描述符的值为2
exit(1);
}
int ticks = atoi(argv[1]);
sleep(ticks);
exit(0);
}
pingpong(easy)
任务
写一个用户程序pingpong,实现两个进程间的数据传递。
$ make qemu
...
init: starting sh
$ pingpong
4: received ping
3: received pong
$
提示
- 使用
pipe
建立管道。
关于管道的理解可以看这篇博文:Linux系统编程pipe()
- 使用
fork
创建子进程。 - 使用
read
和write
对管道进行读和写。 - 使用
getpid
获取当前进程的pid。
源码
//pingpong.c
#include "kernel/types.h"
#include "user/user.h"
int
main() {
int p1[2];//parent->child
int p2[2];//child->parent
pipe(p1);
pipe(p2);
if (fork() == 0) {
//child
char buffer[] = {
'y'};
read(p1[0],buffer,sizeof(buffer));
fprintf(2,"%d: received ping\n",getpid());
write(p2[1],buffer,sizeof(buffer));