xv6-labs-2024 lab1

lab-1

注:實驗環境在我的匯編隨手記的末尾部分有搭建教程。

0.前置

第零章

xv6為我們提供了多種系統調用,其中,exec將從某個文件里讀取內存鏡像(這確實是一個好的說法),并且將其替換到調用它的內存空間,也就是這個打開的文件(一切皆文件)替換了當前的進程,exec僅僅是這樣的功能,同時,執行完成之后,exec并不會返回當前的調用進程,而是執行我們已經加載好的指令!

如果你閱讀過手寫docker或者類似講過相關概念的書,你一定會知道,我們執行命令事實上是通過創建一個子進程,再在子進程中exec我們需要的命令!

exec并不是執行程序這個操作的全部,而只是將當前進程替換為某個可執行文件的工具,它需要結合 fork 使用,才是完整的執行命令的流程。

而命令執行完成,我們的子進程就會調用exit,使得我們的父進程從wait中返回。

**文件描述符是啥?**一切皆文件,我們的文件描述符可以是管道,文件,目錄,socket的抽象,但是,值得注意的是,文件描述符并不代表了這個文件,而是指向這個文件的"指針",使得我們可以對其進行訪問,我們可以獲取多個指向同一個文件的文件描述符,并且能夠對其進行寫入,讀取操作。

應用比如cat指令,cat并不關心你的文件描述符指向的是什么,使得我們可以輕松的實現cat指令,所以文件描述符是一個很棒的抽象。

甚至,fork和文件描述符可以實現我們的重定向,比如當我們fork一個進程之后,關閉子進程的文件描述符0(標準輸入),然后重新打開一個我們指定的文件,文件描述符0指向的是我們指定的文件,也就是說,我們的標準輸入來自于文件,而不是鍵盤了!然后我們執行cat,就會打印出我們的文件內容,指令為:cat < test.txt

一般來說,通過dup和fork產生的文件描述符都將共享同一個偏移量,但是有一些特殊情況,這里不詳細說了。

管道

這段代碼值得分析,先創建一個管道,讀端文件描述符為p[0],寫端為p[1],在我們的子進程中,先將文件描述符0(標準輸入)關閉,然后調用我們的dup將文件描述符p[0]復制到標準輸入中,此時,我們的wc就可以從文件中讀取數據了,然后,我們還需要子進程的寫端,因為子進程中,寫端是無用的,如果不關閉,我們在wc進程中的read將會阻塞,無法返回。

而在父進程中,指向寫入,然后關閉就行了。

int p[2];
char *argv[2];
argv[0] = "wc";
argv[1] = 0;
pipe(p);
if(fork() == 0) {close(0);dup(p[0]);close(p[0]);close(p[1]);exec("/bin/wc", argv);
} else {write(p[1], "hello world\n", 12);close(p[0]);close(p[1]);
}

管道比臨時文件強大得多,管道支持自動銷毀,支持發送任意長度的數據,支持同步地進程間通信。

文件系統

我看這部分主要講的是文件就是一棵樹,前面沒啥好說的

mknod表示創建一個設備文件,其元信息標志他是一個設備,并且記錄了主設備號和輔設備號,他們確定了唯一設備,當進程打開這個文件的時候,內核會將讀寫操作轉發到相應的設備上,而不是文件系統。

fstat可以通過文件描述符獲取他所指向的文件的信息。

這里的一個概念也挺有意思的,就是文件名和文件有很大的區別,一個文件可以有多個文件名,一個文件名同一時刻指向一個文件(inode),比如說下面:

open("a", O_CREATE|O_WRONGLY);
link("a", "b");

這里創建了一個文件,然后通過link使得這個文件既叫a,又叫b,但是,此時我們如果執行unlink('a'),我們的inode和磁盤空間并不會被清空,因為此時我們的文件名b還指向它,所以一個文件的的inode和磁盤空間只有link數量為0的時候才會被清除

所以

fd = open("/tmp/xyz", O_CREATE|O_RDWR);
unlink("/tmp/xyz");

是創建一個臨時inode的最好方式。

1. Sleep

挺簡單的,應該就是讓我們提升自信心的,先fork一個子進程,在子進程中調用sleep,父進程等待。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"int main(int argc, char *argv[]) {if (argc != 2) {fprintf(1, "Usage: sleep seconds\n");exit(1);}   int pid = fork();if (pid == 0) {unsigned int seconds = atoi(argv[1]);sleep(seconds * 10);exit(0);} else {wait(0);}exit(0);
}

2. PingPong

大部分都是前置內容,也就是教材里面講過的,需要創建兩個管道,以供來相互通信,注意關閉讀寫端的時機:

