操作系统实验Mit6.S801笔记 Lab1: Util

sleep

提示:

相关代码 user/echo.c, user/grep.c, user/rm.c。
参数错误提示。
atoi 字符串转整型数。
可以调用系统调用sleep。
kernel/sysproc.c 内核代码,看系统调用sleep的实现;user/user.h 对用户程序调用sleep的C定义;user/usys.S 从用户代码跳转到内核执行sleep。
main得调用exit()返回。
在Makefile中添加sleep,编译执行。(用文本编辑器打开Makefile进行修改)

sleep.c

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int main(int argc, char *argv[]){
  if(argc != 2){
    fprintf(2, "wrong parameters...\n");
    exit(1);
  }
  sleep(atoi(argv[1]));

  exit(0);
}

注:
1、exit(1)表示异常退出,在退出前可以给出一些提示信息,或在调试程序中察看出错原因。
2、exit(0)表示正常退出。

pingpong

要求:

编写一个程序,使用UNIX系统调用在两个进程之间通过一对管道“乒乓”一个字节,每个方向一个。父进程应该给子进程发送一个字节;子进程应该打印"<pid>: received ping",其中是它的进程ID,在父进程的管道上写字节,然后退出;父进程应该从子进程中读取字节,print“<pid>:recerved pong”。并退出。你的解决方案应该在user/pingpong.c文件中。

提示:

使用pipe创建管道。利接收一个长度为2的数组,数组下标0为读端、1为写端;
使用fork创建子进程,子进程和父进程一样,但之后可以让它们执行不同代码。返回值为0则是子进程,否则是父进程。
使用read从管道读取,使用write向管道写入。
在Makefile中将程序添加到UPROGS。
xv6上的用户程序只有一组有限的库函数可用,可以在user/user中看到该列表。资源(除了系统调用)在user/ulib.c,user/ printf.c,user/ umalloc.c。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int main(void){
    int p1[2],p2[2];//0为读端,1为写端
    char buf,msg='0';
    
    //两个管道 int pipe(int*);
    pipe(p1);  //p1 父进程写,子进程读 
    pipe(p2); //p2 子进程写,父进程读 
    
    if(fork()==0){//是子进程
    	close(p1[1]);
    	close(p2[0]);//关闭用不到的父进程一侧的读写端
        read(p1[0],&buf,1);//从p1[0]读到buffer
        printf("%d: received ping\n",getpid());
        write(p2[1],&msg,1);//将msg写入p2[1]
    }else{
    	close(p1[0]);
    	close(p2[1]);
        write(p1[1],&msg,1);
        read(p2[0],&buf,1);
        printf("%d: received pong\n",getpid());
    }
    exit(0);
}

顺序是父进程写,子进程读,子进程写,父进程读。
因此在子进程中先read再write,在父进程中先write再read。

primes

要求:

使用pipe和fork来设置管道。第一个进程将数字2到35输入到管道。对于每个质数,需要创建一个进程,该进程通过一个管道从它的左邻居读取数据,通过另一个管道向它的右邻居写入数据。由于xv6的文件描述符和进程数量有限,第一个进程可以在数字35时停止。

提示:

请小心关闭进程不需要的文件描述符,否则在第一个进程到达35之前,您的程序将耗尽xv6资源。
一旦第一个进程达到35,它应该等待直到整个管道终止,包括所有的子进程、孙进程。因此,主质数进程应该只在所有结果输出完成后退出,并且在所有其他质数进程退出后退出。
当管道的写端关闭时,read返回0。
直接将32位(4字节)整型写入管道是最简单的,而不是使用格式化的ASCIl I/O。
您应该仅在需要时在管道中创建进程。
在Makefile中将程序添加到UPROGS。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

void func(int size, int* p1) {
    int p2[2];
    int counter = 0;
    char buffer[4];
    int nums[34];
    int prime;
    pipe(p2);//创建管道
    read(p1[0], buffer, 4);
    prime = *((int*)buffer);
    printf("prime %d\n", prime);
    if (size == 1) {
        return;
    }
    size--;
    for (int i = 0; i < size; i++) {
        read(p1[0], buffer, 4);
        int temp = *((int*)buffer);
        if (temp % prime != 0) {
            nums[counter] = temp;
            counter++;
        }
    }
    close(p1[0]);
    for (int j = 0; j < counter; j++) {
        write(p2[1], (char*)(nums + j), 4);
    }
    if (fork() == 0) {
        func(counter, p2);
        exit(0);
    }
    wait(0);
}

int  main() {
    int p[2];
    pipe(p);//创建管道
    for (int i = 0; i < 34; i++) {
        int temp = i + 2;
        write(p[1], (char*)(&temp), 4);
    }
    if (fork() == 0) {
        func(34, p);//传入2-35
        exit(0);
    }
    wait(0);
    exit(0);
}

