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.
int main(int argc, char* argv[]){ if (argc < 1) { fprintf(2, "usage: sleep second\n"); exit(1); }
int i = atoi(argv[1]); sleep(i); exit(0); }
2. pingpong
2.1 描述
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.
int main(int argc, char* argv[]){ int p[2]; pipe(p); int pid = fork(); if (pid > 0) { // parent close(p[0]); if (write(p[1], buf, sizeof(buf)) > 0) { wait(0); printf("%d: received pong\n", getpid()); } else { return0; } close(p[1]); } elseif (pid == 0) { // child close(p[1]); if (read(p[0], buf, sizeof(buf)) > 0) { printf("%d: received ping\n", getpid()); } else { return0; } close(p[0]); } else { // error fprintf(2, "error\n"); exit(1); } exit(0); }
3. primes
3.1 描述
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.
应用埃氏筛法实现对素数的筛选,下面给出的是迭代实现,注意利用该条件终止迭代*Hint: read returns zero when the write-side of a pipe is closed.*。每次迭代创建一个管道,父进程通过将原始数据写管道,子进程在读阶段将数据中非素数筛出并保留筛出数据到缓冲区供下次传递使用,并打印数据
int main(int argc, char* argv[]){ int p[2]; int buf[36]; int pid = 0; // initialize. int index = 0; for (int i = 2; i <= 35; ++i) { buf[index++] = i; } // use the sieve function 埃氏筛法 while (index > 0) { pipe(p); // Create pipe every valid loop. if ((pid = fork()) == 0) { // child // sieve operation. int prime = 0; int index = -1; int temp = 0; close(p[1]); while (read(p[0], &temp, sizeof(temp)) != 0) { // handle to sieve prime numbers. if (index < 0) { prime = temp; index++; } else { if (temp % prime != 0) buf[index++] = temp; } } printf("prime %d\n", prime); close(p[0]); } elseif (pid > 0) { // parent close(p[0]); for (int i = 0; i < index; ++i) { write(p[1], &buf[i], sizeof(buf[i]); } close(p[1]); wait(0); // main process is waiting all child processes to quit. exit(0); } else { fprintf(2, "fork failure.\n"); exit(1); } } exit(0); }
4. find
4.1 描述
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.
/** * @brief transmit the complete filename path to the filename eradicated dir. * * @param path complete filename path. * @return return the filename eradicated part behind the last slash "/". */ char* fmtname(char* path){ staticchar buf[DIRSIZ+1]; // +1表示buf最后一个字符为字符串结束符 char* p; // 从后向前遍历找到最底层的文件/目录名 for (p = path+strlen(path); p >= path && *p != '/'; p--); p++; // 跳过slash指向最底层文件/目录名称的第一个字符
// 对这个名称进行处理,如果大于最大的目录名称则直接返回该名称;小于则进行空字符的填充 if (strlen(p) >= DIRSIZ) return p; // 将改名称写入buf中 memmove(buf, p, strlen(p)); /* fill the white space into the rest of the DIRSIZ that * guarantee the correctness of strcmp func. */ // DIRSIZ为目录名称的最大长度(14个字符),目录名称的长度小于14那么就填充对应的' '字符, // 来保证在能够在strcmp中两个比较的目录名称都是14个字符 memset(buf+strlen(p), ' ', DIRSIZ-strlen(p)); buf[strlen(p)] = 0; // 字符串结束符,数组下标由0开始,也就是在该名称后面加上字符串结束符 return buf; }
if ((fd = open(path, 0)) < 0) { // open系统调用通过文件路径获取文件描述符 fprintf(2, "find: cannot open %s\n", path); return; }
if (fstat(fd, &st) < 0) { // 将文件描述符对应的stat结构返回到st参数中 fprintf(2, "find: cannot open %s\n", path); close(fd); return; }
switch (st.type) // 记录文件的类型,st.type的类型为short。xv6用分别用三个宏表示文件类型,依次从1开始(T_DIR, T_FILE, T_DEVICE) { case T_FILE: if (!strcmp(name, fmtname(path))) // 如果相等strcmp返回0 printf("%s\n", path); break; case T_DIR: // 个人感觉两个+1都指的是slash占位符 if (strlen(path)+1+DIRSIZ+1 > sizeof(buf)) { printf("find: path too long\n"); break; }
/* buf store the complete path and hold the buf pointer in front of it that * is convenient to print the complete path which we expect to output. */ strcpy(buf, path); p = buf + strlen(buf); // 将p指向buf的最后一个字符 *p++ = '/'; // i.e. *(p++) = '/'(优先级从右向左). while (read(fd, &de, sizeof(de)) == sizeof(de)) { // 读取文件的目录结构到de结构体(实际上fstat也大概是这么实现的,注意到这两个结构体都是满足字节对齐的) if (de.inum == 0) // inum为当前目录下子目录的个数,如果为0就没必要往下找了 continue; memmove(p, de.name, DIRSIZ); // 将目录名称移动到p指向的区域 p[DIRSIZ] = 0; // 字符串结束符 if (!strcmp(de.name, ".") || !strcmp(de.name, "..")) { // 如果是上一级目录或者是当前目录则continue continue; } find(buf, name); // recursive. } break; } close(fd); }
int main(int argc, char** argv){ if (argc < 3) { fprintf(2, "usage: find path name...\n"); return0; } for (int i = 2; i < argc; ++i) { find(argv[1], argv[i]); } exit(0); }
5. xargs
5.1 描述
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.
需要去了解linux中xargs命令的实现,需要注意的是argv提取的是由xargs之后的参数(运行的是xargs程序),从管道中提取数据作为xargs后面命令的参数。通过read从标准输入读数据,将其中的’\n’和’ ‘参数分隔符用字符串结束符替代,并添加在参数列表的后面,由exec系统调用执行。xargs - build and execute command lines from standard input,完成了用标准输入的内容作为xargs的参数