MIT6.S081 Lab1 Xv6 and Unix utilities (updated)

Domestic OS courses may only teach you the concepts of operating systems on the surface. It is like playing a simulator game and just watching others play. After all, you will still lose your way in the world of OS.

This article was originally published on my personal blog MIT6.S081 lab1

Q1.sleep (easy)

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:

  • Before you start coding, read Chapter 1 of the xv6 book.

    (1. Read the book first)

  • Look at some of the other programs in user/ (e.g., user/echo.c, user/grep.c, and user/rm.c strong>) to see how you can obtain the command-line arguments passed to a program.

    (2. Look at the above files to see how you get the command line parameters)

  • If the user forgets to pass an argument, sleep should print an error message.

    (3. Failure to pass parameters requires special processing)

  • The command-line argument is passed as a string; you can convert it to an integer using atoi (see user/ulib.c).

    (4. The parameters entered on the command line are all strings, and the numbers required by sleep need to be converted into integers using atoi)

  • Use the system call sleep.

    (5. Use the written sleep system call)

  • See kernel/sysproc.c for the xv6 kernel code that implements the sleep system call (look for sys_sleep), user/user.h for the C definition of sleep callable from a user program, and user/usys.S for the assembler code that jumps from user code into the kernel for sleep.

    ()

  • Make sure main calls exit() in order to exit your program.

    (Make sure the program exits with the system call exit() at the end)

  • Add your sleep program to UPROGS in Makefile; once you’ve done that, make qemu will compile your program and you’ll be able to run it from the xv6 shell.

    (Sleep needs to be added to the MakeFile file. I refer to other people’s MakeFile for this part)

  • Look at Kernighan and Ritchie’s book The C programming language (second edition) (K & amp;R) to learn about C.

    (Those with weak C foundation can read this book)

///user/echo.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
  int i;

  for(i = 1; i < argc; i + + ){
    write(1, argv[i], strlen(argv[i]));
    if(i + 1 < argc){
      write(1, " ", 1);
    } else {
      write(1, "\
", 1);
    }
  }
  exit(0);
}
//user/grep.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int
main(int argc, char *argv[])
{
  int fd, i;
  char *pattern;

  if(argc <= 1){
    fprintf(2, "usage: grep pattern [file ...]\
");
    exit(1);
  }
  pattern = argv[1];

  if(argc <= 2){
    grep(pattern, 0);
    exit(0);
  }

  for(i = 2; i < argc; i + + ){
    if((fd = open(argv[i], 0)) < 0){
      printf("grep: cannot open %s\
", argv[i]);
      exit(1);
    }
    grep(pattern, fd);
    close(fd);
  }
  exit(0);
}
//user/rm.c
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"

int
main(int argc, char *argv[])
{
  int i;

  if(argc < 2){
    fprintf(2, "Usage: rm files...\
");
    exit(1);
  }

  for(i = 1; i < argc; i + + ){
    if(unlink(argv[i]) < 0){
      fprintf(2, "rm: %s failed to delete\
", argv[i]);
      break;
    }
  }

  exit(0);
}

Referring to the three .c files above, it is obvious that:

1.argc is the number of parameters, agrv is a two-dimensional character array, argv[0] is the first parameter, argv[1] is the second parameter, then for the sleep we want to implement, enter sleep xxx, then sleep is As argv[0], xxx as argv[1].

2. The parameters required for sleep are not passed and special judgment is required.

3. If there are parameters, use atoi to convert the string into an integer, and finally call the system call sleep

The following is the sleep.c I implemented, which has passed the test

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

int main(int argc,char *argv[]){
    int time;
    if(argc < 2){
        printf("You forget to pass an argument, so I print an error message.");
        exit(1);
    }
    time = atoi(argv[1]);
    sleep(time);
    exit(0);
}

Q2.pingpong (easy)

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 should send a byte to the child; the child should print “ : received ping”, where is its process ID, write the byte on the pipe to the parent, and exit; the parent should read the byte from the child, print “: received pong”, and exit. Your solution should be in the file user/pingpong.c.

Some hints:

  • Use pipe to create a pipe.

    (Using the pipe system call to create a pipeline, this blogger explains it very well and it is easy to understand the detailed explanation of linux pipe pipe_linux pipe-CSDN blog)

  • Use fork to create a child.

    (Use fork to create a child process for parent-child communication)

  • Use read to read from the pipe, and write to write to the pipe.

    (Use the read system call to read and write from the pipe)

  • Use getpid to find the process ID of the calling process.

    (Use getpid call to get the current process id, answer should be output)

  • Add the program to UPROGS in Makefile.

  • User programs on xv6 have a limited set of library functions available to them. You can see the list in user/user.h; the source (other than for system calls) is in user/ulib.c, user/printf.c, and user/umalloc.c.

    (Use the call provided under user.h)

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
    $
  

My code is as follows, full marks:

(After thinking about it for a long time, I realized that it would be easy to use two pipes. I decided it would be easy)

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
 
int main(int argc,char * argv[]){
    int p[2];
    int p2[2];
    char buf[1024];
    pipe(p);
    pipe(p2);
    char *a = "hello mychild";
    char *b = "hello myparent";
    if(fork() == 0){
        close(p[1]);
        int len = read(p[0],buf,sizeof(buf));
        if(len > 0)
            printf("%d: received ping\
",getpid());
        close(p[0]);
        close(p2[0]);
        write(p2[1],b,strlen(b));
        
        close(p2[1]);
    }else{
        close(p[0]);
        write(p[1],a,strlen(a));
        wait((int*)0);
        int len = read(p2[0],buf,sizeof(buf));
        if(len > 0)
            printf("%d: received pong\
",getpid());
        close(p[0]);
        close(p[1]);
        close(p2[0]);
        close(p2[1]);

    }

    exit(0);
}

I’ve been busy with other things lately, so I’ll do the following questions well, and I’ll update them slowly~