find

要求:

编写UNIX find程序的一个简单版本:查找具有特定名称的目录树中的所有文件。您的解决方案应该在user/ find.c文件中。

提示:

查看user/ls.c以了解如何读取目录。
使用递归查找到子目录。
不要递归到“.”和“..”
对文件系统的更改在qemu运行期间保持不变;要获得一个干净的文件系统,请运行make clean,然后make qemu。
你需要使用C字符串。看一下K&R (C的书),例如第5.5节。
注意==不像Python那样比较字符串。使用strcmp()来替代。
在Makefile中将程序添加到UPROGS。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
#include "kernel/fcntl.h"

char* fmtname(char* path) {
    char* p;
    for (p = path + strlen(path); p >= path && *p != '/'; p--);// 找到/后的第一个单词
    p++;
    return p;
}

void find(char* path, char* fileName) {
    char buf[512], * p;
    int fd;
    struct dirent de;
    struct stat st;
    if ((fd = open(path, 0)) < 0) {
        fprintf(2, "find: cannot open %s\n", path);
        return;
    }
    if (fstat(fd, &st) < 0) {
        fprintf(2, "find: cannot stat %s\n", path);
        close(fd);
        return;
    }
    switch (st.type) {
    case T_FILE:
        if (strcmp(fmtname(path), fileName) == 0) {
            printf("%s\n", path);
        }
        break;
    case T_DIR:
        if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {//DIRSIZ在kernel/fs.h中被设置为14
            printf("find: path too long\n");
            break;
        }
        strcpy(buf, path);
        p = buf + strlen(buf);
        *p++ = '/';
        while (read(fd, &de, sizeof(de)) == sizeof(de)) {
            if (de.inum == 0 || strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0)
                continue;
            memmove(p, de.name, DIRSIZ);
            p[DIRSIZ] = 0;
            find(buf, fileName);
        }
        break;
    }
    close(fd);
}

int main(int argc, char* argv[])
{
    if (argc != 3) {
        printf("find: find <path> <fileName>\n");
        exit(1);
    }
    else {
        find(argv[1], argv[2]);
        exit(0);
    }
}

绝大部分代码都可以参考user/ls.c

xargs

要求:

编写一个UNIX xargs程序的简单版本:从标准输入中读取一些行,并为每一行运行一个命令,将该行作为命令的参数提供。 您的解决方案应该在user/xargs.c文件中。

提示:

使用fork和exec在每一行输入上调用命令。 在父进程中使用wait命令来等待子进程完成命令。
要读取单独的输入行,每次读取一个字符,直到出现换行符(’\n’)。
kernel/param.h声明了MAXARG,如果你需要声明一个argv数组,这可能会很有用。
在Makefile中将该程序添加到UPROGS中。
对文件系统的更改在qemu运行期间保持不变; 要获得一个干净的文件系统,请运行make clean,然后make qemu。

#include "kernel/types.h"
#include "user/user.h"
#include "kernel/param.h"

int main(int argc, char* argv[]) {
    int argcount = 0;
    char block[32];//按块读取
    char curarg[95];//参数
    char* p = curarg;//下一个参数的起始位置
    char* lineSplit[MAXARG];//MAXARG为32定义在kernel/param.h
    for (int i = 1; i < argc; i++) {
        lineSplit[argcount] = argv[i];//xarg 后的命令
        argcount++;
    }
    int k, m = 0;
    while ((k = read(0, block, sizeof(block))) > 0) {//读标准输入
        for (int j = 0; j < k; j++) {
            if (block[j] == '\n') {
                curarg[m] = 0;//字符串补0
                lineSplit[argcount] = p;
                argcount++;
                lineSplit[argcount] = 0;//参数组最后补0
                if (fork() == 0) {//子进程
                    exec(argv[1], lineSplit);//执行命令 exec接收两个参数,第一个参数为命令cmd,第二个参数为一个数组,该数组的格式必须为{cmd, “arg1”, “arg2”, …, 0}
                }
                wait(0);
                m = 0;
                p = curarg;
                argcount = argc - 1;
            }
            else if (block[j] == ' ') {
                curarg[m] = 0;
                m++;
                lineSplit[argcount] = p;
                argcount++;
                p = &curarg[m];
            }
            else {
                curarg[m] = block[j];
                m++;
            }
        }
    }
    exit(0);
}

命令行中 | 表示管道,上一条命令的标准输出,作为下一条命令的标准输入。有 | 时,argc、argv都从 | 后开始算。

测试:

提交测试:./grade-lab-util

在这里插入图片描述

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值