mits081 lab1

mitS081 lab1 Xv6 and Unix utilities

sleep

Implement the UNIX program sleep for xv6; your sleep should pause for a user-specified number of ticks. (A tick is a notion of time defined by the xv6 kernel, namely the time between two interrupts from the timer chip.) Your solution should be in the file user/sleep.c.

Some hints:
Look at some of the other programs in user/ to see how you can obtain the command-line arguments passed to a program. If the user forgets to pass an argument, sleep should print an error message.
The command-line argument is passed as a string; you can convert it to an integer using atoi (see user/ulib.c).
Use the system call sleep (see user/usys.S and kernel/sysproc.c).
Make sure main calls exit() in order to exit your program.
Add the program to UPROGS in Makefile and compile user programs by typing make fs.img.
Look at Kernighan and Ritchie’s book The C programming language (second edition) (K&R) to learn about C.
Run the program from the xv6 shell:

  $ make qemu
  ...
  init: starting sh
  $ sleep 10
  (nothing happens for a little while)
  $

Your solution is correct, if your program behaves as shown above.

Optional: write an uptime program that prints the uptime in terms of ticks using the uptime system call.

代码:

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

int
main(int argc, char *argv[])
{
    int time = atoi(argv[1]);
    sleep(time);
    exit();
}

pingpong

Write a program that uses UNIX system calls to ``ping-pong’’ a byte between two processes over a pair of pipes, one for each direction. The parent sends by writing a byte to parent_fd[1] and the child receives it by reading from parent_fd[0]. After receiving a byte from parent, the child responds with its own byte by writing to child_fd[1], which the parent then reads. Your solution should be in the file user/pingpong.c.

Some hints:
Use pipe to create a pipe.
Use fork to create a child.
Use read to read from the pipe, and write to write to the pipe.
Run the program from the xv6 shell and it should produce the following output:

$ make qemu
...
init: starting sh
$ pingpong
4: received ping
3: received pong
$

Your solution is correct, if your program behaves as shown above. The number before “:” is the process id of the process printing the output. You can get the process id by calling the system call getpid.

代码:

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

int
main(int argc, char *argv[])
{
    int parent_fd[2],child_fd[2];
    pipe(parent_fd);pipe(child_fd);
    int pid = fork();
    if(pid > 0){//父进程
        write(parent_fd[1],"ping",4);
        //printf("父进程id:%d\n",getpid());
        char receive[100];
        read(child_fd[0],receive,4);
        printf("%d: received %s\n",getpid(),receive);
    }else if(pid == 0){//子进程
        
        char receive[100];
        read(parent_fd[0],receive,4);
        printf("%d: received %s\n",getpid(),receive);

        write(child_fd[1],"pong",4);
    }else{
        printf("error !\n");
        exit();
    }
    exit();
}

primes

Write a concurrent version of prime sieve using pipes. This idea is due to Doug McIlroy, inventor of Unix pipes. The picture halfway down this page and the surrounding text explain how to do it. Your solution should be in the file user/primes.c.
Your goal is to use pipe and fork to set up the pipeline. The first process feeds the numbers 2 through 35 into the pipeline. For each prime number, you will arrange to create one process that reads from its left neighbor over a pipe and writes to its right neighbor over another pipe. Since xv6 has limited number of file descriptors and processes, the first process can stop at 35.

Some hints:
Be careful to close file descriptors that a process doesn’t need, because otherwise your program will run xv6 out of resources before the first process reaches 35.
Once the first process reaches 35, you should arrange that the pipeline terminates cleanly, including all children (Hint: read will return an end-of-file when the write-side of the pipe is closed).
It’s simplest to directly write 32-bit ints to the pipes, rather than using formatted ASCII I/O.
You should create the processes in the pipeline as they are needed.
Your solution is correct if it produces the following output:

$ make qemu
...
init: starting sh
$ primes
prime 2
prime 3
prime 5
prime 7
prime 11
prime 13
prime 17
prime 19
prime 23
prime 29
prime 31
$

代码:

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

/*
子进程不断将素数送到管道,父进程递归从管道取出素数并且输出
当管道的写端没有关闭时,并且管道中没有数据时,read会被阻塞
当管道的写端关闭时,并且管道中没有数据时,read返回0
*/
void dfs(int fd[]){
    close(fd[1]);
    int x;
    read(fd[0],&x,sizeof(int));
    if(x == 0)return ;
    printf("prime %d\n",x);
    int fd2[2];pipe(fd2);
    int pid = fork();
    if(pid > 0){
        wait();
        dfs(fd2);
    }else{
        int t;read(fd[0],&t,sizeof(int));
        write(fd2[1],&t,sizeof(int));
        // printf("将%d写入新管道\n",t);
        while(read(fd[0],&x,sizeof(int)) != 0){
            if(x % t != 0){
                // printf("将%d写入新管道\n",x);
                write(fd2[1],&x,sizeof(int));
            }
        }
    }
}
int main(int argc, char *argv[]){
    int fd[2];pipe(fd);
    int pid = fork();
    if(pid > 0){
        wait();
        dfs(fd);
    }else{
        int x = 2;
        write(fd[1],&x,sizeof(int));
        for(int i = 2; i <= 35; i++){
            if(i % 2 != 0){
                write(fd[1],&i,sizeof(int));
            }
        }
    }
    exit();
}

