MIT 6.S081 Lab: Xv6 and Unix utilities

  • sleep.c

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.

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

int
main(int argc, char const *argv[])
{
    
    
    if (argc <= 1) {
    
    
        fprintf(2, "usage: sleep <ticks>\n");
        exit(1);
    }
    int n = atoi(argv[1]);
    sleep(n);
    exit(0);
}

  • pingpong.c

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.

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

int 
main(int argc, char const *argv[])
{
    
    
    /* code */
    int child_fd[2];
    int parent_fd[2];

    pipe(child_fd);
    pipe(parent_fd);

    // child process
    if (fork() == 0) {
    
    
        char buf[128];
        // the child close the write side of the pipe, reads from pipe, and
        // then close the read side
        close(child_fd[1]);
        read(child_fd[0], buf, sizeof buf);
        close(child_fd[0]);

        // print "<pid>: received ping", write the byte on the pipe to the 
        // parent and exit
        printf("%d: received p%sng\n", getpid(), buf);
        close(parent_fd[0]);
        write(parent_fd[1], "o", 1);
        close(parent_fd[1]);
        exit(0);
    }
    // parent process
    else {
    
    
        char buf[128];
        // the parent closes the read side of the pipe, writes to the pipe, and
        // then close the write side
        close(child_fd[0]);
        write(child_fd[1], "i", 1);
        close(child_fd[1]);
        
        // the parent should read the byte from the child, print "<pid>: received
        // pong", and exit
        close(parent_fd[1]);
        read(parent_fd[0], buf, sizeof buf);
        close(parent_fd[0]);
        printf("%d: received p%sng\n", getpid(), buf);
        exit(0);
    }
}
  • primes.c

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.

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

int
create_new_process(int parent_fd[2]) {
    
    
    char bytes[4];
    close(parent_fd[1]);
    read(parent_fd[0], bytes, sizeof bytes);

    // convert bytes to int32 and print
    int p = *(int *) bytes;
    printf("prime %d\n", p);

    // if there're no primes to read, don't need to create new process
    if (read(parent_fd[0], bytes, sizeof bytes) == 0) {
    
    
        exit(0);
    }

    int child_fd[2];
    pipe(child_fd);

    int pid = fork();
    if (pid < 0) {
    
    
        exit(1);
    }
    else if (pid == 0) {
    
    
        create_new_process(child_fd);
        exit(0);
    }
    // parent process
    else {
    
    
        close(child_fd[0]);
        // reads from its left neighbor over a pipe and
        // writes to its right neighbor over pipe
        do {
    
    
            int n = *(int *) bytes;
            if (n % p != 0) {
    
    
                write(child_fd[1], bytes, sizeof bytes);
            }
        } while (read(parent_fd[0], bytes, sizeof bytes) != 0);
        close(child_fd[1]);
        close(parent_fd[0]);
        // the main primes process should only exit after all the output has
        // been printed, and after all the other primes processes have exited
        wait((int *) 0);
        exit(0);
    }
}

int 
main(int argc, char const *argv[])
{
    
    
    int parent_fd[2];
    pipe(parent_fd);

    int pid = fork();
    if (pid < 0) {
    
    
        exit(1);
    }
    // child process
    else if (pid == 0) {
    
    
        create_new_process(parent_fd);
        exit(0);
    }
    // The first process feeds the numbers 2 through 35 into the pipeline.
    else {
    
    
        close(parent_fd[0]);
        for (int i = 2; i <= 35; i++) {
    
    
            // convert int32 to 4 bytes
            char bytes[4];
            bytes[3] = (i >> 24) & 0xff;
            bytes[2] = (i >> 16) & 0xff;
            bytes[1] = (i >> 8) & 0xff;
            bytes[0] = i & 0xff;
            write(parent_fd[1], bytes, sizeof bytes);
        }
        close(parent_fd[1]);
        // It should wait until the entire pipeline terminates, including
        // all children, grandchildren
        wait((int *) 0);
        exit(0);
    }
}

  • find.c

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

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

void
find(char *path, char *file) 
{
    
    
    char buf[512], *p;
    int fd;
    struct dirent de;
    struct stat st;
    
    // open and possibly create a file
    if ((fd = open(path, 0)) < 0) {
    
    
        fprintf(2, "find: cannot open %s\n", path);
        exit(1);
    }

    // get file status
    if (fstat(fd, &st) < 0) {
    
    
        fprintf(2, "find: cannot stat %s\n", path);
        close(fd);
        return;
    }

    switch (st.type)
    {
    
    
    case T_FILE:
        // Find first character after last slash.
        for (p=path+strlen(path); p >= path && *p != '/'; p--)
            ;
        p++;
        // if file with the specific name
        if (!strcmp(p, file)) {
    
    
            printf("%s\n", path);
        }
        break;

    case T_DIR:
        if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
    
    
            printf("find: path too long\n");
            break;
        }
        strcpy(buf, path);
        p = buf + strlen(buf);
        *p++ = '/';
        while (read(fd, &de, sizeof(de)) == sizeof(de)) {
    
    
            // don't recurse into "." and ".." and empty dir
            if (de.inum == 0 || !strcmp(de.name, ".") || !strcmp(de.name, ".."))
                continue;

            // add the sub-directories to path
            memmove(p, de.name, DIRSIZ);
            p[DIRSIZ] = 0;
            if (stat(buf, &st) < 0) {
    
    
                printf("find: cannot stat %s\n", buf);
                continue;
            }
            // use recursion to allow find to descend into sub-directories.
            find(buf, file);
        }
        break;
    }
    close(fd);
}

int
main(int argc, char *argv[])
{
    
    
    if (argc < 3) {
    
    
        fprintf(2, "usage: find <path> <file>\n");
        exit(1);
    }
    find(argv[1], argv[2]);
    exit(0);
}

  • xargs.c

Write a simple version of the UNIX xargs program: read lines from the 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.

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

#define MAXLINE 32
int
main(int argc, char *argv[])
{
    
    
    if (argc < 3) {
    
    
        fprintf(2, "usage: xargs <command> <argu>");
        exit(1);
    }
    char *cmd = argv[1];
    char line[MAXLINE];
    memset(line, 0, sizeof line);

    int i = 0;
    char ch;
    while(read(0, &ch, sizeof (char))) {
    
    
        // read individual lines of input, read a character at a time
        // until a newline ('\n') appears.
        if (ch == '\n') {
    
    
            char *child_argv[4];
            child_argv[0] = cmd;
            child_argv[1] = argv[2];
            child_argv[2] = line;
            // don't forget this
            child_argv[3] = 0;
            // child process
            if (fork() == 0) {
    
    
                exec(cmd, child_argv);
            }
            // use wait in the parent to wait for the child to complete the command
            else {
    
    
                wait(0);
            }
            memset(line, 0, sizeof line);
            i = 0;
        }
        else {
    
    
            line[i++] = ch;
        }
    } 
    exit(0);
}

猜你喜欢

转载自blog.csdn.net/weixin_41714373/article/details/109501307