#include "kernel/types.h"
#include "user/user.h"int main(int argc, char *argv[]) {int p1[2];int p2[2];pipe(p1);pipe(p2);int pid1 = fork();if (pid1 == 0) {close(p1[1]);close(p2[0]);char buf[1];read(p1[0], buf, 1);close(p1[0]);printf("%d: received ping\n", getpid());write(p2[1], "x", 1);close(p2[1]);exit(0);}int pid2 = fork();if (pid2 == 0) {close(p1[0]);close(p2[1]);write(p1[1], "x", 1);close(p1[1]);char buf[1];read(p2[0], buf, 1);close(p2[0]);printf("%d: received pong\n", getpid());write(p1[1], "x", 1);close(p1[1]);exit(0);}
}

3. Primes

我去,這個lab真牛逼,最核心的點就是dup去復用我們的管道,讓管道可以及時地被釋放,這真的很重要!否則你的程序大概率只能跑到40左右的數字(血的教訓),另外就是實驗要求使用埃拉托色尼篩法,這一點我最開始也搞不懂要怎么去在管道之間傳遞這個數字,其實就是pipe不熟悉,還是問了gpt才明白,可以一個一個傳,然后一個一個讀取。

然后dup的使用也是參考了別人的blog,感覺自己就是菜。

總之感覺還是挺神奇的。

#include "kernel/types.h"
#include "user/user.h"void primes(int p0[2]) __attribute__((noreturn));int main(int argc, char *argv[]) {int p[2];pipe(p);int pid = fork();if (pid == 0) {//管道的關閉邏輯在primes函數中primes(p);} else {close(p[0]);for (int i = 2; i <= 280; i++) {write(p[1], &i, sizeof(i));}close(p[1]);wait(0);}exit(0);
}void primes(int old_pipe[2]) {//及時釋放管道close(0);dup(old_pipe[0]);close(old_pipe[0]);close(old_pipe[1]);int prime;if (read(0, &prime, sizeof(prime)) == 0) {close(0);exit(0);}printf("prime %d\n", prime);//新建管道,并fork子進程int new_pipe[2];pipe(new_pipe);int pid = fork();if (pid == 0) {primes(new_pipe);} else {close(new_pipe[0]);int num;while (read(0, &num, sizeof(num))) {if (num % prime != 0) {write(new_pipe[1], &num, sizeof(num));}}close(0);close(new_pipe[1]);wait(0);}exit(0);
}

4. Find

實驗hint,讓我們可以從ls.c中知道怎么才可以展開當前目錄,這部分完全是參考了ls.c里面的方法,知道了這一點,我們就很好做判斷了。

#include "kernel/types.h"
#include "kernel/stat.h"
#include "user/user.h"
#include "kernel/fs.h"void find(char *path, char *filename);int main(int argc, char *argv[]) {if (argc != 3) {fprintf(2, "Usage: find filename with path\n");exit(1);}//遞歸搜索find(argv[1], argv[2]);exit(0);}void find(char *path, char *filename) {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_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)continue;memmove(p, de.name, DIRSIZ);p[DIRSIZ] = 0;if (stat(buf, &st) < 0) {printf("find: cannot stat %s\n", buf);continue;}if (st.type == T_FILE && strcmp(de.name, filename) == 0) {printf("%s\n", buf);}if (st.type == T_DIR && strcmp(de.name, ".") != 0 && strcmp(de.name, "..") != 0) {find(buf, filename);}}break;default:if (strcmp(path, filename) == 0) {printf("%s\n", path);}}close(fd);
}

這里有一個很有意思很有意思的東西,我直接跳轉到read的實現,實際上但是他會直接跳到qemu的文件里面,導致我以為我們的read是qemu封裝好的,但是實際上并不是,read確確實實我們的xv6自己實現的!我們可以通過這樣去追溯它的根源:

  1. 在/user/usys.S中,找到有關read的字段,可以看見,它調用了SYS_read。
  2. 回到/kernel/syscall.c,我們可以看見syscall_read的具體定義。
  3. 跳轉,我們會發現,調用了fileread這個函數,繼續跳轉
  4. 在這里,會調用一個至關重要的函數,就是read()
  5. 跳轉到這個函數里面,read就是我們讀取數據的關鍵函數

嗯。。這個函數還是蠻復雜的,先做下一個實驗吧


5. Xargs

我沒用過xargs,最開始可以說是一頭霧水,包括最開始做的時候,甚至還不知道可以傳遞多行參數,改了半天。

整體思路就是先將當前右側的參數讀取,然后循環從標準輸入中讀取數據,遇到換行符,則執行命令,然后重置當前的參數和緩沖區為初始狀態。