find

Write a simple version of the UNIX find program: find all the files in a directory tree whose name matches a string. Your solution should be in the file user/find.c.

Some hints:
Look at user/ls.c to see how to read directories.
Use recursion to allow find to descend into sub-directories.
Don’t recurse into “.” and “…”.
Changes to the file system persist across runs of qemu; to get a clean file system run make clean and then make qemu.
You’ll need to use C strings. Have a look at K&R (the C book), for example Section 5.5.
Optional: support regular expressions in name matching. grep.c has some primitive support for regular expressions.

Your solution is correct if produces the following output (when the file system contains a file a/b):

$ make qemu
...
init: starting sh
$ mkdir a
$ echo > a/b
$ find . b
./a/b
$ 

代码

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

char buf[512];
void dfs(char *p,char s[]){
  int fd = open(buf, 0);
  p = buf+strlen(buf);
  *p++ = '/';
  struct dirent de;
  struct stat st;
  while(read(fd, &de, sizeof(de)) == sizeof(de)){
        if(de.inum == 0)
          continue;
        if(strcmp(de.name,".") == 0 || strcmp(de.name,"..") == 0)continue;
        memmove(p, de.name, DIRSIZ);
        p[DIRSIZ] = 0;
        if(strcmp(de.name,s) == 0){
          //write(0,buf,sizeof(buf));
          printf("%s\n", buf);
        }
        if(stat(buf, &st) < 0){
          printf("ls: cannot stat %s\n", buf);
          continue;
        }
        if(st.type == T_DIR){
          //printf("%s\n",de.name);
          dfs(p,s);
        }
        //printf("%s                  %d %d %d\n", (buf), st.type, st.ino, st.size);
  }
}
int main(int argc, char *argv[]){    
    //printf("find\n");
    // for(int i = 0; i < argc; i++){
    //   printf("%s\n",argv[i]);
    // }
    
    struct stat st;
    //打开指定路径文件
    int fd = open(argv[1], 0);
    fstat(fd, &st);
    if(st.type == T_FILE){
        printf("file\n");
    }
    if(st.type == T_DIR){
        strcpy(buf, argv[1]);
        char *p = 0;
        dfs(p,argv[2]);
    }
    
    close(fd);
    exit();
}

xargs

Write a simple version of the UNIX xargs program: read lines from standard input and run a command for each line, supplying the line as arguments to the command. Your solution should be in the file user/xargs.c.

The following example illustrates xarg’s behavior:
$ xargs echo bye
hello too
bye hello too
ctrl-d
$

Note that the command here is “echo bye” and the additional arguments are “hello too”, making the command “echo bye hello too”, which outputs “bye hello too”.

Some hints:
Use fork and exec system call to invoke the command on each line of input. Use wait in the parent to wait for the child to complete running the command.
Read from stdin a character at the time until the newline character (‘\n’).
kernel/param.h declares MAXARG, which may be useful if you need to declare an argv.
Changes to the file system persist across runs of qemu; to get a clean file system run make clean and then make qemu.
xargs, find, and grep combine well:

$ find . b | xargs grep hello

will run “grep hello” on each file named b in the directories below “.”.
To test your solution for xargs, run the shell script xargstest.sh. Your solution is correct if it produces the following output:

$ make qemu

init: starting sh
$ sh < xargstest.sh
$ $ $ $ $ $ hello
hello
hello
$ $

You may have to fix bugs in your find program. The output has many $ because the xv6 shell is primitive and doesn’t realize it is processing commands from a file instead of from the console, and prints a $ for each command in the file.
代码:

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

int main(int argc, char *argv[]){
    int fd[2];pipe(fd);
    int pid = fork();
    if(pid > 0){
        wait();
        char buf[512];int n;
        n = read(fd[0],buf,sizeof(buf));
        int cnt = 0;
        for(int i = 0; i < n; i++)
            if(buf[i] == '\n')
                cnt++;
        char **p = (char **)malloc(sizeof(char*) * (argc - 1 + cnt));
        p[0] = (char *)malloc(sizeof(char) * strlen(argv[1]));
        strcpy(p[0],argv[1]);
        p[1] = (char *)malloc(sizeof(char) * strlen(argv[2]));
        strcpy(p[1],argv[2]);
        int j = 0;
        for(int i = 2; i < argc - 1 + cnt; i++){
            int index = 0;
            char s[512];
            for(; j < n; j++){
                if(buf[j] == '\n'){
                    s[index] = '\0';
                    p[i] = (char *)malloc(sizeof(char) * index);
                    strcpy(p[i],s);
                    j++;
                    break;
                }else{
                    s[index++] = buf[j];
                }
            }
        }
        exec(p[0],p);
    }else{
        char buf[512];
        int n = read(0,buf,sizeof(buf));
        write(fd[1],buf,n);
        exit();
    }
    exit();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值