sleep
argc表示命令行参数个数,sleep应该为2个参数,第一个参数为路径(大概是这样),argv为指向参数的指针数组,atoi为系统提供的将字符串转为整数的函数,最后用exit退出。

#include "/kernel/types.h"
#include "user/user.h"
int main(int argc, char *argv[])
{
    if(argc != 2){
        fprintf(2,"you must input sleep time");
        exit(0);
    }
    sleep(atoi(argv[1]));
    exit(0);
}

pingpong
学习使用pipe管道,pipe函数接受一个数组指针,将其初始化为一对文件标识符,默认数组第一位是读标识符,第二位是写标识符,当用fork创建子进程时,会复制父进程一模一样的标识符,指向同一位置共享偏移,所以根据需要使用close关闭相应的标识符
学习使用readwrite系统函数进行读写,第一个参数为文件标识符,第二个参数为读写位置,第三个参数为字节数

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

int main(int argc, char *argv[])
{
    int p0[2], p1[2];
    char buf[8];
    pipe(p0[2]);
    pipe(p1[2]);
    if(fork()==0)
    {
        close(p0[1]);
        close(p1[0]);
        if(read(p0[1], buf, 8)!=8)
        {
            printf("read error");
            exit(0);
        }
        printf("%d: received ping\n", getpid());
        if(write(p1[0], buf, 8)!=8)
        {
            printf("write error");
            exit(0);
        }
        exit(0);
    }
    else
    if(read(p1[0], buf, 8)!=8)
    {
        printf("read error");
        exit(0);
    }
    printf("%d: receive pong\n", getpid());
    wait(0);
    exit(0);
}

primes
利用管道筛素数,首先输入2到35,每次输入的第一个数一定是素数,其余的数如果是这个数的倍数就筛掉,然后再进入下一个进程继续筛,最后输出所有素数
学习迭代的思想,建立一个迭代函数进行执行筛的命令
当写通道关闭时,read会返回0,利用这个进行读取管道内所有数

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

void process(int p[])
{
    close(p[1]);
    int prime;
    if(read(p[0], &prime, 4)>0)
    {
        printf("prime %d\n", prime);
        int pp[2];
        pipe(pp);
        if(fork()==0)
        {
            process(pp);
        }
        else
        {
            close(pp[0]);
            int i;
            while(read(p[0], &i, 4)>0)
            {
                if(i%prime!=0)
                write(pp[1], &i, 4);
            }
            close(pp[1]);
            wait(0);
        }
    }
}
int main(int argc, char *argv[])
{
    int p[2];
    pipe(p);
    if(fork()==0)
    {
        process(p);
    }
    else
    {
        close(p[0]);
        for(int i=2; i<36; ++i)
        {
            write(p[1], &i, 4);
        }
        close(p[1]);
        wait(0);
    }
    exit(0);
}

find
argv保存命令行参数,第一个为argv[0]保存调用命令名,后面的一般为用户提供的参数
当从路径的标识符中读取字符时,读取到的是目录下的文件信息,这也是为什么ls可以显示文件信息的原因,实际上只是做了读取的工作
一般目录内容为., .., 文件名

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

char* filename(char *path)
{
    char *p;
    for(p=path+strlen(path); p>=path && *p != '/'; p--)
        ;
    p++;
    return p;
}

void find(char *path, char *target)
{
    char buf[512], *p;
    int fd;
    struct dirent de;
    struct stat st;
    if(fd=open(path, 0) < 0)
    {
        printf("find: cannot open %s\n", path);
        return;//调用open打开path的输出口,打不开函数返回
    }
    if(fstat(fd, &st) < 0)
    {
        printf("find: cannot stat %s\n", path);
        close(fd);
        return;//调用fstat把文件信息放进st,失败就返回
    }
    switch(st.type)
    {
    case T_FILE://是文件
        if(strcmp(filename(path), target) == 0)
        {
            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);//buf==path
        p = buf+strlen(buf);//p位于buf结尾
        *p++ = '/';//buf最后面添加/
        while(read(fd, &de, sizeof(de)) == sizeof(de))//读path目录下的文件
        {
              if(de.inum == 0) 
              {
                  continue;
              }
              if (strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0)//跳过子目录的.和..
              { 
                  continue;
              }
              memmove(p, de.name, DIRSIZ);//读到真正的文件就加在p后面,也就是buf末尾 
              p[DIRSIZ] = 0;//在字符串最后加0表示结束
              find(buf, target);
        }
        break;
    }
    close(fd);
}
int main(int argc, char *argv[])
{
    if(argc < 3)
    {
        printf("error");
        exit(0);
    }
    find(argv[1], argv[2]);
    exit(0);
}