#include "kernel/types.h"
#include "user/user.h"
#include "kernel/param.h"int main(int argc, char *argv[]) {if (argc < 2) {fprintf(2, "Usage: xargs command [args...]\n");exit(1);}char *cmd = argv[1];char *args[MAXARG];int i, n = 0;// 復制參數for (i = 1; i < argc && n < MAXARG - 1; i++) {args[n++] = argv[i];}int end = n;//方便重置索引char buf[512];int m = 0;while (read(0, &buf[m], 1) == 1) {if (buf[m] == '\n') {buf[m] = 0;args[n++] = &buf[0];// 參數必須以 NULL 結尾args[n] = 0;int fd = fork();if (fd == 0) {exec(cmd, args);fprintf(2, "xargs: exec failed\n");exit(1);}wait(0);// 索引重置m = 0;n = end;} else {m++;}}exit(0);
}

lab1給我感覺倒是沒有太多關于os的知識,更多的是需要你去熟悉這個xv6的大體是什么樣的,給他添加一些組件。

目前來看,收獲更多的還得是xv6的教科書,那里面確實能夠學到很多東西,給我的感覺就是比其他我看過的任何操作系統課對小白都要友好得多。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/900518.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/900518.shtml
英文地址,請注明出處:http://en.pswp.cn/news/900518.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

屬性修改器 (AttributeModifier)

