From 24b86e61bf0e3b76f46942d66b110ed430eee9a2 Mon Sep 17 00:00:00 2001 From: doge316 <2281751933@qq.com> Date: Sun, 8 Jun 2025 12:34:46 +0800 Subject: [PATCH 1/2] =?UTF-8?q?Create=20=E8=B5=9B=E9=A2=98=E4=B8=80.cpp?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 功能实现代码 --- "\350\265\233\351\242\230\344\270\200.cpp" | 317 +++++++++++++++++++++ 1 file changed, 317 insertions(+) create mode 100644 "\350\265\233\351\242\230\344\270\200.cpp" diff --git "a/\350\265\233\351\242\230\344\270\200.cpp" "b/\350\265\233\351\242\230\344\270\200.cpp" new file mode 100644 index 0000000..8ac90a1 --- /dev/null +++ "b/\350\265\233\351\242\230\344\270\200.cpp" @@ -0,0 +1,317 @@ +//======================lab1========================== +//sleep +#include "kernel/types.h" +#include "user/user.h" +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(2, "usage: sleep [ticks num]\n"); + exit(1); + } + int ticks = atoi(argv[1]); + int ret = sleep(ticks); + exit(ret); +} +//pingpong +#include "kernel/types.h" +#include "user/user.h" +int main(int argc, char* argv[]) { + int parent_pid, child_pid; + int parent_to_child[2], child_to_parent[2]; + char message = 'a'; + pipe(parent_to_child); + pipe(child_to_parent); + child_pid = fork(); + if (child_pid == 0) { + parent_pid = getpid(); + close(parent_to_child[1]); + close(child_to_parent[0]); + read(parent_to_child[0], &message, 1); + printf("%d: received ping\n", parent_pid); + write(child_to_parent[1], &message, 1); + exit(0); + } + else { + parent_pid = getpid(); + close(parent_to_child[0]); + close(child_to_parent[1]); + write(parent_to_child[1], &message, 1); + read(child_to_parent[0], &message, 1); + printf("%d: received pong\n", parent_pid); + exit(0); + } +} + +//primes +#include "kernel/types.h" +#include "user/user.h" +void run_prime_sieve(int listenfd) { + int prime = 0; + while (1) { + if (read(listenfd, &candidate, sizeof(int)) == 0) { + close(listenfd); + + if (has_child) { + close(child_pipe[1]); + wait(0); + } + exit(0); + } + if (prime == 0) { + prime = candidate; + printf("prime %d\n", prime); + continue; + } + if (candidate % prime != 0) { + if (!has_child) { + pipe(child_pipe); + has_child = 1; + if (fork() == 0) { + close(child_pipe[1]); + close(listenfd); + run_prime_sieve(child_pipe[0]); + } + else { + close(child_pipe[0]); + } + } + write(child_pipe[1], &candidate, sizeof(int)); + } + } +} + +int main(int argc, char* argv[]) { + int initial_pipe[2]; + pipe(initial_pipe); + for (int num = 2; num <= 35; num++) { + write(initial_pipe[1], &num, sizeof(int)); + } + close(initial_pipe[1]); + + run_prime_sieve(initial_pipe[0]); + exit(0); +} + +//find +#include "kernel/types.h" +#include "kernel/fcntl.h" +#include "kernel/fs.h" +#include "kernel/stat.h" +#include "user/user.h" + +char* basename(char* pathname) { + char* prev = 0; + char* curr = strchr(pathname, '/'); + while (curr != 0) { + prev = curr; + curr = strchr(curr + 1, '/'); + } + return prev; +} + +void find(char* curr_path, char* target) { + char buf[512], * p; + int fd; + struct dirent de; + struct stat st; + if ((fd = open(curr_path, O_RDONLY)) < 0) { + fprintf(2, "find: cannot open %s\n", curr_path); + return; + } + + if (fstat(fd, &st) < 0) { + fprintf(2, "find: cannot stat %s\n", curr_path); + close(fd); + return; + } + + switch (st.type) { + + case T_FILE: { + char* f_name = basename(curr_path); + int match = 1; + if (f_name == 0 || strcmp(f_name + 1, target) != 0) { + match = 0; + } + if (match) + printf("%s\n", curr_path); + close(fd); + break; + } + case T_DIR: { + memset(buf, 0, sizeof(buf)); + uint curr_path_len = strlen(curr_path); + memcpy(buf, curr_path, curr_path_len); + buf[curr_path_len] = '/'; + p = buf + curr_path_len + 1; + while (read(fd, &de, sizeof(de)) == sizeof(de)) { + if (de.inum == 0 || strcmp(de.name, ".") == 0 || + strcmp(de.name, "..") == 0) + continue; + memcpy(p, de.name, DIRSIZ); + p[DIRSIZ] = 0; + find(buf, target); + } + close(fd); + break; + } + } +} + +int main(int argc, char* argv[]) { + if (argc != 3) { + fprintf(2, "usage: find [directory] [target filename]\n"); + exit(1); + } + find(argv[1], argv[2]); + exit(0); +} + +//xargs +#include "kernel/param.h" +#include "kernel/types.h" +#include "user/user.h" + +#define buf_size 512 + +int main(int argc, char* argv[]) { + char buf[buf_size + 1] = { 0 }; + uint occupy = 0; + char* xargv[MAXARG] = { 0 }; + int stdin_end = 0; + for (int i = 1; i < argc; i++) { + xargv[i - 1] = argv[i]; + } + + while (!(stdin_end && occupy == 0)) { + if (!stdin_end) { + int remain_size = buf_size - occupy; + int read_bytes = read(0, buf + occupy, remain_size); + if (read_bytes < 0) { + fprintf(2, "xargs: read returns -1 error\n"); + } + if (read_bytes == 0) { + close(0); + stdin_end = 1; + } + occupy += read_bytes; + } + + char* line_end = strchr(buf, '\n'); + while (line_end) { + char xbuf[buf_size + 1] = { 0 }; + memcpy(xbuf, buf, line_end - buf); + xargv[argc - 1] = xbuf; + int ret = fork(); + if (ret == 0) { + if (!stdin_end) { + close(0); + } + if (exec(argv[1], xargv) < 0) { + fprintf(2, "xargs: exec fails with -1\n"); + exit(1); + } + } + else { + memmove(buf, line_end + 1, occupy - (line_end - buf) - 1); + occupy -= line_end - buf + 1; + memset(buf + occupy, 0, buf_size - occupy); + int pid; + wait(&pid); + line_end = strchr(buf, '\n'); + } + } + } + exit(0); +} + +//============================lab2============================= +//trace +#include "kernel/param.h" +#include "kernel/types.h" +#include "kernel/stat.h" +#include "user/user.h" + +int +main(int argc, char *argv[]) +{ + int i; + char *nargv[MAXARG]; + + if(argc < 3 || (argv[1][0] < '0' || argv[1][0] > '9')){ + fprintf(2, "Usage: %s mask command\n", argv[0]); + exit(1); + } + + if (trace(atoi(argv[1])) < 0) { + fprintf(2, "%s: trace failed\n", argv[0]); + exit(1); + } + + for(i = 2; i < argc && i < MAXARG; i++){ + nargv[i-2] = argv[i]; + } + exec(nargv[0], nargv); + exit(0); +} + +//sysinfo +//在 kernel/sysproc.c 中实现 sys_sysinfo() 函数 +#include "sysinfo.h" +uint64 +sys_sysinfo(void) +{ + struct sysinfo info; + uint64 addr; // 用户空间指针 + if(argaddr(0, &addr) < 0) + return -1; + info.freemem = kfreemem(); + info.nproc = procnum(); + if(copyout(myproc()->pagetable, addr, (char *)&info, sizeof(info)) < 0) + return -1; + return 0; +} +//获取空闲内存量,在 kernel/kalloc.c 中添加: +uint64 +kfreemem(void) +{ + struct run *r; + uint64 n = 0; + acquire(&kmem.lock); + r = kmem.freelist; + while(r){ + n += PGSIZE; + r = r->next; + } + release(&kmem.lock); + return n; +} +//获取进程数量,在 kernel/proc.c 中添加: +uint64 +procnum(void) +{ + struct proc *p; + uint64 n = 0; + for(p = proc; p < &proc[NPROC]; p++){ + acquire(&p->lock); + if(p->state != UNUSED){ + n++; + } + release(&p->lock); + } + return n; +} +#include "kernel/types.h" +#include "kernel/sysinfo.h" +#include "user/user.h" +int +main(int argc, char *argv[]) +{ + struct sysinfo info; + if(sysinfo(&info) < 0){ + printf("sysinfo failed\n"); + exit(1); + } + printf("free memory: %d bytes\n", info.freemem); + printf("process count: %d\n", info.nproc); + exit(0); +} From 429ae26e68fa47ac8b0ebe0fb11d5dca580bb384 Mon Sep 17 00:00:00 2001 From: doge316 <2281751933@qq.com> Date: Sun, 8 Jun 2025 13:48:25 +0800 Subject: [PATCH 2/2] =?UTF-8?q?Create=20=E8=B5=9B=E9=A2=98=E4=B8=80?= =?UTF-8?q?=E6=96=87=E6=A1=A3.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...30\344\270\200\346\226\207\346\241\243.md" | 86 +++++++++++++++++++ 1 file changed, 86 insertions(+) create mode 100644 "\350\265\233\351\242\230\344\270\200\346\226\207\346\241\243.md" diff --git "a/\350\265\233\351\242\230\344\270\200\346\226\207\346\241\243.md" "b/\350\265\233\351\242\230\344\270\200\346\226\207\346\241\243.md" new file mode 100644 index 0000000..8209d6f --- /dev/null +++ "b/\350\265\233\351\242\230\344\270\200\346\226\207\346\241\243.md" @@ -0,0 +1,86 @@ +lab1: +1.sleep 略 + +2.pingpong 利用系统调用函数fork和pipe在父进程和子进程前交换一个字节即可 + +3.prime 需要使用管道和进程来筛选质数,进程间通过管道传递候选数字,每个质数对应一个新进程。 +a.每个进程需要从左侧管道读取数字,向右侧管道传递筛选后的数字,必须正确关闭不需要的管道端 +b.第一个进程生成初始数字序列 (2-35) +每个后续进程: +读取第一个数字作为质数 +过滤掉该质数的倍数 +将剩余数字传递给下一个进程 +需要注意的点: + 1. 一个进程怎么知道自己被分配的质数? + # 它从左手边进程读来的第一个数字就是自己的质数 + 2. 怎么从左边进程读数字? + # 写一个递归函数, 参数传进来一个pipe的读端fd + 3. 怎么等待子进程都结束保证进程生命周期链的正确性? + # 每个进程最多fork出一个子进程, 直接wait(int* pid)即可. 如果一个进程从没有fork过子进程, 那么它不需要等待 + * 代码过程中需要注意及时关闭一切用不到的file descriptors, 不然会超过xv6的系统fd上限 + +4.find 给定一个初始路径和目标文件名, 要不断递归的扫描找到所有子目录前匹配的文件全路径。 +实现这个功能需要解决以下几个关键问题: + 1. 区分文件和目录 + 使用 open() 打开路径 + 通过 fstat() 获取文件状态信息 + 检查 st.type 字段: + T_DIR 表示目录 + T_FILE 表示普通文件 + T_DEVICE 表示设备文件 + 2. + 使用 read() 系统调用读取目录条目 + 每个目录条目是 struct dirent 结构,包含文件名和inode号 + 跳过 inode 号为0的条目(空条目) + 跳过特殊目录 "." 和 ".."(当前目录和父目录) + 3. 使用递归处理流程 + 打开当前路径,获取文件状态,如果是普通文件,比较文件名与目标名,匹配则打印完整路径;如果是目录,读取每个目录条目,构造完整子路径,递归调用 find 处理子路径,关闭文件描述符。 + 4.需要留意边界处理 + +5.xargs 将标准输入里每一个以'\n'分割的行作为单独1个额外的参数, 传递并执行下一个命令. 这题主要感觉是考察fork + exec的使用. +滑动窗口buffer的管理比较难实现,其核心思想是​​重复利用固定大小的缓冲区​​,通过移动数据而非复制数据来处理输入流。 +具体做法: + 在缓冲区中查找换行符('\n') + 将换行符替换为字符串结束符('\0'),形成完整的参数字符串 + 处理完一行后,将剩余数据移动到缓冲区开头 + 更新缓冲区有效数据长度 + +lab2: + +1.trace 允许用户程序跟踪特定的系统调用执行情况 +需要注意的点: + 1.子进程会继承父进程的 trace_mask + 在 fork() 系统调用中复制掩码值 + 2.只在设置了跟踪掩码时检查系统调用 + 尽量减少跟踪带来的性能开销 + 3.只有当前进程的系统调用会被跟踪 + 不能跟踪其他进程的系统调用 + +2.sysinfo +实现包括 数据结构定义 系统调用注册 内核实现 辅助函数实现 +需要注意: +​​内存信息收集​​: +遍历空闲内存链表计算总空闲内存 +需要考虑锁机制保证线程安全 +​​进程计数​​: +遍历进程表统计非UNUSED状态的进程 +需要获取每个进程的锁 +​​运行时间获取​​: +直接使用现有的 uptime() 函数 +​​用户空间复制​​: +使用 copyout() 将内核数据复制到用户空间 +需要检查复制是否成功 + + + +附:实现成功的截图 +![BEF6758ACA6640474C47F3B83E4D1C90](https://github.com/user-attachments/assets/d91f0bb0-22e2-404d-bbae-d14dfd461925) +![aa3e79d5fc57c4d22ca4445133f9814e](https://github.com/user-attachments/assets/d5dc2ec8-ab2f-4c5a-8e3d-d3974ea33e94) +![55992046bda92f602fe7f6a2b2da1c0a](https://github.com/user-attachments/assets/19a149a5-dae7-4f3e-8355-ba430c192c45) +![711f4940cd8a3f01bf5ec2b031971d18](https://github.com/user-attachments/assets/98e70b9f-bfc0-45f3-a92b-59ca188bb734) +![2c7e3aa9319e90359ac2631d0ac304c0](https://github.com/user-attachments/assets/f2e15414-2aca-4365-945e-a8b4534aef4e) + + + + +