原文地址:YSBLOG
sleep
sleep 延迟times时间(在xv6中 10 times 为 1s)
在user/user.h中定义了sleep函数,只需将参数转为int类型直接传入即可
#include "kernel/types.h"
#include "user/user.h"int main(int argc, char* argv[]) {
int i;if (argc < 2) {
printf("sleep : tick number is not specified\n");exit(0);}i = atoi(argv[1]);if (i <= 0) {
printf("sleep : tick number is invalid\n");exit(0);}sleep(i);exit(0);
}
pingpong
该任务要求在父进程与子进程之间建立管道,父进程通过管道向子进程传递一个byte,子进程输出后将这个byte传递给父进程输出。
因为管道是单向的,所以需要建立两个管道,管道p1由父进程输出,子进程接收,管道p2由子进程输出,父进程接收。
#include "kernel/types.h"
#include "user/user.h"int main() {
int p1[2];int p2[2];char buffer[512];pipe(p1); // p1由父进程输出,子进程接收pipe(p2); // p2由父进程接收,子进程输出if (fork() == 0) {
// 若为子进程close(p1[1]); // 关闭p1的输出close(p2[0]); // 关闭p2的接收read(p1[0], buffer, 512); // 通过p1读取buffer// 输出接收内容,提交时不需要输出具体内容printf("<%d> : received pong : %s", getpid(), buffer); // printf("%d: received pong\n", getpid());write(p2[1], buffer, sizeof(buffer)); // 通过p2写回bufferclose(p1[0]); // 关闭p1接收close(p2[1]); // 关闭p2输入} else {
close(p1[0]); // 关闭p1的接收close(p2[1]); // 关闭p2的输出write(p1[1], "hello\n", sizeof("hello\n")); // 向p1输出内容,题目要求一个字节即可read(p2[0], buffer, sizeof(buffer));// 阻塞读取来自子进程p2管道的内容// 输出接收内容,提交时不需要输出具体内容printf("<%d> : received pong : %s", getpid(), buffer);// printf("%d: received ping\n", getpid());close(p1[1]); // 关闭p1输出close(p2[0]); // 关闭p2接收}exit(0);
}
primes
实现如图所示的效果,主进程向管道输入(1-35)的数,每级子进程分别输出一个质数。
我采用的方案是主进程创建一个管道p,主进程向管道写入1-35的数,子进程每次读取一个数,若该数为质素,则输出该数并创建子进程重复操作,若该数不为质素,则继续读取直到管道全部读取完毕。
#include "kernel/types.h"
#include "user/user.h"// 判断是否为质素,是则返回1,不是返回0
int prime(int num) {
if (num <= 1) return 0;for (int i = 2; i < num; ++i) {
if (num % i == 0) {
return 0;}}return 1;
}int main() {
int p0[2];pipe(p0);int num[35] = {
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35};write(p0[1], num, sizeof(num)); // 向管道写入1-35的数close(p0[1]); // 关闭管道写if (fork() == 0) {
// 若为子进程while (1) {
int tmp = 0;do {
// 循环读取第一个质素if (read(p0[0], &tmp, sizeof(int)) == 0) {
close(p0[0]);exit(0); // 管道为空时退出}} while (!prime(tmp));printf("prime %d\n", tmp); // 输出该进程读取到的质素if (fork() == 0) {
// 若为孙子进程则重复操作continue;} else {
// 等待孙子进程的结束wait(0);exit(0);}}} else {
close(p0[0]); // 主线程关闭读通道wait(0); // 等待子线程结束}exit(0);
}
find
find
参考user/ls.c实现,若路径为文件直接进行比较,若路径是目录,则对目录下的每一项都指向find(排除.以及…路径)
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"void find(char *path, const char *target) {
char buf[512], *p;int fd;struct dirent de; // 目录项结构体struct stat st; // 目录项参数if((fd = open(path, 0)) < 0){
// 打开该路径fprintf(2, "ls: cannot open %s\n", path);return;}if(fstat(fd, &st) < 0){
// 获取当前path的参数 fprintf(2, "ls: cannot stat %s\n", path);close(fd);return;}switch(st.type){
case T_FILE: // 如果当前path是一个文件,直接对比if (strcmp(target, path + strlen(path) - strlen(target)) == 0) {
printf("%s\n", path);}break;case T_DIR: // 如果当前path是一个目录if(strlen(path) + 1 + DIRSIZ + 1 > sizeof buf){
printf("ls: path too long\n");break;}strcpy(buf, path);p = buf+strlen(buf);*p++ = '/';while(read(fd, &de, sizeof(de)) == sizeof(de)){
// 读取当前目录下所有的目录项if(de.inum == 0) // 若不排除inum为0会出现很多异常输出,暂不清楚inum为0代表的含义continue;if (strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0) continue; // 排除.以及..strcpy(p, de.name); // 拼接新路径find(buf, target); // 对于子目录项递归执行find}break;}close(fd);
}int main (int argc, char *argv[]) {
if (argc != 3) {
printf("usage: find <path> <file name>\n");exit(1);}find(argv[1], argv[2]);exit(0);
}
xargs
xargs … 实现将标准输入作为command的参数并执行
#include "kernel/types.h"
#include "user/user.h"int main(int argc, char* argv[]) {
if (argc < 2) {
printf("xargs <command>\n");exit(1);}// 添加命令运行参数的二维数组char* commandArgv[32];int commandSize = argc - 1;// 将原本argv中的参数拷贝到新的参数数组中for (int i = 0; i < commandSize; ++i) {
commandArgv[i] = argv[i + 1];}char inputBuffer[512]; // 输入缓冲char inputChar; // 输入字符int inputNum = 0; // 输入字符计数while (read(0, &inputChar, sizeof(char)) > 0) {
if (inputChar == '\n') {
// 遇到回车时执行// 将当前指令添加到运行参数的二维数组中inputBuffer[inputNum] = 0; // 在字符数组最后添加'\0'commandArgv[commandSize++] = inputBuffer; // 将标准输入获取的参数拼接到参数数组中 commandArgv[commandSize] = 0; // 添加参数数组的结尾if (fork() == 0) {
exec(argv[1], commandArgv); // 子进程中执行目标命令}wait(0); // 等待子进程命令执行结束commandSize = argc - 1; // 初始化,保留argv中参数,准备执行下一行inputNum = 0;} else if (inputChar == ' ') {
inputBuffer[inputNum++] = 0; // 遇到空格添加分割符} else {
inputBuffer[inputNum++] = inputChar; // 正常字符输入}}exit(0);
}