主頁面設置組件 import { MyButtonModifier } from ../datastore/MyButtonModifier;Entry ComponentV2 struct MainPage {// 支持用狀態裝飾器修飾&#xff0c;行為和普通的對象一致Local modifier: MyButtonModifier new MyButtonModifier();build() {Column() {Button(&quo…

【 <二> 丹方改良:Spring 時代的 JavaWeb】之 Spring Boot 中的監控:使用 Actuator 實現健康檢查

<前文回顧> 點擊此處查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、引子&…

類和對象(下篇)(詳解)

【本節目標】 1. 再談構造函數 2. Static成員 3. 友元 4. 內部類 5. 再次理解封裝 1. 再談構造函數 1.1 構造函數體賦值 在創建對象時&#xff0c;編譯器通過調用構造函數&#xff0c;給對象中各個成員變量一個合適的初始值。 #include <iostream> using name…

高精度算法

高精度加法 輸入兩個數&#xff0c;輸出他們的和&#xff08;高精度&#xff09; 輸入樣例 111111111111111111111111111111 222222222222222222222222222222 輸出樣例 333333333333333333333333333333 #include <bits/stdc.h> using namespace std;string a,b; in…

Linux開發中注意哪些操作系統安全

在 Linux 開發中&#xff0c;確保操作系統的安全至關重要。以下是一些需要注意的方面&#xff1a; 用戶管理與權限控制 合理設置用戶權限&#xff1a;為不同的用戶和用戶組分配適當的權限&#xff0c;遵循最小權限原則。避免給普通用戶過多的權限&#xff0c;以免他們誤操作或…

x64dbg調試python解釋器

可以先寫個input()這會讓dbg中斷在ntdll模塊中&#xff0c;查看調用堆棧在系統調用結束后的打斷點 然后直接斷到PyObject_Vectorcall函數

? Ultralytics YOLO驗證(Val)時自動輸出COCO指標(AP):2025最新配置與代碼詳解 (小白友好 + B站視頻)

? YOLO獲取COCO指標(3)&#xff1a;驗證(Val) 啟用 COCO API 評估&#xff08;自動輸出AP指標&#xff09;| 發論文必看&#xff01; | Ultralytics | 小白友好 文章目錄 一、問題定位二、原理分析三、解決方案與實踐案例步驟 1: 觸發 COCO JSON 保存步驟 2: 確保 self.is_coc…

【嵌入式學習3】基于python的tcp客戶端、服務器

目錄 1、tcp客戶端 2、tcp服務器 3、服務器多次連接客戶端、多次接收信息 1、tcp客戶端 """ tcp:客戶端 1. 導入socket模塊 2. 創建socket套接字 3. 建立tcp連接(和服務端建立連接) 4. 開始發送數據(到服務端) 5. 關閉套接字 """ import soc…

Linux: network: 兩臺直連的主機業務不通

前提環境,有一個產品的設定是兩個主機之間必須是拿網線直連。但是設備管理者可能誤將設置配錯,不是直連。 最近遇到一個問題,說一個主機發的包,沒有到對端,一開始懷疑設定的bond設備的問題,檢查了bond的設置狀態,發現沒有問題,就感覺非常的奇怪。后來就開始懷疑兩個主機…

COMSOL固體力學接觸

目錄 一、接觸非線性及接觸面積計算 一、接觸非線性及接觸面積計算 COMSOL接觸非線性及接觸面積計算_嗶哩嗶哩_bilibili 形成聯合體&#xff0c;在定義處右鍵選擇“建立接觸對” 位移dz使用參數化掃描。 接觸選擇定義中設置的接觸對&#xff0c;選擇罰函數&#xff0c;摩擦設置…

22.OpenCV輪廓匹配原理介紹與使用

OpenCV輪廓匹配原理介紹與使用 1. 輪廓匹配的基本概念 輪廓匹配&#xff08;Contour Matching&#xff09;是計算機視覺中的一種重要方法&#xff0c;主要用于比較兩個輪廓的相似性。它廣泛應用于目標識別、形狀分析、手勢識別等領域。 在 OpenCV 中&#xff0c;輪廓匹配主要…

oracle 快速創建表結構

在 Oracle 中快速創建表結構&#xff08;僅復制表結構&#xff0c;不復制數據&#xff09;可以通過以下方法實現&#xff0c;適用于需要快速復制表定義或生成空表的場景 1. 使用 CREATE TABLE AS SELECT (CTAS) 方法 -- 復制源表的全部列和數據類型&#xff0c;但不復制數據 C…

若依原理筆記

代碼生成器 源碼分析 查詢數據庫列表 導入表結構 生成代碼 修改generator.yml配置文件 代碼生成器增強 Velocity模版引擎 基礎語法-變量 Lombok集成 E:\javaProject\dkd-parent\dkd-generator\src\main\resources\vm\java\domain.java.vm package ${packageName}.domain;#fo…

Ansible的使用

##### Ansible使用環境 - 控制節點 - 安裝Ansible軟件 - Python環境支持&#xff1a;Python>2.6 - 必要的模塊&#xff1a;如PyYAML等 - 被控節點 - 啟用SSH服務 - 允許控制節點登錄&#xff0c;通常設置免密登錄 - Python環境支持 http://www.ansible.com/ …

C++ 提高編程:模板與 STL 深度剖析

摘要&#xff1a;本文深入探討 C 提高編程中的模板編程與標準模板庫&#xff08;STL&#xff09;相關內容。詳細闡述模板編程中函數模板和類模板的概念、語法、特性及應用案例&#xff1b;對 STL 的誕生背景、基本概念、六大組件進行剖析&#xff0c;并對常用容器、函數對象、常…

C++(類模板的運用)

使用vector實現一個簡單的本地注冊登錄系統 注冊&#xff1a;將賬號密碼存入vector里面&#xff0c;注意防重復判斷 登錄&#xff1a;判斷登錄的賬號密碼是否正確 #include <iostream> #include <vector> #include <fstream> #include <sstream> usi…

【大模型】DeepSeek+藍耕MaaS平臺+海螺AI生成高質量視頻實戰詳解

目錄 一、前言 二、藍耘智能云MaaS平臺介紹 2.1 藍耘智算平臺是什么 2.2 平臺優勢 2.3 平臺核心能力 三、海螺AI視頻介紹 3.1 海螺AI視頻是什么 3.2 海螺AI視頻主要功能 3.3 海螺AI視頻應用場景 3.4 海螺AI視頻核心優勢 3.5 項目git地址 四、藍耘MaaS平臺DeepSeek海…

接口自動化學習二:session自動管理cookie

session自動管理cookie&#xff1a; cookie中的數據&#xff0c;都是session提供的 實現步驟&#xff1a; 1.創建session對象&#xff1b;my_sessionrequests.Session() 2.使用session實例&#xff0c;調用get方法&#xff0c;發送獲取驗證碼請求&#xff08;不需要提取cookie&…

C++類型轉換詳解

目錄 一、內置 轉 內置 二、內置 轉 自定義 三、自定義 轉 內置 四、自定義 轉 自定義 五、類型轉換規范化 1.static_case 2.reinterpret_cast 3.const_cast 4.dynamic_cast 六、RTTI 一、內置 轉 內置 C兼容C語言&#xff0c;在內置類型之間轉換規則和C語言一樣的&am…

QEMU源碼全解析 —— 塊設備虛擬化(17)

接前一篇文章:QEMU源碼全解析 —— 塊設備虛擬化(16) 本文內容參考: 《趣談Linux操作系統》 —— 劉超,極客時間 《QEMU/KVM源碼解析與應用》 —— 李強,機械工業出版社 《KVM實戰 —— 原理、進階與性能調優》—— 任永杰 程舟,機械工業出版社