2024-01-21 17:11阅读: 17评论: 0推荐: 0

[MIT 6.S081] Lab: Xv6 and Unix utilities

Lab: Xv6 and Unix utilities

Grade

sleep

sleep 格式如下

sleep 5

这边需要使用 kernal/stat.h 中的 sleep 系统调用,并将参数转化为传入。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
int main(int argc, char* argv[]) {
if (argc != 2) {
printf("usage: sleep digit");
exit(1);
}
int is_digit = 1, sec = 0;
for (const char* s = argv[1]; *s; s ++) {
if (*s >= '0' && *s <= '9') {
sec = sec * 10 + *s - '0';
} else {
is_digit = 0;
break;
}
}
if (!is_digit) {
printf("argv must be int");
exit(1);
}
sleep(sec);
exit(0);
}

pingpong

pingpong 需要父进程和子进程之间具有交流信息的能力,也就是使用一对管道。对于父进程,先向子进程传输一个字节的信息,然后等待子进程返回一个字节的信息后 ,输出 pong 。对于子进程来说,需要先接收信息,然后输出 ping ,再将信息传输回去。要记住的是,及时关闭各个进程的通道读端和写端,也就是及时释放资源。

#include "kernel/types.h"
#include "user/user.h"
int main() {
const char* msg = "a";
char buf[2] = {};
int pipe_p_to_c[2], pipe_c_to_p[2];
// 0:= read fd
// 1:= write fd
pipe(pipe_p_to_c);
pipe(pipe_c_to_p);
// == 0 := ch p
if (fork() == 0) {
close(pipe_p_to_c[0]);
close(pipe_c_to_p[1]);
read(pipe_p_to_c[0], buf, 1);
printf("%d: received ping\n", getpid());
write(pipe_c_to_p[1], msg, 1);
close(pipe_p_to_c[1]);
close(pipe_c_to_p[0]);
} else {
close(pipe_c_to_p[0]);
close(pipe_p_to_c[1]);
write(pipe_p_to_c[1], msg, 1);
wait(0);
read(pipe_c_to_p[0], buf, 1);
printf("%d: received pong\n", getpid());
close(pipe_c_to_p[1]);
close(pipe_p_to_c[0]);
}
exit(0);
}

primes

这一步就比较困难。

首先 primes 的要求是:在每个进程中输出还未筛出的第一个素数,并在这个进程中进行一轮筛法,将剩下的数使用 pipe 传递给下一个进程。

std::vector<int> pri;
bool is_not_pri[N];
void GetPrime() {
is_not_pro[0] = is_not_pri[1] = true;
for (int i = 2; i < N; i ++) {
if (is_not_pri[i])
continue;
pri.emplace_back(i);
for (int j = i * 2; j < N; j += i) {
is_not_pri[j] = true;
}
}
}

也就是说,每个进程相当于是 continue 之后的步骤。由于数字范围比较小,可以直接将目前得到的素数作为基准,用这个素数筛去其倍数即可。

需要注意的是,在这里特别要留意资源释放的问题。每次开启 pipe ,就必须要释放掉所可能不需要的 fd 。同时,父进程需要保留到所有子进程结束后才可退出,这时候就需要 wait() 了。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
__attribute__((noreturn))
void dfs(int rd) {
int n;
if (read(rd, &n, 4) == 0) {
exit(0);
}
printf("prime %d\n", n);
int p[2];
pipe(p);
if (fork() == 0) {
close(p[0]);
int m;
while (read(rd, &m, 4)) {
if (m % n) {
write(p[1], &m, 4);
}
}
close(rd);
close(p[1]);
} else {
close(p[1]);
dfs(p[0]);
}
wait(0);
exit(0);
}
int main() {
int p[2];
pipe(p);
for (int i = 2; i <= 35; i ++) {
write(p[1], &i, 4);
}
close(p[1]);
dfs(p[0]);
wait(0);
exit(0);
}

find

这块可以直接参考 ls 的实现,观察 ls 是如何遍历目录的,find 只是多了需要比较名字的步骤。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"
#include <float.h>
char* get_filename(char* path) {
static char buf[DIRSIZ + 1] = {};
char* p;
for (p = path + strlen(path); p >= path && *p != '/'; p --);
p ++;
if (strlen(p) >= DIRSIZ) {
return p;
}
memmove(buf, p, strlen(p));
memset(buf + strlen(p), ' ', DIRSIZ - strlen(p));
return buf;
}
void find(char *path, char *tar) {
char buf[512];
int fd;
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_DEVICE:
case T_FILE:
if (strcmp(tar, get_filename(path)) == 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);
char* p = buf + strlen(buf);
*p ++ = '/';
struct dirent de;
while(read(fd, &de, sizeof(de)) == sizeof(de)) {
if (de.inum == 0) {
continue;
}
memmove(p, de.name, DIRSIZ);
p[DIRSIZ] = 0;
if (stat(buf, &st) < 0) {
printf("find: cannot stat %s\n", buf);
continue;
}
char* name = de.name;
if (st.type != T_DIR) {
// goto TAR_FILE;
if (strcmp(tar, name) == 0) {
printf("%s\n", buf);
}
continue;
}
if (strcmp(name, ".") && strcmp(name, "..")) {
find(buf, tar);
}
}
break;
default:
break;
}
close(fd);
return;
}
int main(int argc, char* argv[]) {
if (argc != 3) {
fprintf(2, "useage: find path/to/dir file_name\n");
} else {
find(argv[1], argv[2]);
}
exit(0);
}

xargs

xargs 真正执行的就是其第一个参数中的命令,只要从标准输入流中读入前面命令的输出,然后将这个输出作为真正执行的命令的参数,调用 exec 即可。

#include "kernel/types.h"
#include "kernel/param.h"
#include "user/user.h"
int main(int argc, char* argv[]) {
char* xargv[MAXARG] = {};
for (int i = 1; i < argc; i ++)
xargv[i - 1] = argv[i];
char buf[512] = {};
while (gets(buf, 512)) {
int len = strlen(buf);
if (len == 0)
break;
if (buf[len - 1] == '\n')
buf[len - 1] = '\0';
xargv[argc - 1] = buf;
if (fork() == 0) {
exec(argv[1], xargv);
} else {
wait(0);
}
}
exit(0);
}

本文作者:フランドール·スカーレット

本文链接:https://www.cnblogs.com/FlandreScarlet/p/17978040

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   フランドール·スカーレット  阅读(17)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起
  1. 1 Scarborough Fair 山田タマル
  2. 2 Faster Than Light Paradox Interactive,Andreas Waldetoft
  3. 3 世界は可愛く出来ている 上海アリス幻樂団
Scarborough Fair - 山田タマル
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : Pual Simon

作曲 : Pual Simon

作词 : イングランド民謡

作曲:加藤达也

Are you going to Scarborough Fair?

Parsley, sage, rosemary and thyme

Remember me to one who lives there

He once was a true love of mine

Tell him to make me a cambric shirt

Tell him to make me a cambric shirt

Parsley, sage, rosemary and thyme

Without no seams nor needlework

Then he'll be a true love of mine.

Tell him to find me an acre of land

Tell him to find me an acre of land

Parsley, sage, rosemary and thyme

Between the salt water and the sea strand

Then he'll be a true love of mine

Are you going to Scarborough Fair?