1.sleep
第一个任务主要是让我们了解命令行传参的格式?我是这么理解的。然后直接调用系统调用即可。
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char *argv[]){
if(argc != 2){
fprintf(2, "usage: sleep time\n");
exit(1);
}
int n=atoi(argv[1]);
int ret=sleep(n);
if(ret<0){
fprintf(2, "sleep wrong\n");
}
exit(0);
}
2.pingpong
第二个任务是让我们利用管道。就是存在两个进程,第一个给第二个发个ping,第二个给第一个发个pong。
但是这个任务有个坑,那就是发的顺序有问题:
试想一下,如果父进程给子进程发送一个ping,子进程等待然后输出ping,然后子进程再给父进程发送pong,父进程输出pong,这样是不是没问题?
没错,确实没问题,但是如果反过来的话可能父进程在发完pong之后直接溜走,子进程还没打印完pong,就会造成输出的一些混乱。
因此,必须按照第一种顺序来。
代码如下所示:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char *argv[])
{
int p1[2], p2[2];
pipe(p1);
pipe(p2);
char str[10];
int ret = fork();
if (ret > 0)
{ //父进程接收之后退出 注意同步顺序
close(p1[0]);
write(p1[1], "ping", 5);
close(p1[1]);
close(p2[1]);
read(p2[0], str, 5);
printf("%d: received %s\n", getpid(), str);
// printf("%s", str);
close(p2[0]);
}
else if (ret == 0)
{
close(p1[1]);
read(p1[0], str, 5);
printf("%d: received %s\n", getpid(), str);
// printf("%s", str);
close(p1[0]);
close(p2[0]);
write(p2[1], "pong", 5);
close(p2[1]);
}
else
{
fprintf(2, "error in fork\n");
}
exit(0);
}
3.primes
这里的实现思路如下:
创建父进程和子进程。
最初的父进程先把2到35写到管道里边。
子进程从管道里边读第一个数,如果是0说明已经读完了。
否则,再fork一下,创建子进程的子进程,而当前子进程的任务就变成了,往新创建的管道里边写入被筛掉后剩下的数,而子进程的子进程继续上一个子进程的过程。当然,子进程在发送完数据之后就一直wait他的子进程结束。
代码如下所示:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char *argv[])
{
int prev[2];
pipe(prev);
int ret = fork();
if (ret < 0)
{
fprintf(2, "error in fork\n");
}
else if (ret == 0)
{
int base = 0;
while (1)
{
close(prev[1]); //关闭写端
if (read(prev[0], &base, sizeof(base)) == 0)
{
exit(0);
}
printf("prime %d\n", base);
int next[2];
pipe(next);
int r = fork();
// 父进程从读端筛选质数
if (r > 0)
{
int cur = 0;
close(next[0]);
for (; read(prev[0], &cur, sizeof(cur)) != 0;)
{
if (cur % base != 0)
{
write(next[1], &cur, sizeof(cur));
}
}
close(prev[0]);
close(next[1]);
wait(0);
exit(0);
}
close(prev[0]);
prev[0] = next[0];
prev[1] = next[1];
}
}
else
{
close(prev[0]);
for (int i = 2; i <= 35; i++)
{
write(prev[1], &i, sizeof(int));
}
close(prev[1]);
wait(0);
}
exit(0);
}
4.find
emmm这个纯属参考ls.c,代码如下所示:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
char *fmtname(char *path)
{
static char buf[DIRSIZ + 1];
char *p;
// Find first character after last slash.
for (p = path + strlen(path); p >= path && *p != '/'; p--)
;
p++;
// Return blank-padded name.
if (strlen(p) >= DIRSIZ)
return p;
memmove(buf, p, strlen(p));
memset(buf + strlen(p), ' ', DIRSIZ - strlen(p));
buf[strlen(p)] = '\0';
return buf;
}
void find(char *path, char *findName)
{
char buf[512], *p;
int fd;
struct dirent de;
struct stat st;
if ((fd = open(path, 0)) < 0)
{
fprintf(2, "find: cannot open %s\n", path);
return;
}
if (fstat(fd, &st) < 0)
{
fprintf(2, "find: cannot stat %s\n", path);
close(fd);
return;
}
switch (st.type)
{
case T_FILE:
// printf("%s, %s, %s\n", path, fmtname(path), findName);
if (strcmp(fmtname(path), findName) == 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);
p = buf + strlen(buf);
*p++ = '/';
while (read(fd, &de, sizeof(de)) == sizeof(de))
{
if (de.inum == 0 || strcmp(de.name, ".") == 0 || strcmp(de.name, "..") == 0)
continue;
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if (stat(buf, &st) < 0)
{
printf("find: cannot stat %s\n", buf);
continue;
}
find(buf, findName);
}
break;
}
close(fd);
}
int main(int argc, char *argv[])
{
if (argc != 3)
{
fprintf(2, "error in find\n");
}
// printf("%s, %s\n", argv[1], argv[2]);
find(argv[1], argv[2]);
exit(0);
}
5.xargs
xargs在这里边的实现就是,从标准输入里边按照行分割参数,然后装载给exec,这里用一个一个字符读的方法:
#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/param.h"
int main(int argc, char *argv[])
{
char *cmd = argv[1];
char rec[MAXARG];
memset(rec, 0, sizeof(rec));
int i = 0;
char ch;
while (read(0, &ch, sizeof(char)))
{
if (ch == '\n')
{
char *child_argv[4];
rec[i] = 0;
child_argv[0] = cmd;
child_argv[1] = argv[2];
child_argv[2] = rec;
child_argv[3] = 0;
int pid = fork();
if (pid == 0)
{
exec(child_argv[0], child_argv);
}
else
{
wait(0);
}
i = 0;
}
else
{
rec[i++] = ch;
}
}
exit(0);
}
// int main(int argc, char *argv[])
// {
// char *argv_stdin = (char *)malloc(sizeof(char) * MAXARG);
// read(0, argv_stdin, MAXARG);
// printf("%s\n", argv_stdin);
// printf("%d\n", strlen(argv_stdin));
// char *param[argc + 1];
// for (int i = 0; i < argc - 1; i++)
// {
// param[i] = argv[i + 1];
// }
// param[argc - 1] = (char *)malloc(sizeof(char) * MAXARG);
// param[argc] = 0;
// char *p = argv_stdin;
// while (*p != '\0')
// {
// int i = 0;
// while (*p != '\n' && *p != 0)
// {
// param[argc - 1][i++] = *p++;
// }
// if (*p == '\n')
// {
// p++;
// }
// param[argc - 1][i] = 0;
// printf("i=%d\n", i);
// //查看参数是否正确
// for (i = 0; i < argc + 1; i++)
// {
// printf("%s\t", param[i]);
// }
// printf("\n");
// int pid = fork();
// int child_status;
// if (pid > 0)
// {
// wait(&child_status);
// }
// else if (pid == 0)
// {
// exec(param[0], param);
// exit(0);
// }
// else
// {
// printf("xargs:fail to create child process\n");
// }
// }
// free(param[argc - 1]);
// free(argv_stdin);
// exit(0);
// }
// echo hello too | xargs echo bye
// sh < xargstest.sh