diff --git a/README.md b/README.md deleted file mode 100644 index 6fe3cd73d82564047b2983defc42e5e381ce6b16..0000000000000000000000000000000000000000 --- a/README.md +++ /dev/null @@ -1,124 +0,0 @@ -# Welcome to NPUcore👋 - -[](https://img.shields.io/badge/Lang-Rust-green) [](https://img.shields.io/badge/ISA-riscv64-yellowgreen) [](https://img.shields.io/badge/Platform-Qemu%2c%20k210%20%26%20Hifive%20Unmatched-yellow) - -### 简介 - -`NPUcore`是æ¥è‡ªè¥¿åŒ—工业大å¦çš„三ä½åŒå¦åŸºäºŽæ¸…åŽå¤§å¦`rCore Tutorial`框架,å‚è€ƒå€Ÿé‰´åŽ»å¹´å†…æ ¸èµ›é“优秀å‚赛队ä¼ä¸ŽLinuxå†…æ ¸çš„è¯¸å¤šä¼˜ç§€è®¾è®¡ï¼Œå¹¶ç»“åˆç¡¬ä»¶å¹³å°ç‰¹æ€§è¿›è¡Œä¼˜åŒ–å’Œé‡æž„ï¼Œä¸æ–è¿ä»£å½¢æˆçš„竞赛æ“作系统,现已支æŒ`qemu`ã€`k210`ã€`Hifive Unmatched`三平å°çš„è¿è¡Œã€‚ - -### 特性 - -+ å®Œå–„çš„å†…æ ¸åŠŸèƒ½æ”¯æŒ - -`NPUcore`æ ¹æ®Linux Manualæ”¯æŒæˆ–ä¸å®Œå…¨æ”¯æŒçš„系统调用多达87ä¸ªï¼Œä¸”è¾ƒä¸ºå®Œæ•´åœ°å®žçŽ°äº†ä¿¡å·æœºåˆ¶ï¼Œçº¿ç¨‹ç‰åŠŸèƒ½ï¼Œåœ¨å†³èµ›ç¬¬ä¸€é˜¶æ®µé’ˆå¯¹C库接å£çš„æµ‹è¯•程åº`libc-test`ä¸èŽ·å¾—äº†æ»¡åˆ†ã€‚ä½†æˆ‘ä»¬çš„ç›®æ ‡å¹¶ä¸ä»…仅是通过测试用例,而是希望`NPUcore`å…·æœ‰ä¸€å®šçš„è¶£å‘³æ€§å’Œå®žç”¨æ€§ï¼Œè¿™å°±è¦æ±‚`NPUcore`能够è¿è¡Œæ›´å¤šç”¨æˆ·ç¨‹åºã€‚å› æ¤æˆ‘们支æŒäº†bash这个许多Linuxå‘行版的默认shell,结åˆbusyboxå¯ä»¥èŽ·å¾—è¾ƒå¥½çš„CLI使用体验。 - -+ 精巧的内å˜ç®¡ç† - -`NPUcore`最åˆé¢å‘`k210`å¹³å°ï¼Œç”±äºŽ`k210`åªæœ‰8MB内å˜ç©ºé—´ï¼Œæœ‰é™çš„空间驱使`NPUcore`团队围绕内å˜ç®¡ç†åšäº†å¾ˆå¤šå·¥ä½œï¼šæ‡’分é…ã€å†™æ—¶å¤åˆ¶ã€zRAM,虚拟内å˜ç‰ã€‚这些机制使得内å˜èƒ½å¤Ÿå¾—到尽å¯èƒ½çš„利用,能够支撑更多用户程åºã€‚ - -+ 基于ç‰å¾…队列的阻塞 - -阻塞与éžé˜»å¡žæ˜¯èµ„æºè®¿é—®çš„ä¸¤ç§æ–¹å¼ã€‚在éžé˜»å¡žçš„资æºè®¿é—®ä¸‹ï¼Œé€šå¸¸è¦ä½¿ç”¨è½®è¯¢æ¥æ£€æŸ¥å¾…获å–çš„èµ„æºæ˜¯å¦å°±ç»ªï¼Œè¿™ç§å夿Ÿ¥è¯¢çš„æ“ä½œä¼šé€ æˆCPU资æºçš„æµªè´¹ã€‚`NPUCore`实现了基于ç‰å¾…队列的系统资æºè®¿é—®ï¼Œ`futex`ç‰ç³»ç»Ÿè°ƒç”¨ä½¿ç”¨ç‰å¾…队列实现,能够æé«˜å†…æ ¸äº‹ä»¶é€šçŸ¥å’Œèµ„æºè®¿é—®çš„æ•ˆçŽ‡ã€‚ - -+ å—缓å˜å’Œé¡µç¼“å˜ - -`NPUcore`团队通过对函数调用的跟踪统计å‘现文件系统在I/Oæ—¶çš„ç‰å¾…有æžå¤§çš„开销,为了æé«˜ç³»ç»ŸI/O性能, `NPUcore`实现了类似Linuxçš„Buffer Cache(å—缓å˜)å’ŒPage Cache(页缓å˜),Buffer Cache缓å˜å—设备上的数æ®å—ï¼ŒåŠ é€Ÿå¯¹å˜å‚¨å™¨çš„访问。Page Cacheç¼“å˜æ–‡ä»¶çš„逻辑内容, åŠ é€Ÿå¯¹æ–‡ä»¶å†…å®¹çš„è®¿é—®ã€‚æ¤å¤–,考虑到`k210`çš„å†…å˜æœ‰é™ï¼Œè€ŒBuffer Cacheå’ŒPage Cache之间åˆå˜åœ¨æ•°æ®å†—余,`NPUcore`å°è¯•å°†Buffer Cacheå’ŒPage Cache之间é‡å¤çš„æ•°æ®æ˜ 射到相åŒçš„物ç†é¡µï¼Œå¹¶ä¸”进行维护,确ä¿ä¸ä¼šå‡ºçŽ°ä¸€è‡´æ€§é—®é¢˜ã€‚è¿™æ ·èƒ½å¤Ÿæå‡å†…å˜åˆ©ç”¨çŽ‡ï¼Œå‡å°‘Buffer Cacheå’ŒPage Cache之间的拷è´ã€‚æ¤å¤–ï¼Œæˆ‘ä»¬è¿˜æ ¹æ®Fat区和数æ®åŒºçš„特性设计了ä¸åŒçš„缓å˜ç–略,使得文件系统的I/O性能大幅上å‡ã€‚ - -`NPUcore`使用较为激进的缓å˜ç–略,Page Cache容é‡ä¸è®¾ä¸Šé™ï¼Œæ‰€æœ‰çš„内å˜ç©ºé—´éƒ½å¯ä»¥ä½œä¸ºç¼“å˜ä½¿ç”¨ã€‚å‘生内å˜ä¸è¶³æ—¶ï¼Œ`NPUcore` ä¼šæ ¹æ®LRUç®—æ³•æ¸…ç†æ— 用缓å˜ã€‚ç»è¿‡æµ‹è¯•å‘现,在这ç§ç¼“å˜ç–略下è¿è¡Œå¤§å¤šæ•°æµ‹ä¾‹æ—¶ï¼Œå¯¹æ¯ä¸ªæ–‡ä»¶`NPUcore`åªä»Žå¤–å˜è¯»å–一次,之åŽçš„读写全部å‘生在Cacheä¸ï¼Œä»Žè€Œå¸¦æ¥æžå¤§çš„æ€§èƒ½æå‡ã€‚ - -+ é«˜æ•ˆå¯æ‰©å±•的虚拟文件系统 - -åœ¨å‰æœŸå¼€å‘ä¸ï¼Œ`NPUCore`团队注æ„到文件目录的查找æ“ä½œæ¯æ¬¡éƒ½éœ€è¦è®¿é—®åº•层文件系统,åå¤è¯»å–Fat区和数æ®åŒºï¼Œé€ æˆäº†å·¨å¤§çš„耗时。`NPUcore`在开å‘过程ä¸å¯¹è™šæ‹Ÿæ–‡ä»¶ç³»ç»Ÿè¿›è¡Œäº†é‡å†™ï¼Œå¼•å…¥äº†ç›®å½•æ ‘è¿™ä¸€æ•°æ®ç»“构,作为文件目录逻辑结构的缓å˜ï¼Œä¸€äº›æ–‡ä»¶ç³»ç»Ÿæ“作如切æ¢ç›®å½•ç‰åœ¨ç¼“å˜å‘½ä¸æ—¶ä¸å†éœ€è¦è®¿é—®åº•层文件系统,大幅å‡å°‘文件I/O,使文件æ“ä½œæ›´åŠ é«˜æ•ˆã€‚ - -å¦å¤–,在Linuxçš„VFSä¸ï¼ŒåŒä¸€æ–‡ä»¶æ“作å¯ä»¥é€šè¿‡å‡½æ•°æŒ‡é’ˆå®žçް坹ä¸åŒåº•层文件系统的函数调用,这其实是一ç§ç”±Cè¯è¨€å®žçŽ°çš„â€œå¤šæ€â€ã€‚æˆ‘ä»¬å€Ÿé‰´è¿™ç§æ€æƒ³ï¼Œä½¿ç”¨Rustçš„è¯æ³•将文件æ“作traitåŒ–ï¼Œè¿™æ ·èƒ½å¤Ÿè®©VFSå…·æœ‰æ›´é«˜çš„å¯æ‰©å±•性。 - -+ 稳定性 - -`NPUcore`éµå¾ªè½¯ä»¶å·¥ç¨‹çš„æ€æƒ³ï¼Œåœ¨æ¯æ¬¡åˆå¹¶æ–°æ¨¡å—åŽéƒ½ä¼šè¿›è¡ŒåŽ‹åŠ›æµ‹è¯•å’Œå›žå½’æµ‹è¯•ï¼Œèƒ½å¤Ÿå°½å¯èƒ½å‘现系统ä¸éšè—çš„bug。结åˆå®Œå–„çš„è¿è¡Œæ—¥å¿—系统,QEMU远程调试和JTAG硬件调试,å¯ä»¥è¿…速定ä½é—®é¢˜å¹¶åŠ ä»¥è§£å†³ã€‚è¿™ä½¿å¾—`NPUcore`有相当的稳定性,能够在`k210`开呿¿ä¸Šå¾ªçޝè¿è¡Œå†³èµ›æµ‹ä¾‹é•¿è¾¾6å°æ—¶ã€‚ - -### å†³èµ›ç¬¬ä¸€é˜¶æ®µå®Œæˆæƒ…况 - -`NPUcore`在决赛第一阶段完æˆäº†`libc-test`的所有测试用例的支æŒï¼Œæ‹¿åˆ°äº†`k210`èµ›é“220分满分的æˆç»©ï¼ŒåŒæ—¶ä¹Ÿæ”¯æŒäº†`fu740`å¹³å°ï¼Œåœ¨`Unmatched`èµ›é“æ‹¿åˆ°äº†æ»¡åˆ†ï¼Œæˆä¸ºäº†ä¸ºæ•°ä¸å¤šçš„æ”¯æŒåŒèµ›é“的队ä¼ä¹‹ä¸€ã€‚ - -##### k210èµ›é“ - - -##### unmatchedèµ›é“ - - - -### åˆ†æ”¯ä»‹ç» - -- master——最新代ç åŠæ–‡æ¡£ -- comp-1——åˆèµ›æäº¤åˆ†æ”¯ -- comp-2——决赛一阶段æäº¤åˆ†æ”¯ï¼ˆk210) -- comp-2-qemu——决赛一阶段æäº¤åˆ†æ”¯ï¼ˆqemu) -- comp-2-fu740——决赛一阶段æäº¤åˆ†æ”¯ï¼ˆfu740) -- comp-3——决赛二阶段æäº¤åˆ†æ”¯ï¼ˆk210) -- comp-3-qemu——决赛二阶段æäº¤åˆ†æ”¯ï¼ˆqemu) -- comp-3-fu740——决赛二阶段æäº¤åˆ†æ”¯ï¼ˆfu740) -- extend——扩展内容 - -### 如何è¿è¡Œ - -**交互å¼è¿è¡Œ** - -准备工作 - -````shell -make all # 构建`bash`与`initproc` -cd os && make fat32 # 进入`os`ç›®å½•ï¼Œæž„å»ºæ–‡ä»¶ç³»ç»Ÿé•œåƒ -```` - -在QEMU上è¿è¡Œï¼š - -````shell -make run # 直接è¿è¡Œ -```` - -在k210上è¿è¡Œï¼š - -````shell -make sdcard # 将文件系统镜åƒå†™å…¥sdcard -make run BOARD=k210 # 烧写è¿è¡Œ -```` - -PS: - -1. 在OSè¿è¡Œæ—¶ç›´æŽ¥å…³é—模拟器或者拔下k210æœ‰æ¦‚çŽ‡å†™åæ–‡ä»¶ç³»ç»Ÿï¼Œå¦‚æžœé‡åˆ°è¿™ç§æƒ…å†µï¼Œè¯·é‡æ–°æž„建文件系统镜åƒï¼ˆå°†æ–‡ä»¶ç³»ç»Ÿé•œåƒé‡æ–°å†™å…¥sdcard)。 -2. 按以上æ¥éª¤æž„建的文件系统镜åƒä»…å«`initproc`å’Œ`bash`,如果需è¦ä½¿ç”¨æ›´å¤šç”¨æˆ·ç¨‹åºï¼Œè¯·ä¿®æ”¹`buildfs.sh`或者手动将ELF文件拷è´åˆ°é•œåƒä¸ã€‚ - -### 模å—与特性相关文档 - -+ [ä¿¡å·](./Doc/os/signal.md) -+ [oom handler](./Doc/os/oom.md) -+ [Page Fault & CoW](./Doc/mm/page_fault.md) -+ [futex系统调用](./Doc/task/futex.md) -+ [修改RustSBI处ç†ä¸å¯¹é½è¯»](./Doc/debug/rustsbi%E4%B8%8D%E5%AF%B9%E9%BD%90%E8%AF%BB.md) -+ [常数优化](./Doc/debug/常数优化相关方法.md) - -### Fat32文件系统教程 - -`NPUcore`åœ¨å¼€å‘æ–‡ä»¶ç³»ç»Ÿçš„åŒæ—¶è®°å½•了开å‘çš„å¿ƒè·¯åŽ†ç¨‹ï¼Œæ•´ç†æˆäº†ä¸€ä»½æ•™ç¨‹ã€‚`NPUcore`团队的ç†å¿µæ˜¯ï¼šå¯¹çš„æ–¹å¼åƒç¯‡ä¸€å¾‹ï¼Œé”™çš„æ–¹å¼åƒå¥‡ç™¾æ€ªï¼Œä¸ºä»€ä¹ˆæ˜¯é”™çš„æ¯”ä»€ä¹ˆæ˜¯å¯¹çš„æ›´åŠ é‡è¦ã€‚所以这份教æä¼šè®°å½•我们走过的弯路,希望能够为那些想从零开始写Fat32文件系统的人æä¾›ä¸€äº›å¸®åŠ©ã€‚ - -+ [æ¥è‡ªNPUcoreçš„Fat32文件系统教程](./Doc/fs/fat.md) -+ [Linux下的çŸç›®å½•å生æˆ](./Doc/fs/Linux%E4%B8%8B%E7%9A%84%E7%9F%AD%E7%9B%AE%E5%BD%95%E5%90%8D%E7%94%9F%E6%88%90.md) -+ [ä»£ç æ–‡æ¡£: easy-fs-doc](./Doc/fs/easy-fs-doc.md) - -### Debug相关文档 - -以下是我们在开å‘ä¸é‡åˆ°çš„å„ç§bug和解决方法。 - -+ [Virt-IO驱动跨页问题](./Doc/debug/Virt-IO%E9%A9%B1%E5%8A%A8bug.md) -+ [浮点寄å˜å™¨çš„ä¿å˜](./Doc/debug/%E6%B5%AE%E7%82%B9%E5%AF%84%E5%AD%98%E5%99%A8bug.md) -+ [清ç†é¡µç¼“å˜å¯¼è‡´æ»é”](./Doc/debug/%E6%B8%85%E7%90%86%E9%A1%B5%E7%BC%93%E5%AD%98%E6%AD%BB%E9%94%81.md) -+ [read/write错误返回EFAULT](./Doc/debug/EFAULT技术细节.md) -+ [viä¸èƒ½è¾“å…¥](./Doc/debug/viä¸èƒ½è¾“å…¥bug.md) -+ [vi返回异常](./Doc/debug/vi返回异常bug.md) - -### 其他技术细节 - -+ [页表项刷新相关细节](./Doc/debug/%E9%A1%B5%E8%A1%A8%E9%A1%B9%E5%88%B7%E6%96%B0%E7%9B%B8%E5%85%B3%E7%BB%86%E8%8A%82.md) -+ [Rustçš„ä¼ é”æ–¹æ³•](./Doc/debug/Rust%E7%9A%84%E4%BC%A0%E9%94%81%E6%96%B9%E6%B3%95.md) -+ [æå‡SDå¡é©±åŠ¨ç¨³å®šæ€§](./Doc/debug/sd%E5%8D%A1%E9%A9%B1%E5%8A%A8%E5%93%8D%E5%BA%94%E5%A4%B1%E8%B4%A5bug.md) -+ [TTY回显问题](./Doc/debug/TTYä¸å›žæ˜¾bug.md) diff --git a/os/src/syscall/process.rs b/os/src/syscall/process.rs index 6649f99cedebed02de2deba58ca085eb52b60bc2..28a0a2cd7a8683d71150f2754cc549ee4af2207f 100644 --- a/os/src/syscall/process.rs +++ b/os/src/syscall/process.rs @@ -495,7 +495,7 @@ pub fn sys_clone( // } pub fn sys_fork(stack: *const u8, ptid: *mut u32, tls: usize, ctid: *mut u32) -> isize { - sys_clone(28, stack, ptid, tls, ctid) + sys_clone(17, stack, ptid, tls, ctid) } pub fn sys_execve( diff --git "a/\346\226\207\346\241\243/image/QQ20241223-204809.png" "b/\346\226\207\346\241\243/image/QQ20241223-204809.png" new file mode 100644 index 0000000000000000000000000000000000000000..004fe1a176772da191337dd6eaa71a5e52bdb415 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-204809.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-204848.png" "b/\346\226\207\346\241\243/image/QQ20241223-204848.png" new file mode 100644 index 0000000000000000000000000000000000000000..fdc4f891f4625d286f2fdba3824de149f2bc128b Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-204848.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-204951.png" "b/\346\226\207\346\241\243/image/QQ20241223-204951.png" new file mode 100644 index 0000000000000000000000000000000000000000..9a7271635563b2dcea4a794f4d7e873ba2de9747 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-204951.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-210122.png" "b/\346\226\207\346\241\243/image/QQ20241223-210122.png" new file mode 100644 index 0000000000000000000000000000000000000000..a5cb58735f62e704128957b49734f60d90c1e2c7 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-210122.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-210809.png" "b/\346\226\207\346\241\243/image/QQ20241223-210809.png" new file mode 100644 index 0000000000000000000000000000000000000000..0800dd9a5284f0565fe0f1e3ffe6076bf5f677dd Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-210809.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-211716.png" "b/\346\226\207\346\241\243/image/QQ20241223-211716.png" new file mode 100644 index 0000000000000000000000000000000000000000..eba722272177ae50daaa6d76cc87b43164848d38 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-211716.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-212050.png" "b/\346\226\207\346\241\243/image/QQ20241223-212050.png" new file mode 100644 index 0000000000000000000000000000000000000000..d3c9a62db6da851321b49e677fae540859729765 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-212050.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-212523.png" "b/\346\226\207\346\241\243/image/QQ20241223-212523.png" new file mode 100644 index 0000000000000000000000000000000000000000..d6b34da4196f7c632f0d8ffbd4673104228a4340 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-212523.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-213317.png" "b/\346\226\207\346\241\243/image/QQ20241223-213317.png" new file mode 100644 index 0000000000000000000000000000000000000000..d914162e87c525add13ad365d14fadf1e466b76b Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-213317.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-221654.png" "b/\346\226\207\346\241\243/image/QQ20241223-221654.png" new file mode 100644 index 0000000000000000000000000000000000000000..953f2443fadeffcd64e38f92c46a9e28b2767438 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-221654.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-222942.png" "b/\346\226\207\346\241\243/image/QQ20241223-222942.png" new file mode 100644 index 0000000000000000000000000000000000000000..3d22f7185567b0ce09f55ea2dfab6a94ea070d48 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-222942.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-223904.png" "b/\346\226\207\346\241\243/image/QQ20241223-223904.png" new file mode 100644 index 0000000000000000000000000000000000000000..608c32596f2ede728a11f0a936449d2ad11e6be9 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-223904.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-224648.png" "b/\346\226\207\346\241\243/image/QQ20241223-224648.png" new file mode 100644 index 0000000000000000000000000000000000000000..22ca0c0708ac72f051f27b54afee21e58d17d481 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-224648.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-225538.png" "b/\346\226\207\346\241\243/image/QQ20241223-225538.png" new file mode 100644 index 0000000000000000000000000000000000000000..d7cb0d0b9860e06cb945ba898c054938c215b67d Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-225538.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-230214.png" "b/\346\226\207\346\241\243/image/QQ20241223-230214.png" new file mode 100644 index 0000000000000000000000000000000000000000..4c1e94f284a6f37551eb4c62430c71bede15e4dd Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-230214.png" differ diff --git "a/\346\226\207\346\241\243/image/QQ20241223-230416.png" "b/\346\226\207\346\241\243/image/QQ20241223-230416.png" new file mode 100644 index 0000000000000000000000000000000000000000..b639b499fcbcbdc1285963a5fddb9226e8485460 Binary files /dev/null and "b/\346\226\207\346\241\243/image/QQ20241223-230416.png" differ diff --git "a/\346\226\207\346\241\243/\345\214\272\345\237\237\350\265\233\346\226\207\346\241\243.md" "b/\346\226\207\346\241\243/\345\214\272\345\237\237\350\265\233\346\226\207\346\241\243.md" new file mode 100644 index 0000000000000000000000000000000000000000..4c56db1e6cc32de746b5554f4d76bbec8bf8b8d2 --- /dev/null +++ "b/\346\226\207\346\241\243/\345\214\272\345\237\237\350\265\233\346\226\207\346\241\243.md" @@ -0,0 +1,1613 @@ +# 区域赛文档 + +## **仓库准备** + +拉å–仓库 + +```bash +git clone https://gitlab.eduxiji.net/2019301887/oskernel2022-npucore.git + +cd oskernel2022-npucore +``` + +清除git历å²è®°å½•ï¼Œåˆ åŽ» .git éšè—文件夹 + +linux系统下: + +```bash +rm -rf .git +``` + +## **比赛平å°ä»“库建立** + +1.按照手册建立仓库。 + +2.å› ä¸º`riscv64-linux-musl-cross`在测评平å°ä¼šæä¾›ï¼Œå› æ¤æ— éœ€ä¸Šä¼ è‡³ä»“åº“ï¼Œå‰©ä¸‹çš„æ–‡ä»¶å¯ä»¥ä¸€æ¬¡æäº¤ã€‚ + +按照如下指令执行: + +```bash +git config --global user.name "wyyhhh" +git config --global user.email "t202410699994200@eduxiji.net" +git init --initial-branch=main +git remote add origin https://gitlab.eduxiji.net/T202410699994200/oskernel2024-wyh-NPU.git +(å¯çœç•¥ +git add riscv64-linux-musl-cross +git commit -m "Initial commit" +git push -u origin main +) +git add . +git commit -m "Initial commit" +git push -u origin main +``` + +如果ä¸å°å¿ƒæŠŠ`riscv64-linux-musl-cross`æäº¤è‡³ä»“库,å¯ä»¥é€šè¿‡ä»¥ä¸‹å‘½ä»¤å°†ä»“库ä¸çš„åˆ é™¤ï¼š + +```bash +1.å¦‚æžœä½ åªæƒ³ä»Žç‰ˆæœ¬æŽ§åˆ¶ä¸åˆ 除文件夹而ä¿ç•™æœ¬åœ°å‰¯æœ¬ï¼Œå¯ä»¥åŠ ä¸Š --cached: +git rm -r --cached folder_name +2.æäº¤æ›´æ”¹ï¼š æäº¤åˆ 除æ“作: +git commit -m "Deleted folder riscv64-linux-musl-cross" +3.推é€åˆ°è¿œç¨‹ä»“库: æŽ¨é€æ›´æ”¹åˆ° GitLab: +git push origin branch_name +å°† branch_name 替æ¢ä¸ºä½ æ£åœ¨ä½¿ç”¨çš„分支(如 main 或 master)。 +``` + +以上内容进行完æˆä¹‹åŽï¼Œå°±å¯ä»¥åœ¨å¹³å°ä¸Šç¼–译è¿è¡ŒæˆåŠŸï¼Œå¾—åˆ°ä¸€ä¸ª0分的结果了。具体怎么得到分数,需è¦ä¸‹é¢çš„æ¥éª¤ã€‚ + +## åˆ·å…¥æµ‹è¯„é•œåƒ + +### 详情å¯å‚考如下链接ä¸çš„æ¥éª¤ï¼š + +[适é…区域赛评测]: https://gitlab.eduxiji.net/202310699101073/oskernel2023-npucore-plus/-/blob/comp-1-qemu/docs/ForOJ.md + +### 除了文档ä¸çš„æ¥éª¤è¿˜éœ€è¦ï¼š + +**1**.**完善shutdown()的系统调用** + +osä¸çš„调用: + + + +userä¸çš„调用: + + + +**2**.**å°†RELEASEå˜é‡è®¾ç½®ä¸º --release,将构建优化为å‘布版本** + + + +以上内容进行完æˆä¹‹åŽï¼Œå°±å¯ä»¥å¾—åˆ°ä¸€ä¸ªåˆæ¥çš„分数了。 + +## å…·ä½“ç³»ç»Ÿè°ƒç”¨çš„å®Œæˆ + +如果使用的是2022版的NPUcore,到这里就å¯ä»¥å¾—到91分,还剩下4个系统调用ç‰å¾…完善,分别是openat()ã€getppid()ã€pipe()ã€dup2()。 + +å°æç¤ºï¼šæƒ³è¦ä¿®æ”¹å‡ºæ£ç¡®çš„系统调用,当然è¦çŸ¥é“平尿˜¯æ€Žä¹ˆæµ‹è¯„自己的系统调用的,å¯ä»¥åœ¨ä¸‹é¢çš„é“¾æŽ¥ä¸æŸ¥çœ‹æµ‹è¯„çš„.c文件和.py文件: + +[测例代ç ]: https://github.com/oscomp/testsuits-for-oskernel/tree/main/riscv-syscalls-testing/user/src/oscomp + +想è¦åœ¨æœ¬åœ°è·‘测评,就需è¦åœ¨ä¸‹é¢çš„链接下载压缩包: + +[测评镜åƒåŽ‹ç¼©åŒ…]: https://gitlab.eduxiji.net/202310699101073/oskernel2023-npucore-plus/-/blob/comp-1-qemu/sdcard.img.gz + +å°†åŽ‹ç¼©åŒ…æ”¾åœ¨æ ¹ç›®å½•ä¸‹ï¼Œç„¶åŽæ¥è§£åŽ‹ sdcard.img.gz: + +```bash +gunzip -c sdcard.img.gz > sdcard.img +``` + +è¿è¡Œå‘½ä»¤ï¼ˆæ¯æ¬¡è¿è¡Œå‰è¦å…ˆ`make clean`): + +```bash +make all +qemu-system-riscv64 -machine virt -kernel kernel-qemu -m 128M -nographic -smp 2 -bios sbi-qemu -drive file=sdcard.img,if=none,format=raw,id=x0 -device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 +``` + +下é¢ä¾æ¬¡è¿›è¡Œ4个系统调用的完善: + +### 1.openat(打开文件) + +è¿è¡ŒåŽå‘çŽ°å…‰æ ‡å¡ä½äº†ï¼š + + + +这时候就需è¦è¿›è¡ŒGDBè°ƒè¯•ï¼Œé€æ¥è§‚察代ç 在哪里åœä¸‹ï¼Œå‘现åœåœ¨è¿™ä¸€è¡Œï¼š + + + +那么一定是这一行出现的问题,往å‰çœ‹ï¼Œå¯ä»¥çœ‹åˆ°`681`è¡Œæœ‰ä¸€ä¸ªå’Œè¯¥è¡Œå‡ ä¹Žä¸€æ ·çš„è¡¨è¾¾ï¼Œè€Œä¸”ç”±äºŽè¿™è¡Œä»£ç çš„æ„æ€æ˜¯ç»™`task`åŠ é”以防æ¢å¤šè¿›ç¨‹å¹¶å‘å¯èƒ½å¯¼è‡´çš„é—®é¢˜ï¼Œæ‰€ä»¥ä¸¤æ¬¡åŠ é”å°±å¯ä»¥æ–定这里产生了`æ»é”`ï¼Œå’Œå…‰æ ‡åœé¡¿çš„现象也å»åˆã€‚ + +将该行注释掉之åŽï¼Œå†æ¬¡è¿è¡Œå°±å¯ä»¥å‘现该测试点已ç»é€šè¿‡ï¼Œåˆ†æ•°ä¹Ÿæ¥åˆ°äº†95分。 + +### 2.getppid(获å–父进程 ID ) + +é¦–å…ˆè¦æ˜Žç™½PPID是(Parent Process ID)的缩写,指的是父进程的进程ID。 + +直接è¿è¡Œå¾—到结果: + + + +这时候会一头雾水,怎么æ‰èƒ½ç®—success呢,这时测例代ç 就起了大作用: + +```c +int test_getppid() +{ + TEST_START(__func__); + pid_t ppid = getppid(); + if(ppid > 0) printf(" getppid success. ppid : %d\n", ppid); + else printf(" getppid error.\n"); + TEST_END(__func__); +} +``` + +很明显å¯ä»¥çœ‹å‡ºéœ€è¦ppid大于0,æ‰èƒ½é€šè¿‡æµ‹è¯„,那么现在的ppid是多少呢? + +å¯ä»¥æ‰“å°ä¸€ä¸‹ï¼š + + + +ppidåŽŸæ¥æ˜¯0ï¼Œé‚£ç¡®å®žæ— æ³•é€šè¿‡ã€‚å¦‚æžœä»…ä»…æƒ³é€šè¿‡æµ‹è¯„ï¼Œå¯ä»¥ç®€å•地将函数返回值强制设置为1,而ä¸å…³å¿ƒppidçš„çœŸå®žå€¼ï¼Œä½†æ˜¯è¿™æ˜¾ç„¶ä¸æ˜¯ä¸»åŠžæ–¹æƒ³è¦çš„,就需è¦è¿½å¯»æ›´æ·±å±‚çš„åŽŸå› ï¼Œé‡äº‹ä¸å†³GDB: + +在父进程创建的æŸä¸€æ¥ï¼Œå‘现æ¥åˆ°äº†è¿™é‡Œï¼š + + + +这一æ¥çš„功能是在pid分é…器ä¸å¼¹å‡ºä¸€ä¸ªç©ºé—²çš„pid给当å‰è¿›ç¨‹ï¼Œé‚£ä¹ˆppid应该是在这一æ¥å¾—到0,观察一下,å‘现currentæ¤æ—¶æ˜¯0,那弹出的å¯ä¸å°±æ˜¯0嘛,完全对上了,想è¦ppid大于0,就把分é…器ä¸çš„åˆå§‹pid(也就是current)设置为从1开始ä¸å°±å¥½äº†å—,修改之åŽå†æ¬¡è¿è¡Œï¼š + + + +å®Œç¾Žé€šè¿‡ï¼æ‰“å°çš„ppid也确实是1了,但是别得æ„忘形了,一定è¦è®°å¾—把打å°è¯å¥åŽ»æŽ‰å†æäº¤ï¼Œå› ä¸ºæµ‹è¯„æ–‡ä»¶æ˜¯ä¸¥æ ¼åŒ¹é…å—符的,打å°å—符会扰乱,导致0分。这时候应该å¯ä»¥å¾—到96分。 + +### 3.pipe(创建管é“) + +直接è¿è¡Œï¼š + + + +上测例代ç : + +```python +def test(self, data): + self.assert_ge(len(data), 3) + cpid0 = False + cpid1 = False + for line in data[:3]: + if line == "cpid: 0": + cpid0 = True + continue + r = re.findall(r"cpid: (\d+)", line) + if r and int(r[0]) > 0: + cpid1 = True + continue + self.assert_equal(cpid0, True) + self.assert_equal(cpid1, True) + self.assert_equal(data[2], " Write to pipe successfully.") +``` + +å‘现,并没有打å°" Write to pipe successfully." + +pipe.c: + +```c +void test_pipe(void){ + TEST_START(__func__); + int cpid; + char buf[128] = {0}; + int ret = pipe(fd); + assert(ret != -1); + const char *data = " Write to pipe successfully.\n"; + cpid = fork(); + printf("cpid: %d\n", cpid); + if(cpid > 0){ + close(fd[1]); + while(read(fd[0], buf, 1) > 0) + write(STDOUT, buf, 1); + write(STDOUT, "\n", 1); + close(fd[0]); + wait(NULL); + }else{ + close(fd[0]); + write(fd[1], data, strlen(data)); + close(fd[1]); + exit(0); + } + TEST_END(__func__); +} +``` + +cpid>0时读,cpid=0时写,于是父进程为读端,åè¿›ç¨‹ä¸ºå†™ç«¯ï¼Œä»£ç æ¶‰åŠçš„系统调用有两个,pipe()和readï¼ˆï¼‰ï¼Œå› ä¸ºè°ƒè¯•å¹¶æœªå‘现pipe()有错误,那么就把目光放在readï¼ˆï¼‰ä¸Šï¼Œè¿˜æ˜¯ä¸€æ ·çš„ï¼Œçœ‹ä¸€ä¸‹åœ¨å“ªé‡Œå‡ºçš„æµ‹è¯•ç‚¹ï¼š + + + +在这一æ¥ä¹‹åŽread_user函数就准备退出了,所以这个ifåˆ¤æ–æ˜¯æˆç«‹çš„,在å˜é‡å¤„也å¯ä»¥çœ‹åˆ°sigmask=0,sigpending=65536(2^16),而这个值就是clone函数ä¸çš„ä¸€ä¸ªå‚æ•°ï¼Œå³SIGCHLD,代表å进程的退出,å进程的退出代表管é“的写端已ç»å®Œæˆäº†å†™ï¼Œä¸‹é¢è¦åˆ°çˆ¶è¿›ç¨‹ï¼ˆå³è¯»ç«¯ï¼‰è¿›è¡Œè¯»å–,但是由于父进程收到å进程退出的信å·SIGCHLD,导致ifåˆ¤æ–æˆç«‹ï¼Œè¿˜æ²¡æœ‰è¿›è¡Œè¯»å–便结æŸè¯»ç«¯ï¼Œä¼˜å…ˆå¤„ç†åè¿›ç¨‹çš„é€€å‡ºï¼Œåˆ°è¿™é‡Œæ”¹æ³•ä¹Ÿé€æ¸æ˜Žæœ—,测试点想è¦çš„æ— éžæ˜¯çˆ¶è¿›ç¨‹å¯ä»¥è¯»åˆ°å—ç¬¦ï¼Œç„¶åŽæŠŠå—符显示在终端,那把整个if判æ–去掉,使父进程读完å†é€€å‡ºå°±å¯ä»¥ï¼Œå†æ¬¡è¿è¡Œï¼š + + + +GDB跟踪也是å¯ä»¥çœ‹å‡ºçˆ¶è¿›ç¨‹æ¯æ¬¡è¯»ä¸€ä¸ªå—ç¬¦ï¼Œç„¶åŽæ‰“å°ã€‚这次就通过了,分数也æ¥åˆ°äº†100分。 + +### 4.dup2(文件æè¿°ç¬¦å¤åˆ¶å¹¶è®¾ç½®æ ‡å¿—) + +æ ¹æ®ç³»ç»Ÿè°ƒç”¨å·è¦æ˜Žç™½dup2就是代ç ä¸çš„dup3。 + +直接è¿è¡Œï¼š + + + +dup2.c: + +```c +void test_dup2(){ + TEST_START(__func__); + int fd = dup2(STDOUT, 100); + assert(fd != -1); + const char *str = " from fd 100\n"; + write(100, str, strlen(str)); + TEST_END(__func__); +} +``` + +å‘现应该打å°å‡º" from fd 100\n"ï¼Œä¹Ÿæ˜¯æœ‰ç‚¹æ— ä»Žä¸‹æ‰‹ï¼Œç›´æŽ¥å¼€å§‹è°ƒè¯•ï¼š + +首先到这一æ¥ï¼š + + + +å¯ä»¥çœ‹åˆ°å˜é‡éƒ¨åˆ†ï¼Œcurrent=4,pos=100,所以è¦åˆ°else部分,首先判æ–pos是å¦å¤§äºŽsoft_limitï¼Œä¹Ÿå°±æ˜¯è½¯ä»¶è¦æ±‚的最大值,å†ä¸‹ä¸€æ¥è¿™ä¸ªå‡½æ•°å°±è¿”回了,于是推æ–pos大于soft_limit,直接返回Error了,查找soft_limit的值: + + + +å‘现soft_limit=64,确实å°äºŽposçš„100,那改大ä¸å°±å¥½äº†ï¼Œä¸ºäº†ä¿è¯è®¡ç®—机内部二进制,改为128å³å¯ï¼Œå†æ¬¡è¿è¡Œï¼š + + + +æˆåŠŸæ‰“å°å‡ºç»“果,分数也æ¥åˆ°äº†102分,至æ¤ï¼Œç³»ç»Ÿè°ƒç”¨çš„修改告一段è½ã€‚ + +## æ“作系统整体讲解 + +### 系统调用 + +#### 概述 + +1. **系统调用的概念与作用** + - **系统调用的定义**:系统调用是应用程åºä¸Žæ“ä½œç³»ç»Ÿå†…æ ¸ä¹‹é—´çš„æŽ¥å£ï¼Œå®ƒå…许应用程åºè¯·æ±‚å†…æ ¸æ‰§è¡Œç‰¹å®šçš„æ“作,如文件读写ã€è¿›ç¨‹ç®¡ç†ã€è®¾å¤‡æŽ§åˆ¶ç‰ã€‚在 NPUcore æ“作系统ä¸ï¼Œç³»ç»Ÿè°ƒç”¨æ˜¯é€šè¿‡è½¯ä»¶ä¸æ–(如 ecall 指令)触å‘的,将控制æƒä»Žç”¨æˆ·æ€è½¬ç§»åˆ°å†…æ ¸æ€ï¼Œç”±å†…æ ¸æ‰§è¡Œç›¸åº”çš„æ“作。 + - **系统调用的作用**:æ“ä½œç³»ç»Ÿé€šè¿‡ç³»ç»Ÿè°ƒç”¨æ¥æä¾›å¯¹ç¡¬ä»¶èµ„æºçš„æŠ½è±¡å’Œç®¡ç†ï¼Œä½¿å¾—应用程åºèƒ½å¤Ÿæ–¹ä¾¿åœ°ä½¿ç”¨ç³»ç»Ÿèµ„æºï¼Œè€Œæ— éœ€äº†è§£ç¡¬ä»¶çš„ç»†èŠ‚ã€‚åŒæ—¶ï¼Œç³»ç»Ÿè°ƒç”¨ä¹Ÿæä¾›äº†ä¸€ç§å®‰å…¨æœºåˆ¶ï¼Œé˜²æ¢åº”用程åºç›´æŽ¥è®¿é—®å†…æ ¸æ•°æ®å’Œæ‰§è¡Œæ•感æ“ä½œï¼Œä¿æŠ¤ç³»ç»Ÿçš„ç¨³å®šæ€§å’Œå®‰å…¨æ€§ã€‚ +2. **系统调用的实现机制** + - **䏿–机制**:在 RISC-V 架构下,系统调用是通过 ecall 指令触å‘çš„ä¸æ–æ¥å®žçŽ°çš„ã€‚å½“ç”¨æˆ·æ€ç¨‹åºæ‰§è¡Œ ecall æŒ‡ä»¤æ—¶ï¼Œä¼šé™·å…¥å†…æ ¸æ€ï¼Œè·³è½¬åˆ° STVEC 寄å˜å™¨ä¸æŒ‡å®šçš„䏿–处ç†ç¨‹åºï¼ˆtrap_handler 函数)进行相应的æ“ä½œã€‚ä¸æ–处ç†ç¨‹åºä¼šæ ¹æ®ç³»ç»Ÿè°ƒç”¨å·æ¥åˆ†å‘处ç†ä¸åŒçš„系统调用。 + - **寄å˜å™¨æ“作**:在执行系统调用时,需è¦å°†å‚æ•°ä¼ é€’ç»™å†…æ ¸ã€‚NPUcore 通过特定的寄å˜å™¨çº¦å®šæ¥ä¼ 递傿•°ï¼Œä¾‹å¦‚使用 a0-a7 寄å˜å™¨ä¼ 递系统调用å·å’Œå‚æ•°ã€‚åŒæ—¶ï¼Œå†…æ ¸ä¹Ÿä¼šä½¿ç”¨å¯„å˜å™¨æ¥ä¿å˜ç³»ç»Ÿè°ƒç”¨çš„返回值,以便返回给用户æ€ç¨‹åºã€‚ + - **函数调用**ï¼šåœ¨å†…æ ¸æ€ï¼Œç³»ç»Ÿè°ƒç”¨ä¼šé€šè¿‡å‡½æ•°è°ƒç”¨æ¥å®žçŽ°å…·ä½“çš„åŠŸèƒ½ã€‚ä¾‹å¦‚ï¼Œåœ¨ NPUcore ä¸ï¼Œwrite ç³»ç»Ÿè°ƒç”¨ä¼šè°ƒç”¨å†…æ ¸ä¸çš„ç›¸å…³å‡½æ•°æ¥æ‰§è¡Œæ–‡ä»¶å†™å…¥æ“ä½œï¼Œè¿™äº›å‡½æ•°ä¼šæ ¹æ®ç³»ç»Ÿè°ƒç”¨çš„傿•°å’Œå†…æ ¸çš„çŠ¶æ€æ¥å®Œæˆå…·ä½“的工作。 +3. **系统调用的具体æµç¨‹** + - **用户æ€è¿›ç¨‹è°ƒç”¨ syscall**:应用程åºé€šè¿‡è°ƒç”¨ç”¨æˆ·æ€åº“函数(如 write 函数),库函数会进一æ¥è°ƒç”¨ syscall 函数,将系统调用å·å’Œå‚æ•°ä¼ é€’ç»™å†…æ ¸ã€‚ä¾‹å¦‚ï¼Œåœ¨ user/src/usr_call.rs ä¸çš„ write 函数会调用 sys_write 函数,sys_write 函数å†è°ƒç”¨ syscall 函数。 + - **syscall 调用 ecall æŒ‡ä»¤é™·å…¥å†…æ ¸æ€**:syscall 函数ä¸çš„å†…è”æ±‡ç¼–ä»£ç æ‰§è¡Œ ecall 指令,触å‘䏿–,使程åºé™·å…¥å†…æ ¸æ€ã€‚æ¤æ—¶ï¼Œç¡¬ä»¶ä¼šè‡ªåЍä¿å˜ç”¨æˆ·æ€çš„ä¸Šä¸‹æ–‡ï¼Œå¹¶è·³è½¬åˆ°å†…æ ¸æ€çš„䏿–处ç†ç¨‹åºã€‚ + - **å†…æ ¸æ€å¤„ç†ç³»ç»Ÿè°ƒç”¨**ï¼šåœ¨å†…æ ¸æ€ï¼Œä¸æ–处ç†ç¨‹åºï¼ˆtrap_handler å‡½æ•°ï¼‰ä¼šæ ¹æ®ç³»ç»Ÿè°ƒç”¨å·æ¥åˆ†å‘处ç†ä¸åŒçš„系统调用。例如,对于 write ç³»ç»Ÿè°ƒç”¨ï¼Œä¼šè°ƒç”¨å†…æ ¸ä¸çš„ç›¸åº”å‡½æ•°æ¥æ‰§è¡Œæ–‡ä»¶å†™å…¥æ“作,并将结果返回给用户æ€ã€‚ + - **æ¢å¤ç”¨æˆ·æ€ä¸Šä¸‹æ–‡å¹¶è¿”回**:系统调用处ç†å®ŒæˆåŽï¼Œå†…æ ¸ä¼šæ¢å¤ç”¨æˆ·æ€çš„上下文,并通过 sret 指令返回用户æ€ï¼Œç»§ç»æ‰§è¡Œç”¨æˆ·æ€ç¨‹åºçš„åŽç»æŒ‡ä»¤ã€‚ +4. **常è§ç³»ç»Ÿè°ƒç”¨ç¤ºä¾‹** + - **fork 系统调用**:用于创建一个新的进程,新进程是原进程的副本,包括代ç ã€æ•°æ®å’Œå †æ ˆç‰èµ„æºã€‚在 NPUcore ä¸ï¼Œfork 系统调用通过调用 clone 函数æ¥å®žçŽ°ï¼Œclone 函数å¯ä»¥æ›´ç²¾ç¡®åœ°æŽ§åˆ¶è¿›ç¨‹ä¹‹é—´çš„æ‰§è¡Œä¸Šä¸‹æ–‡ç»†èŠ‚ï¼Œå¦‚å…±äº«å†…å˜ç©ºé—´ã€æ–‡ä»¶æè¿°ç¬¦è¡¨ç‰ã€‚ + - **exec 系统调用**ï¼šç”¨äºŽåŠ è½½å¹¶æ‰§è¡Œä¸€ä¸ªæ–°çš„ç¨‹åºï¼Œæ›¿æ¢å½“å‰è¿›ç¨‹çš„地å€ç©ºé—´å’Œä¸Šä¸‹æ–‡çŽ¯å¢ƒã€‚åœ¨ NPUcore ä¸ï¼Œexec ç³»ç»Ÿè°ƒç”¨ä¼šæ‰“å¼€æŒ‡å®šçš„å¯æ‰§è¡Œæ–‡ä»¶ï¼Œæ£€æŸ¥æ–‡ä»¶æ ¼å¼ï¼Œå°†æ–‡ä»¶å†…å®¹åŠ è½½åˆ°å†…å˜ä¸ï¼Œå¹¶è®¾ç½®æ–°çš„进程上下文,然åŽå¼€å§‹æ‰§è¡Œæ–°ç¨‹åºã€‚ + - **sbrk 系统调用**:用于动æ€è°ƒæ•´è¿›ç¨‹çš„å †ç©ºé—´å¤§å°ã€‚在 NPUcore ä¸ï¼Œsbrk 系统调用通过 Memoryset 接å£ä¸‹çš„ sbrk 函数实现,它å¯ä»¥æ ¹æ®ä¼ å…¥çš„å‚æ•°å¢žåŠ æˆ–ç¼©å°å †ç©ºé—´ï¼Œå¹¶è¿”å›žæ–°çš„å †é¡¶æŒ‡é’ˆã€‚åŒæ—¶ï¼Œsbrk 函数会调用 mmap 或 munmap 函数æ¥å®žçŽ°å †ç©ºé—´çš„æ˜ å°„å’Œé‡Šæ”¾ã€‚ +5. **系统调用与其他æ“作系统概念的关系** + - **与进程管ç†çš„关系**:系统调用在进程管ç†ä¸èµ·ç€é‡è¦ä½œç”¨ï¼Œå¦‚ forkã€exec ç‰ç³»ç»Ÿè°ƒç”¨ç”¨äºŽåˆ›å»ºå’Œæ‰§è¡Œè¿›ç¨‹ï¼Œè€Œ getpid 系统调用用于获å–当å‰è¿›ç¨‹çš„ ID。进程的调度和切æ¢ä¹Ÿä¸Žç³»ç»Ÿè°ƒç”¨å¯†åˆ‡ç›¸å…³ï¼Œä¾‹å¦‚,当一个进程执行系统调用时,å¯èƒ½ä¼šå¯¼è‡´è¿›ç¨‹é˜»å¡žæˆ–被调度到其他进程执行。 + - **与内å˜ç®¡ç†çš„关系**:系统调用与内å˜ç®¡ç†ç›¸äº’å…³è”,例如,sbrk 系统调用用于动æ€åˆ†é…内å˜ï¼Œè€Œ mmap ç³»ç»Ÿè°ƒç”¨ç”¨äºŽå°†æ–‡ä»¶æ˜ å°„åˆ°å†…å˜ç©ºé—´ã€‚内å˜ç®¡ç†æ¨¡å—负责为系统调用分é…和管ç†å†…å˜èµ„æºï¼Œç¡®ä¿ç³»ç»Ÿè°ƒç”¨çš„æ£å¸¸æ‰§è¡Œã€‚ + - **与文件系统的关系**:文件系统相关的系统调用(如 openã€readã€write ç‰ï¼‰ç”¨äºŽå®žçŽ°å¯¹æ–‡ä»¶çš„æ“作。这些系统调用与文件系统的接å£å±‚ã€ç¼“å˜å±‚和索引节点层ç‰å¯†åˆ‡é…åˆï¼Œå®Œæˆæ–‡ä»¶çš„æ‰“å¼€ã€è¯»å–ã€å†™å…¥å’Œå…³é—ç‰æ“作,实现数æ®çš„æŒä¹…åŒ–å˜å‚¨ã€‚ + +#### 具体实现机制 + +1. **系统调用的触å‘ä¸Žé™·å…¥å†…æ ¸æ€** + - **用户æ€è¿›ç¨‹è°ƒç”¨ syscall**:应用程åºé€šè¿‡è°ƒç”¨ç”¨æˆ·æ€åº“函数å‘起系统调用。以 write 系统调用为例,在 user/src/usr_call.rs ä¸ï¼Œwrite 函数被应用程åºè°ƒç”¨ï¼Œå®ƒè¿›ä¸€æ¥è°ƒç”¨ sys_write 函数,如`pub fn write(fd: usize, buf: &[u8]) -> isize { sys_write(fd, buf) }`。sys_write 函数则调用 syscall å‡½æ•°ï¼Œå¹¶ä¼ é€’ç³»ç»Ÿè°ƒç”¨å·å’Œå‚数,如`pub fn sys_write(fd: usize, buffer: &[u8]) -> isize { syscall(SYSCALL_WRITE, [fd, buffer.as_ptr() as usize, buffer.len()]) }`。 + - **syscall 调用 ecall æŒ‡ä»¤é™·å…¥å†…æ ¸æ€**:在 syscall 函数ä¸ï¼Œé€šè¿‡å†…è”æ±‡ç¼–执行 ecall 指令触å‘䏿–,使程åºé™·å…¥å†…æ ¸æ€ã€‚具体代ç 如下: + +```rust +fn syscall(id: usize, args: [usize; 3]) -> isize { + let mut ret: isize; + unsafe { + asm!( + "ecall", + inlateout("x10") args[0] => ret, + in("x11") args[1], + in("x12") args[2], + in("x17") id + ); + } + ret +} +``` + +在这段代ç ä¸ï¼Œecall 指令触å‘䏿–,将系统调用å·å’Œå‚æ•°ä¼ é€’ç»™å†…æ ¸ã€‚inlateout æŒ‡ä»¤å°†å‚æ•° args [0] 放入 a0 寄å˜å™¨ï¼Œå¹¶åœ¨å‡½æ•°è¿”回åŽå°† x10 寄å˜å™¨çš„值作为返回值赋给 ret。 + +2. **å†…æ ¸æ€å¯¹ç³»ç»Ÿè°ƒç”¨çš„处ç†** + +- **设置 stvec 寄å˜å™¨ä¸Ž trap 处ç†**:在æ“作系统åˆå§‹åŒ–时,通过`set_user_trap_entry`函数设置 stvec 寄å˜å™¨ï¼Œä½¿å…¶æŒ‡å‘æ£ç¡®çš„ Trap 处ç†å…¥å£ç‚¹ï¼ˆ`TRAMPOLINE`)。当用户æ€è¿›ç¨‹æ‰§è¡Œ ecall æŒ‡ä»¤é™·å…¥å†…æ ¸æ€åŽï¼ŒCPU 会跳转到 stvec 寄å˜å™¨æŒ‡å‘的地å€ï¼Œå¼€å§‹æ‰§è¡Œ Trap 处ç†ç¨‹åºã€‚在 trap 处ç†ç¨‹åºä¸ï¼Œé¦–先通过`__alltraps`å°† Trap 上下文ä¿å˜åœ¨å†…æ ¸æ ˆä¸Šï¼Œç„¶åŽè·³è½¬åˆ°ä½¿ç”¨ Rust 编写的 trap_handler å‡½æ•°å®Œæˆ Trap 分å‘åŠå¤„ç†ã€‚ +- **trap_handler 函数ä¸çš„系统调用分å‘**:trap_handler å‡½æ•°æ ¹æ®ç³»ç»Ÿè°ƒç”¨å·å¯¹æ“作进行分å‘处ç†ã€‚以处ç†ç³»ç»Ÿè°ƒç”¨çš„部分代ç 为例: + +```rust +pub fn trap_handler() ->! { + set_kernel_trap_entry(); + let scause = scause::read(); + match scause.cause() { + Trap::Exception(Exception::UserEnvCall) => { + let mut cx = current_trap_cx(); + cx.gp.pc += 4; + let result = syscall( + cx.gp.a7, + [cx.gp.a0, cx.gp.a1, cx.gp.a2, cx.gp.a3, cx.gp.a4, cx.gp.a5], + ); + cx = current_trap_cx(); + cx.gp.a0 = result as usize; + } + //... + trap_return(); +} +``` + +在这段代ç ä¸ï¼Œé¦–å…ˆè¯»å– scause 寄å˜å™¨èŽ·å– Trap åŽŸå› ï¼Œå½“åˆ¤æ–为用户环境调用(UserEnvCall)时,获å–å½“å‰ Trap 上下文,将程åºè®¡æ•°å™¨ï¼ˆpcï¼‰åŠ 4 以指å‘ä¸‹ä¸€æ¡æŒ‡ä»¤ï¼Œç„¶åŽè°ƒç”¨å†…æ ¸æ€çš„ syscall 函数进行具体的系统调用处ç†ï¼Œå¹¶å°†ç»“æžœä¿å˜åˆ°è¿”回值寄å˜å™¨ a0 ä¸ã€‚ + +3. **系统调用的具体功能实现(以 write 系统调用为例)** + +- **å†…æ ¸æ€ write ç³»ç»Ÿè°ƒç”¨çš„å¤„ç†æµç¨‹**ï¼šåœ¨å†…æ ¸æ€ï¼Œwrite 系统调用最终会调用到 os/src/syscall/mod.rs ä¸çš„ syscall å‡½æ•°ï¼Œæ ¹æ®ç³»ç»Ÿè°ƒç”¨å·è¿›è¡Œåˆ†å‘处ç†ã€‚对于 write 系统调用(SYSCALL_WRITE),会调用相应的功能函数(如 sys_write ç‰ï¼‰æ¥æ‰§è¡Œå…·ä½“的文件写入æ“作。 +- **涉åŠçš„相关函数与数æ®ç»“æž„**:在 write 系统调用的实现ä¸ï¼Œæ¶‰åŠåˆ°å¤šä¸ªå‡½æ•°å’Œæ•°æ®ç»“构的ååŒå·¥ä½œã€‚例如,在用户æ€ä¼ 递的文件æè¿°ç¬¦ï¼ˆfd)和缓冲区指针(buf)ç‰å‚æ•°ï¼Œåœ¨å†…æ ¸æ€ä¼šé€šè¿‡æ–‡ä»¶æè¿°ç¬¦è¡¨ï¼ˆFdTable)找到对应的文件æè¿°ç¬¦å¯¹è±¡ï¼Œç„¶åŽè°ƒç”¨æ–‡ä»¶å¯¹è±¡çš„ write_user 方法将数æ®å†™å…¥æ–‡ä»¶ã€‚文件æè¿°ç¬¦è¡¨ç”¨äºŽç®¡ç†è¿›ç¨‹æ‰“开的文件,æ¯ä¸ªæ–‡ä»¶æè¿°ç¬¦å¯¹åº”一个文件对象,文件对象实现了 File Trait,定义了一系列文件æ“作的接å£å‡½æ•°ï¼Œå¦‚ writeã€read ç‰ã€‚ + + 4.**系统调用与其他模å—的交互**(**如内å˜ç®¡ç†**ã€**进程管ç†**) + +- **与内å˜ç®¡ç†çš„交互**:在一些系统调用ä¸ï¼Œå¦‚ sbrk 系统调用用于动æ€è°ƒæ•´è¿›ç¨‹çš„å †ç©ºé—´å¤§å°ï¼Œå®ƒä¸Žå†…å˜ç®¡ç†æ¨¡å—密切相关。sbrk 系统调用会调用 Memoryset 接å£ä¸‹çš„ sbrk 函数,该函数å¯èƒ½ä¼šè°ƒç”¨ mmap 或 munmap 函数æ¥å®žçŽ°å †ç©ºé—´çš„æ˜ å°„å’Œé‡Šæ”¾ï¼Œæ¶‰åŠåˆ°å†…å˜ç®¡ç†ä¸çš„页表æ“作ã€ç‰©ç†å†…å˜åˆ†é…ç‰åŠŸèƒ½ã€‚ +- **与进程管ç†çš„交互**:系统调用在进程管ç†ä¸ä¹Ÿå‘挥ç€é‡è¦ä½œç”¨ã€‚例如,fork 系统调用用于创建新进程,它涉åŠåˆ°è¿›ç¨‹æŽ§åˆ¶å—(TCB)的创建ã€è¿›ç¨‹æ ‡è¯†ç¬¦ï¼ˆPID)的分é…ã€å†…å˜ç©ºé—´çš„å¤åˆ¶ç‰æ“ä½œï¼Œä¸Žè¿›ç¨‹ç®¡ç†æ¨¡å—ä¸çš„相关数æ®ç»“构和函数紧密åä½œã€‚åŒæ—¶ï¼Œè¿›ç¨‹çš„调度和切æ¢ä¹Ÿå¯èƒ½ç”±ç³»ç»Ÿè°ƒç”¨è§¦å‘,如 sys_yield 系统调用用于让出当å‰è¿›ç¨‹çš„å 用æƒï¼Œæ¶‰åŠåˆ°è¿›ç¨‹çжæ€çš„æ”¹å˜ã€å°±ç»ªé˜Ÿåˆ—的管ç†ç‰è¿›ç¨‹ç®¡ç†ç›¸å…³çš„æ“ä½œã€‚ + +### 内å˜ç®¡ç† + +#### 1. 内å˜å¸ƒå±€ä¸Žè™šæ‹Ÿåœ°å€ç©ºé—´ + +##### 1.1 å†…æ ¸è™šæ‹Ÿåœ°å€ç©ºé—´åˆ†å¸ƒ + +在NPUcoreä¸ï¼Œå†…æ ¸è™šæ‹Ÿåœ°å€ç©ºé—´è¢«ç²¾å¿ƒè§„划以确ä¿å„个组件之间ä¸ä¼šç›¸äº’干扰,并且æä¾›äº†è¶³å¤Ÿçš„çµæ´»æ€§æ¥æ»¡è¶³ä¸åŒåº”ç”¨åœºæ™¯çš„éœ€æ±‚ã€‚ä»¥ä¸‹æ˜¯å‡ ä¸ªå…³é”®éƒ¨åˆ†ï¼š + +- **Trampoline**:ä½äºŽæœ€é«˜è™šæ‹Ÿé¡µé¢ä¸Šï¼Œä¸»è¦ç”¨äºŽå¤„ç†panicç‰å¼‚常情况。 +- **User Stack**:紧éšå…¶åŽçš„æ˜¯ç”¨æˆ·æ ˆåŒºåŸŸï¼Œæ¯ä¸ªç”¨æˆ·æ ˆå 用一页大å°ï¼ˆ4KB),并且å‘下增长。 +- **Guard Page**ï¼šä¸ºäº†é˜²æ¢æ ˆæº¢å‡ºå¯¼è‡´çš„å®‰å…¨é—®é¢˜ï¼Œåœ¨ç›¸é‚»ä¸¤ä¸ªå†…æ ¸æ ˆä¹‹é—´é¢„ç•™äº†ä¸€ä¸ªä¿æŠ¤é¡µé¢ï¼ˆåŒæ ·ä¸ºä¸€é¡µå¤§å°ï¼‰ã€‚ +- **Kernel Program**:å†å¾€ä¸‹åˆ™æ˜¯åŠ è½½å†…æ ¸ç¨‹åºçš„地方。 + +æ¤å¤–ï¼Œè¿˜æœ‰å…¶ä»–ä¸€äº›è¾…åŠ©æ€§çš„åŒºåŸŸï¼Œå¦‚ç”¨äºŽå˜æ”¾å…¨å±€å˜é‡æˆ–陿€æ•°æ®çš„æ®µè½ç‰ã€‚è¿™ç§å±‚æ¬¡åŒ–çš„ç»“æž„ä½¿å¾—ç³»ç»Ÿèƒ½å¤Ÿæ›´åŠ æœ‰åºåœ°ç®¡ç†å’Œåˆ©ç”¨æœ‰é™çš„内å˜èµ„æºã€‚ + +##### 1.2 用户进程的虚拟地å€ç©ºé—´ + +对于æ¯ä¸€ä¸ªç”¨æˆ·è¿›ç¨‹æ¥è¯´ï¼Œå®ƒéƒ½æœ‰è‡ªå·±ç‹¬ç«‹çš„一å—虚拟地å€ç©ºé—´ã€‚è¿™å—空间由æ“作系统负责创建并维护,ä¿è¯äº†è¿›ç¨‹é—´çš„隔离性。当新进程å¯åŠ¨æ—¶ï¼Œå®ƒçš„åˆå§‹åœ°å€ç©ºé—´ä¸ºç©ºï¼›éšç€è¿›ç¨‹è¿è¡Œè¿‡ç¨‹ä¸ä¸æ–申请新的页é¢ï¼Œæ‰€å 的物ç†å†…å˜ä¹Ÿä¼šé€æ¸å¢žåŠ ã€‚ä¸ºäº†å®žçŽ°è¿™ä¸€ç‚¹ï¼Œæ“ä½œç³»ç»Ÿéœ€è¦æä¾›ä¸€å¥—å®Œæ•´çš„API供用户进程调用æ¥è¯·æ±‚和释放内å˜ã€‚ + +#### 2. 虚拟地å€åˆ°ç‰©ç†åœ°å€çš„è½¬æ¢ + +##### 2.1 åœ°å€æ ¼å¼ + +NPUcore采用页å¼ç®¡ç†æ–¹æ¡ˆï¼Œå…¶ä¸æ¯ä¸ªé¡µé¢å¤§å°å›ºå®šä¸º4KiB (2^12 B)。这æ„味ç€è™šæ‹Ÿåœ°å€å¯ä»¥åˆ†ä¸ºä¸¤éƒ¨åˆ†ï¼šé«˜27ä½ä½œä¸ºè™šæ‹Ÿé¡µå·(VPN),低12ä½ä½œä¸ºé¡µå†…åç§»(Page Offset)ã€‚åŒæ ·åœ°ï¼Œç‰©ç†åœ°å€ä¹Ÿå¯ä»¥æ‹†åˆ†æˆé«˜44ä½çš„物ç†é¡µå·(PPN)åŠ ä¸Šç›¸åŒçš„12ä½é¡µå†…åç§»ã€‚è¿™æ ·çš„è®¾è®¡ç®€åŒ–äº†åœ°å€è½¬æ¢çš„è¿‡ç¨‹ï¼ŒåŒæ—¶ä¹Ÿä¾¿äºŽç¡¬ä»¶å®žçŽ°ã€‚ + +##### 2.2 é¡µè¡¨æ˜ å°„ + +为了完æˆä»Žè™šæ‹Ÿåœ°å€åˆ°ç‰©ç†åœ°å€çš„转æ¢ï¼ŒNPUcore引入了多级页表结构。æ¯å½“有新的页é¢è¢«åˆ†é…ç»™æŸä¸ªè¿›ç¨‹æ—¶ï¼Œç›¸åº”的页表项就会被更新,从而建立起虚拟地å€ä¸Žç‰©ç†åœ°å€ä¹‹é—´çš„对应关系。具体æ¥è¯´ï¼Œè¿™ä¸ªè¿‡ç¨‹æ¶‰åŠä»¥ä¸‹å‡ 个æ¥éª¤ï¼š + +1. æ£€æŸ¥ä¼ å…¥çš„è™šæ‹Ÿé¡µå·(VPN)是å¦å·²ç»è¢«åˆ†é…过; +2. 如果未分é…ï¼Œåˆ™æ ¹æ®æ‰€éœ€ç±»åž‹é€‰æ‹©åˆé€‚çš„æ˜ å°„æ–¹å¼ï¼ˆä¾‹å¦‚æ’ç‰æ˜ å°„æˆ–è€…æ™®é€šæ˜ å°„ï¼‰ï¼› +3. å¯¹äºŽæ™®é€šæ˜ å°„ï¼Œè°ƒç”¨`frame_alloc_uninit()`函数æ¥èŽ·å–一个空闲的物ç†é¡µé¢ï¼› +4. 更新页表,建立VPN到PPNçš„æ˜ å°„ï¼› +5. 返回最终得到的物ç†åœ°å€ã€‚ + +é€šè¿‡è¿™ç§æ–¹å¼ï¼Œå³ä½¿åº”用程åºåªéœ€è¦å°‘é‡è¿žç»çš„虚拟地å€ï¼Œå®ƒä»¬ä¹Ÿå¯èƒ½åˆ†æ•£åœ¨æ•´ä¸ªç‰©ç†å†…å˜çš„ä¸åŒä½ç½®ï¼Œä½†å¯¹åº”ç”¨æœ¬èº«è€Œè¨€å´æ˜¯é€æ˜Žçš„。 + +#### 3. 物ç†å†…å˜åˆ†é…器 + +##### 3.1 分é…器åˆå§‹åŒ– + +在编写任何应用程åºä¹‹å‰ï¼Œå¿…须先对内å˜è¿›è¡Œæ£ç¡®çš„åˆå§‹åŒ–æ“作,å¦åˆ™å¯èƒ½ä¼šå¼•å‘å„ç§é”™è¯¯ï¼Œæ¯”å¦‚å†…å˜æ³„æ¼ç”šè‡³ç¨‹åºå´©æºƒã€‚å› æ¤ï¼Œåœ¨NPUcoreå¯åŠ¨é˜¶æ®µï¼Œä¼šæ‰§è¡Œä¸€ç³»åˆ—åˆå§‹åŒ–工作,其ä¸åŒ…括设置好物ç†å†…å˜åˆ†é…器的工作范围。这部分代ç 在`frame_allocator.rs`文件ä¸ï¼š + +```rust +pub fn init_frame_allocator(){ + extern "C" { + fn ekernel(); + } + FRAME_ALLOCATOR.write().init( + PhysAddr::from(ekernel as usize).ceil(), + PhysAddr::from(MEMORY_END).floor(), + ); +} +``` + +这里`ekernel`æŒ‡ä»£å†…æ ¸ç©ºé—´ç»“æŸçš„ä½ç½®ï¼Œè€Œ`MEMORY_END`则定义了整个å¯ç”¨ç‰©ç†å†…å˜çš„æœ€å¤§è¾¹ç•Œã€‚两者之间的所有地å€éƒ½å°†è¢«åˆ†é…器管ç†èµ·æ¥ï¼Œä¾›åŽç»ä½¿ç”¨ã€‚ + +##### 3.2 分é…å™¨æŽ¥å£ + +NPUcoreæä¾›äº†ä¸€å¥—ç®€æ´æ˜“用的API。这些APIéšè—äº†è®¸å¤šåº•å±‚ç»†èŠ‚ï¼Œè®©ç”¨æˆ·æ— éœ€å…³å¿ƒå…·ä½“çš„å®žçŽ°é€»è¾‘ã€‚ä»¥ä¸‹æ˜¯å‡ ä¸ªæ ¸å¿ƒæ–¹æ³•ï¼š + +- `new()`:创建一个新的分é…器实例。 +- `alloc()`:分é…一个物ç†é¡µé¢ï¼Œå¹¶è¿”回一个包å«è¯¥é¡µé¢ä¿¡æ¯çš„对象(`FrameTracker`)。 +- `dealloc(ppn: PhysPageNum)`:回收指定物ç†é¡µå·å¯¹åº”的页é¢ã€‚ + +值得注æ„的是,还有一个å为`alloc_uninit()`的方法,它å¯ä»¥è·³è¿‡åˆå§‹åŒ–æ¥éª¤ç›´æŽ¥è¿”回页é¢å¯¹è±¡ï¼Œé€‚用于那些ä¸éœ€è¦é¢å¤–å‡†å¤‡å·¥ä½œçš„åœºæ™¯ï¼Œè¿™æ ·å¯ä»¥åŠ å¿«åˆ†é…速度。 + +##### 3.3 æ ˆå¼ç®¡ç†ç–ç•¥ + +为了进一æ¥ä¼˜åŒ–性能,NPUcoreé‡‡ç”¨äº†åŸºäºŽæ ˆçš„æ•°æ®ç»“æž„æ¥ç»„ç»‡ç©ºé—²é¡µé¢æ± 。æ¯å½“有新的页é¢éœ€æ±‚时,分é…å™¨ä¼šä»Žæ ˆé¡¶å¼¹å‡ºæœ€ä¸Šé¢çš„一个页é¢ï¼›ç›¸å地,当页é¢ä¸å†éœ€è¦æ—¶ï¼Œåˆ™ä¼šè¢«åŽ‹å›žåˆ°æ ˆåº•ã€‚è¿™ç§æ–¹æ³•ä¿è¯äº†æ¯æ¬¡åˆ†é…都能尽å¯èƒ½å¿«åœ°å®Œæˆï¼ŒåŒæ—¶å‡å°‘了碎片化带æ¥çš„è´Ÿé¢å½±å“。 + +#### 4. 页é¢ç½®æ¢ç®—法 + +虽然我们尽é‡é¿å…频ç¹åœ°æ¢å…¥æ¢å‡ºé¡µé¢ï¼Œä½†åœ¨æŸäº›æƒ…况下ä»ç„¶ä¸å¯é¿å…地会å‘ç”Ÿè¿™ç§æƒ…况。为æ¤ï¼ŒNPUcore实现了一套页é¢ç½®æ¢ç®—法,用以决定哪些页é¢åº”该被替æ¢å‡ºåŽ»ä»¥è…¾å‡ºç©ºé—´ã€‚è¿™é€šå¸¸æ˜¯åŸºäºŽæŸç§å¯å‘å¼çš„规则æ¥è¿›è¡Œåˆ¤æ–,例如最近最少使用(LRU)æˆ–éšæœºé€‰æ‹©(RAND)ç‰ç–略。 + +### è¿›ç¨‹ç®¡ç† + +#### é‡è¦æ•°æ®ç»“æž„ + +1. **è¿›ç¨‹æ ‡è¯†ç¬¦**`PidHandle` + - 定义:`pub struct PidHandle(pub usize);`,是一个 64 使— ç¬¦å·æ•´æ•°ï¼Œç”¨äºŽå”¯ä¸€æ ‡è¯†è¿›ç¨‹ ID。 + - 分é…ä¸Žå›žæ”¶ï¼šç”±æ ‡è¯†ç¬¦åˆ†é…器`RecycleAllocator`管ç†ï¼Œ`RecycleAllocator`通过`current`å—æ®µè®°å½•下一个分é…çš„`pid`è¿›ç¨‹å· / å†…æ ¸æ ˆå·ï¼ˆè‹¥`recycled`æ•°ç»„ä¸ºç©ºï¼‰ï¼Œæ¯æ¬¡åˆ†é…åŽ`current`åŠ 1ï¼›`recycled`数组ä¿å˜å·²å›žæ”¶çš„`pid`å·ã€‚å…¶æä¾›äº†`alloc`分é…器方法(若`recycled`䏿œ‰å¯ç”¨`pid`å·åˆ™ç›´æŽ¥åˆ†é…,å¦åˆ™ç”Ÿæˆæ–°`pid`å·ï¼‰ã€`dealloc`å›žæ”¶å™¨æ–¹æ³•ï¼ˆæ£€æŸ¥åˆæ³•性åŽå›žæ”¶`pid`å·ï¼‰å’Œ`get_allocated`方法(获å–当剿£åœ¨è¿è¡Œçš„进程数é‡ï¼‰ã€‚ + - 示例代ç : + +```rust +lazy_static! { + static ref PID_ALLOCATOR: Mutex<RecycleAllocator> = Mutex::new(RecycleAllocator::new()); +} + +pub fn pid_alloc() -> PidHandle { + PidHandle(PID_ALLOCATOR.lock().alloc()) +} + +impl Drop for PidHandle { + fn drop(&mut self) { + PID_ALLOCATOR.lock().dealloc(self.0); + } +} +``` + +2. **å†…æ ¸æ ˆ**`KernelStack` + +- å˜åœ¨æ„ä¹‰ï¼šç³»ç»Ÿè°ƒç”¨é™·å…¥å†…æ ¸åŽï¼Œç”¨äºŽæ”¯æŒå‡½æ•°è°ƒç”¨å’Œè‡ªåЍå˜é‡ã€‚æ¯ä¸ªè¿›ç¨‹éƒ½æœ‰ç‹¬è‡ªçš„å†…æ ¸æ ˆï¼Œé¿å…è¿›ç¨‹é—´å…±äº«å†…æ ¸æ ˆå¯¼è‡´æ•°æ®ç ´å。 +- 方法: + - `kernel_stack_position`:返回当å‰å†…æ ¸æ ˆåœ¨å†…æ ¸ç©ºé—´ä¸çš„æ ˆé¡¶å’Œæ ˆåº•ä½ç½®ã€‚ + - `kstack_alloc`ï¼šå†…æ ¸æ ˆåˆ†é…器,从`KSTACK_ALLOCATOR`获å–å†…æ ¸æ ˆç¼–å·ï¼Œè®¡ç®—æ ˆä½ç½®åŽæ’å…¥å†…æ ¸åœ°å€ç©ºé—´ã€‚ + - `drop`ï¼šå°†å†…æ ¸æ ˆä»Žå†…æ ¸ç©ºé—´ç§»é™¤ï¼Œé‡Šæ”¾ç›¸å…³èµ„æºã€‚ + - `push_on_top`:将å˜é‡åŽ‹å…¥å†…æ ¸æ ˆé¡¶å¹¶è¿”å›žè£¸æŒ‡é’ˆã€‚ +- 示例代ç : + +```rust +pub fn kernel_stack_position(kstack_id: usize) -> (usize, usize) { + let top = TRAMPOLINE - kstack_id * (KERNEL_STACK_SIZE + PAGE_SIZE); + let bottom = top - KERNEL_STACK_SIZE; + (bottom, top) +} + +pub fn kstack_alloc() -> KernelStack { + let kstack_id = KSTACK_ALLOCATOR.lock().alloc(); + let (kstack_bottom, kstack_top) = kernel_stack_position(kstack_id); + KERNEL_SPACE.lock().insert_framed_area( + kstack_bottom.into(), + kstack_top.into(), + MapPermission::R | MapPermission::W, + ); + KernelStack(kstack_id) +} + +impl Drop for KernelStack { + fn drop(&mut self) { + let (kernel_stack_bottom, _) = kernel_stack_position(self.0); + let kernel_stack_bottom_va: VirtAddr = kernel_stack_bottom.into(); + KERNEL_SPACE + .lock() + .remove_area_with_start_vpn(kernel_stack_bottom_va.into()) + .unwrap(); + KSTACK_ALLOCATOR.lock().dealloc(self.0) + } +} + +impl KernelStack { + #[allow(unused)] + pub fn push_on_top<T>(&self, value: T) -> *mut T + where + T: Sized, + { + let kernel_stack_top = self.get_top(); + let ptr_mut = (kernel_stack_top - core::mem::size_of::<T>()) as *mut T; + unsafe { + *ptr_mut = value; + } + ptr_mut + } + + pub fn get_top(&self) -> usize { + let (_, kernel_stack_top) = kernel_stack_position(self.0); + kernel_stack_top + } +} +``` + + 3.**进程控制å—**`TCB(Task Control Block)` + +- 作用:记录æ“作系统管ç†è¿›ç¨‹æ‰€éœ€çš„全部信æ¯ï¼Œæ˜¯è¿›ç¨‹å˜åœ¨çš„å”¯ä¸€æ ‡å¿—ï¼Œå®žçŽ°è¿›ç¨‹é—´æ–æ€§è¿è¡Œã€æä¾›ç®¡ç†å’Œè°ƒåº¦æ‰€éœ€ä¿¡æ¯ï¼Œä»¥åŠè¿›ç¨‹é—´çš„åŒæ¥å’Œé€šä¿¡ã€‚ +- 组æˆï¼šç”±å¯å˜éƒ¨åˆ†ã€ä¸å¯å˜éƒ¨åˆ†åŠå¯å…±äº«ä¸”å¯å˜éƒ¨åˆ†ç»„æˆã€‚ + - ä¸å¯å˜éƒ¨åˆ†åŒ…括`pid`(进程å·ï¼‰ã€`kstack`ï¼ˆå†…æ ¸æ ˆï¼‰ã€`ustack_base`ï¼ˆç”¨æˆ·æ ˆåŸºåœ°å€ï¼‰ã€`exit_signal`(退出信å·ï¼‰ã€‚ + - å¯å˜éƒ¨åˆ†ä¸º`inner`,其类型`TaskControlBlockInner`包å«`sigmask`ã€`sigpending`ã€`trap_cx_ppn`ï¼ˆå˜æ”¾`Trap`上下文的物ç†åœ°å€ï¼‰ã€`task_cx`(进程上下文)ã€`task_status`(进程状æ€ï¼Œæœ‰`Ready`ã€`Running`ã€`Zombie`ã€`Interruptible`å››ç§çжæ€ï¼‰ã€`parent`(父进程弱引用)ã€`children`(å进程列表)ã€`exit_code`(退出ç )ã€`clear_child_tid`ç‰ã€‚ +- 示例代ç : + +```rust +pub struct TaskControlBlock { + // immutable + pub pid: PidHandle, + pub tid: usize, + pub tgid: usize, + pub kstack: KernelStack, + pub ustack_base: usize, + pub tui: Signals, + // mutable + inner: Mutex<TaskControlBlockInner>, + // shareable and mutable + pub exe: Arc<Mutex<FileDescriptor>>, + pub tid_allocator: Arc<Mutex<RecycleAllocator>>, + pub files: Arc<Mutex<FdTable>>, + pub fs: Arc<Mutex<FsStatus>>, + pub vm: Arc<Mutex<MemorySet>>, + pub sighand: Arc<Mutex<Vec<Option<Box<SigAction>>>>>, + pub futex: Arc<Mutex<Futex>>, +} + +pub struct TaskControlBlockInner { + pub sigmask: Signals, + pub sigpending: Signals, + pub trap_cx_ppn: PhysPageNum, + pub task_cx: TaskContext, + pub task_status: TaskStatus, + pub parent: Option<Weak<TaskControlBlock>>, + pub children: Vec<Arc<TaskControlBlock>>, + pub exit_code: u32, + pub clear_child_tid: usize, + pub robust_list: RobustList, + pub heap_bottom: usize, + pub heap_pt: usize, + pub pgid: usize, + pub rusage: Rusage, + pub clock: ProcClock, + pub timer: [ITimerVal; 3], +} +``` + +#### 进程创建 + +1. **总体æµç¨‹** + + - ä»Žç³»ç»Ÿæ–‡ä»¶ä¸æ‰¾åˆ°å†…æ ¸åŠ è½½ç¬¬ä¸€ä¸ªåˆå§‹è¿›ç¨‹çš„`elf`文件,获å–å…¶æ•°æ®å’Œå†…容,调用`TCB`ä¸çš„`new()`æ–¹æ³•åˆ›å»ºå†…æ ¸çš„ç¬¬ä¸€ä¸ªè¿›ç¨‹`initproc`。 + - 其余进程由`initproc`通过`clone`系统调用克隆而æ¥ï¼Œç„¶åŽæ–°è¿›ç¨‹é€šè¿‡`exec`ç³»ç»Ÿè°ƒç”¨åŠ è½½ç‹¬ç«‹çš„ç¨‹åºä»£ç å’Œæ•°æ®æ–‡ä»¶ã€‚ + +2. `initproc`**的创建** + + - åˆå§‹åŒ–`INITPROC`:通过`lazy_static!`宿‡’分é…`INITPROC`,调用`ROOT_FD.open`获å–`elf`文件数æ®ï¼Œå†è°ƒç”¨`TaskControlBlock::new(elf)`创建进程控制å—。 + + - ``` + TaskControlBlock::new + ``` + + 方法: + + - 获å–`elf`坿‰§è¡Œæ–‡ä»¶æ•°æ®ã€‚ + - 从`ELF`文件解æžåº”用地å€ç©ºé—´ã€ç”¨æˆ·å †é¡¶ä½ç½®å’Œ`elf`ä¿¡æ¯ï¼Œç§»é™¤åœ°å€æ˜ 射关系。 + - åˆå§‹åŒ–线程分é…器,分é…`pid`ã€`tid`ã€`tgid`å’Œå†…æ ¸æ ˆï¼Œè®°å½•å†…æ ¸æ ˆä½ç½®ã€‚ + - 查找`Trap`上下文物ç†é¡µå¸§ï¼Œåˆå§‹åŒ–进程控制å—å„ä¸ªå—æ®µï¼ŒåŒ…括`exe`ï¼ˆå¯æ‰§è¡Œæ–‡ä»¶ï¼‰ã€`tid_allocator`(线程分é…器)ã€`files`(文件æè¿°ç¬¦è¡¨ï¼‰ã€`fs`(文件系统状æ€ï¼‰ã€`vm`(内å˜é›†åˆï¼‰ã€`sighand`(信å·å¤„ç†ï¼‰ã€`futex`(互斥é”)ç‰ï¼Œè®¾ç½®è¿›ç¨‹çжæ€ä¸º`Ready`。 + - åˆå§‹åŒ–`Trap`上下文,使进程能æ£ç¡®è¿›å…¥ç”¨æˆ·æ€å’Œå†…æ ¸æ€ã€‚ + + - 示例代ç : + +```rust +lazy_static! { + pub static ref INITPROC: Arc<TaskControlBlock> = Arc::new({ + let elf = ROOT_FD.open("initproc", OpenFlags::O_RDONLY, true).unwrap(); + TaskControlBlock::new(elf) + }); +} + +pub fn new(elf: FileDescriptor) -> Self { + let elf_data = elf.map_to_kernel_space(MMAP_BASE); + let (mut memory_set, user_heap, elf_info) = MemorySet::from_elf(elf_data).unwrap(); + crate::mm::KERNEL_SPACE + .lock() + .remove_area_with_start_vpn(VirtAddr::from(MMAP_BASE).floor()) + .unwrap(); + let tid_allocator = Arc::new(Mutex::new(RecycleAllocator::new())); + // alloc a pid and a kernel stack in kernel space + let pid_handle = pid_alloc(); + let tid = tid_allocator.lock().alloc(); + let tgid = pid_handle.0; + let pgid = pid_handle.0; + let kstack = kstack_alloc(); + let kstack_top = kstack.get_top(); + let trap_cx_ppn = memory_set + .translate(VirtAddr::from(trap_cx_bottom_from_tid(tid)).into()) + .unwrap() + .ppn(); + let task_control_block = Self { + pid: pid_handle, + tid, + tgid, + kstack, + ustack_base: ustack_bottom_from_tid(tid), + exit_signal: Signals::empty(), + exe: Arc::new(Mutex::new(elf)), + tid_allocator, + files: Arc::new(Mutex::new(FdTable::new({ + let mut vec = Vec::with_capacity(144); + let tty = Some(ROOT_FD.open("/dev/tty", OpenFlags::O_RDWR, false).unwrap()); + vec.resize(3, tty); + vec + }))), + fs: Arc::new(Mutex::new(FsStatus { + working_inode: Arc::new( + ROOT_FD + .open(".", OpenFlags::O_RDONLY | OpenFlags::O_DIRECTORY, true) + .unwrap(), + ), + })), + vm: Arc::new(Mutex::new(memory_set)), + sighand: Arc::new(Mutex::new({ + let mut vec = Vec::with_capacity(64); + vec.resize(64, None); + vec + })), + futex: Arc::new(Mutex::new(Futex::new())), + inner: Mutex::new(TaskControlBlockInner { + sigmask: Signals::empty(), + sigpending: Signals::empty(), + trap_cx_ppn, + task_cx: TaskContext::goto_trap_return(kstack_top), + task_status: TaskStatus::Ready, + parent: None, + children: Vec::new(), + exit_code: 0, + clear_child_tid: 0, + robust_list: RobustList::default(), + heap_bottom: user_heap, + heap_pt: user_heap, + pgid, + rusage: Rusage::new(), + clock: ProcClock::new(), + timer: [ITimerVal::new(); 3], + }), + }; + let trap_cx = task_control_block.acquire_inner_lock().get_trap_cx(); + *trap_cx = TrapContext::app_init_context( + elf_info.entry, + ustack_bottom_from_tid(tid), + KERNEL_SPACE.lock().token(), + kstack_top, + trap_handler as usize, + ); + task_control_block +} +``` + + 3.`clone`**系统调用** + +- 作用:创建新进程或线程,精确控制调用进程和å进程之间的执行上下文细节,如共享虚拟地å€ç©ºé—´ã€æ–‡ä»¶æè¿°ç¬¦è¡¨ã€ä¿¡å·å¥æŸ„表ç‰ï¼Œè¿˜å¯å°†å进程放入ä¸åŒå‘½å空间。 +- 实现: + - ç³»ç»Ÿè°ƒç”¨å‚æ•°ï¼š`sys_clone`函数接å—`flags`(`CloneFlags`类型,包å«å¤šç§æ ‡å¿—控制`clone`行为)ã€`stack`(åè¿›ç¨‹ä½¿ç”¨çš„æ ˆä½ç½®ï¼‰ã€`ptid`(与`CloneFlags`ä¸çš„`CLONE_CHILD_SETTID`有关,ä¿å˜çº¿ç¨‹ ID)ã€`tls`(与`CloneFlags`ä¸çš„`CLONE_SETTLS`有关,ä¿å˜`TLS`)ã€`ctid`(与`CloneFlags`ä¸çš„`CLONE_PARENT_SETTID`有关,ä¿å˜çº¿ç¨‹ ID)ç‰å‚数。 + - 函数体逻辑: + - 获å–`exit_signal`ï¼Œæ ¹æ®`flags`获å–`clone flag`。 + - 调用`parent.sys_clone`实现`clone`ï¼Œåœ¨å…¶ä¸æ ¹æ®`flags`决定是å¦å…±äº«å†…å˜ç©ºé—´å’Œçº¿ç¨‹ç»„关系,分é…`pid`ã€`tid`ã€`tgid`å’Œå†…æ ¸æ ˆï¼Œæž„å»ºæ–°è¿›ç¨‹`TCB`,设置`TCB`çš„å„ç§å±žæ€§ï¼ˆå¦‚å…±äº«èµ„æºæ ‡å¿—决定是å¦å…±äº«æ–‡ä»¶æè¿°ç¬¦ã€æ–‡ä»¶ç³»ç»Ÿã€ä¿¡å·å¤„ç†ç‰ï¼‰ï¼Œä¿®æ”¹çˆ¶è¿›ç¨‹çš„å进程表,设置新进程è¿è¡Œä¸Šä¸‹æ–‡å’Œçº¿ç¨‹æœ¬åœ°å˜å‚¨ï¼Œæœ€åŽè¿”回新进程`TCB`。 + - æ ¹æ®`flags`åˆ¤æ–æ˜¯å¦è®¾ç½®`CLONE_PARENT_SETTID`ã€`CLONE_CHILD_SETTID`ã€`CLONE_CHILD_CLEARTID`ç‰æ ‡å¿—,执行相应æ“作(如将å进程线程 ID 写入指定ä½ç½®ã€æ¸…除指定内å˜ç‰ï¼‰ã€‚ + - å°†æ–°è¿›ç¨‹åŠ å…¥ä»»åŠ¡ç®¡ç†å™¨çš„就绪队列。 +- 示例代ç : + +```rust +pub fn sys_clone( + flags: u32, + stack: *const u8, + ptid: *mut u32, + tls: usize, + ctid: *mut u32, +) -> isize { + let exit_signal = match Signals::from_signum((flags & 0xff) as usize) { + Ok(signal) => signal, + Err(_) => { + warn!( + "[sys_clone] signum of exit_signal is unspecified or invalid: {}", + (flags & 0xff) as usize + ); + // This is permitted by standard, but we only support 64 signals + Signals::empty() + } + }; + // Sure to succeed, because all bits are valid (See `CloneFlags`) + let flags = CloneFlags::from_bits(flags &!0xff).unwrap(); + show_frame_consumption! { + "clone"; + let child = parent.sys_clone(flags, stack, tls, exit_signal); + } + if flags.contains(CloneFlags::CLONE_PARENT_SETTID) { + match translated_refmut(parent.get_user_token(), ptid) { + Ok(word) => *word = child.pid.0 as u32, + Err(errno) => return errno, + }; + } + if flags.contains(CloneFlags::CLONE_CHILD_SETTID) { + match translated_refmut(child.get_user_token(), ctid) { + Ok(word) => *word = child.pid.0 as u32, + Err(errno) => return errno, + }; + } + if flags.contains(CloneFlags::CLONE_CHILD_CLEARTID) { + child.acquire_inner_lock().clear_child_tid = ctid as usize; + } + add_task(child); + SUCCESS +} + +pub fn sys_clone( + self: &Arc<TaskControlBlock>, + flags: CloneFlags, + stack: *const u8, + tls: usize, + exit_signal: Signals, +) -> Arc<TaskControlBlock> { + // ---- hold parent PCB lock + let mut parent_inner = self.acquire_inner_lock(); + // copy user space(include trap context) + let memory_set = if flags.contains(CloneFlags::CLONE_VM) { + self.vm.clone() + } else { + crate::mm::frame_reserve(16); + Arc::new(Mutex::new(MemorySet::from_existing_user( + &mut self.vm.lock(), + ))) + }; + let tid_allocator = if flags.contains(CloneFlags::CLONE_THREAD) { + self.tid_allocator.clone() + } else { + Arc::new(Mutex::new(RecycleAllocator::new())) + }; + // alloc a pid and a kernel stack in kernel space + let pid_handle = pid_alloc(); + let tid = tid_allocator.lock().alloc(); + let tgid = if flags.contains(CloneFlags::CLONE_THREAD) { + self.tgid + } else { + pid_handle.0 + }; + let kstack = kstack_alloc(); + let kstack_top = kstack.get_top(); + if flags.contains(CloneFlags::CLONE_THREAD) { + memory_set.lock().alloc_user_res(tid, stack.is_null()); + } + let task_control_block = Arc::new(TaskControlBlock { + pid: pid_handle, +``` + +#### è¿›ç¨‹åˆ‡æ¢ + +1. **实现方法** + - ä¾é `os/src/task/mod.rs`ä¸çš„`suspend_current_and_run_next`å‡½æ•°å®žçŽ°ã€‚è¯¥å‡½æ•°æœ‰ä¸¤ä¸ªåº”ç”¨åœºæ™¯ï¼šä¸€æ˜¯åº”ç”¨ç¨‹åºæ‰‹åŠ¨ä½¿ç”¨`sys_yield`系统调用让出当å‰è¿›ç¨‹å 用æƒï¼›äºŒæ˜¯å†…æ ¸å‡ºçŽ°é”™è¯¯é€ æˆ`trap`时,程åºä¼šè·³è½¬è‡³`os/src/trap/mod.rs`å†…éƒ¨çš„ä¸æ–处ç†ç¨‹åºï¼Œåœ¨å…¶ä¸è°ƒç”¨`suspend_current_and_run_next`。 +2. **函数实现原ç†** + - 获å–当剿£åœ¨æ‰§è¡Œè¿›ç¨‹çš„`PCB`(命å为`task`),获å–å…¶å¯å˜éƒ¨åˆ†ï¼ˆåŒ…å«è¿›ç¨‹ä¸Šä¸‹æ–‡ä¿¡æ¯ï¼‰å¹¶è½¬åŒ–为å¯å˜è£¸æŒ‡é’ˆã€‚ + - 将当å‰è¿›ç¨‹çŠ¶æ€æ”¹ä¸º`Ready`,手动å‡å°‘引用计数(`drop`æ“作)。 + - 将当å‰ä»»åŠ¡æ”¾å…¥å°±ç»ªé˜Ÿåˆ—ï¼ˆé€šè¿‡`add_task`å‡½æ•°ï¼‰ï¼Œè¯¥å‡½æ•°å°†ä»»åŠ¡åŠ å…¥åˆ°æ‡’åˆ†é…的全局å˜é‡`TASK_MANAGER`的就绪队列ä¸ï¼Œ`TASK_MANAGER`是`TaskManager`结构体的实例,包å«å°±ç»ªé˜Ÿåˆ—å’Œå¯ä¸æ–ç¡çœ 状æ€é˜Ÿåˆ—,用于管ç†è¿›ç¨‹è°ƒåº¦ã€‚ + - 调用`schedule`函数完æˆè¿›ç¨‹åˆ‡æ¢ï¼Œ`schedule`函数负责将当å‰è¿›ç¨‹åˆ‡æ¢åˆ°å¤„ç†å™¨è°ƒåº¦è¿›ç¨‹ï¼ˆ`idle task`),通过获å–`PROCESSOR`(`Processor`结构体的懒分é…全局å˜é‡ï¼‰ä¸çš„`idle_task_cx_ptr`(`idle`控制æµçš„任务上下文指针),并使用汇编代ç `__switch`实现上下文切æ¢ï¼Œå°†æ—§è¿›ç¨‹ä¸Šä¸‹æ–‡ä¿å˜åˆ°å†…å˜ï¼Œä»Žå†…å˜å–出新进程上下文到 CPU 寄å˜å™¨ä¸ã€‚ + - 示例代ç : + +```rust +pub fn suspend_current_and_run_next() { + // There must be an application running. + let task = take_current_task().unwrap(); + // ---- hold current PCB lock + let mut task_inner = task.acquire_inner_lock(); + let task_cx_ptr = &mut task_inner.task_cx as *mut TaskContext; + // Change status to Ready + task_inner.task_status = TaskStatus::Ready; + drop(task_inner); + // ---- release current PCB lock + // push back to ready queue. + add_task(task); + // jump to scheduling cycle + schedule(task_cx_ptr); +} + +lazy_static! { + pub static ref TASK_MANAGER: Mutex<TaskManager> = Mutex::new(TaskManager::new()); +} + +pub fn add_task(task: Arc<TaskControlBlock>) { + TASK_MANAGER.lock().add(task); +} + +impl TaskManager { + pub fn add(&mut self, task: Arc<TaskControlBlock>) { + self.ready_queue.push_back(task); + } +} + +lazy_static! { + pub static ref PROCESSOR: Mutex<Processor> = Mutex::new(Processor::new()); +} + +pub fn schedule(switched_task_cx_ptr: *mut TaskContext) { + let idle_task_cx_ptr = PROCESSOR.lock().get_idle_task_cx_ptr(); + unsafe { + __switch(switched_task_cx_ptr, idle_task_cx_ptr); + } +} +``` + +#### 进程调度 + +1. **调度ç–ç•¥** + - NPUcore 采用时间片轮转(RR)调度ç–略,将所有就绪线程按 FCFS 原则排æˆå°±ç»ªé˜Ÿåˆ—ï¼Œæ¯æ¬¡è°ƒåº¦æ—¶å°† CPU åˆ†æ´¾ç»™é˜Ÿé¦–è¿›ç¨‹ï¼Œæ‰§è¡Œä¸€ä¸ªæ—¶é—´ç‰‡ã€‚æ—¶é’Ÿä¸æ–时,若进程时间片用完,将其é€åˆ°å°±ç»ªé˜Ÿåˆ—é˜Ÿå°¾ï¼Œåˆ‡æ¢æ‰§è¡Œé˜Ÿé¦–进程;若未用完,进程继ç»ä½¿ç”¨ CPU。 + - æ¤å¤–,NPUcore 支æŒé˜»å¡žå¼çš„进程调度模å¼ï¼Œå½“è¿›ç¨‹å› IO æ“ä½œç‰æ— 法获å–èµ„æºæ—¶ï¼Œä¼šè¿›å…¥ç¡çœ 状æ€ï¼Œè®©å‡º CPU,进入阻塞队列,直到被唤醒。唤醒进程的代ç é€šå¸¸åœ¨ä¸æ–处ç†ç¨‹åºä¸ï¼Œå› 为硬件资æºèŽ·å¾—æ—¶å¾€å¾€ä¼´éšä¸æ–。 +2. **相关代ç 实现** + - 任务管ç†å™¨`TaskManager`:是进程调度的容器,包å«å°±ç»ªé˜Ÿåˆ—`ready_queue`å’Œå¯ä¸æ–ç¡çœ 状æ€é˜Ÿåˆ—`interruptible_queue`。其数æ®ç»“构和方法如下: + - æ•°æ®ç»“构: + +```rust +pub struct TaskManager { + pub ready_queue: VecDeque<Arc<TaskControlBlock>>, + pub interruptible_queue: VecDeque<Arc<TaskControlBlock>>, +} +``` + +- **方法**: + + - `new`:åˆå§‹åŒ–`TaskManager`实例,返回包å«ä¸¤ä¸ªç©ºé˜Ÿåˆ—的实例。 + - `add`ï¼šå°†è¿›ç¨‹æ·»åŠ åˆ°å°±ç»ªé˜Ÿåˆ—ã€‚ + - `fetch`:从就绪队列获å–一个进程,若有`oom_handler`特性,获å–è¿›ç¨‹æ—¶ä¼šå°†å…¶æ ‡è®°ä¸ºæ´»è·ƒçŠ¶æ€ã€‚ + - `add_interruptible`:将å¯ä¸æ–è¿›ç¨‹æ·»åŠ åˆ°å¯ä¸æ–队列。 + - `drop_interruptible`:从å¯ä¸æ–队列移除指定进程。 + - `find_by_pid`å’Œ`find_by_tgid`ï¼šæ ¹æ®è¿›ç¨‹ ID 或线程组 ID åœ¨é˜Ÿåˆ—ä¸æŸ¥æ‰¾è¿›ç¨‹ã€‚ + - `ready_count`å’Œ`interruptible_count`:获å–就绪队列和å¯ä¸æ–队列ä¸è¿›ç¨‹çš„æ•°é‡ã€‚ + - `wake_interruptible`:将已唤醒的å¯ä¸æ–进程移动到就绪队列,内部调用`try_wake_interruptible`。 + - `try_wake_interruptible`:å°è¯•将已唤醒的å¯ä¸æ–进程移动到就绪队列,若进程ä¸å˜åœ¨äºŽå°±ç»ªé˜Ÿåˆ—ï¼Œåˆ™æ·»åŠ ï¼›è‹¥å·²å˜åœ¨ï¼Œè¿”回错误。 + +- **ç‰å¾…队列**`WaitQueue` + + :用于管ç†ç‰å¾…ç‰¹å®šèµ„æºæˆ–时间的进程或线程,是先进先出的数æ®ç»“构。其方法如下: + + - `new`:创建新的`WaitQueue`实例。 + - `add_task`ï¼šå°†ä»»åŠ¡æ·»åŠ åˆ°ç‰å¾…队列末尾。 + - `pop_task`:从ç‰å¾…队列å‰ç«¯å¼¹å‡ºä»»åŠ¡ã€‚ + - `contains`:判æ–ç‰å¾…队列是å¦åŒ…å«ç»™å®šä»»åŠ¡ã€‚ + - `is_empty`:判æ–ç‰å¾…队列是å¦ä¸ºç©ºã€‚ + - `wake_all`:唤醒ç‰å¾…é˜Ÿåˆ—ä¸æ‰€æœ‰ä»»åŠ¡ï¼Œå®žé™…é€šè¿‡è°ƒç”¨`wake_at_most(usize::MAX)`实现。 + - `wake_at_most`:唤醒ç‰å¾…队列ä¸ä¸è¶…过`limit`æ•°é‡çš„任务,从队列头部弹出任务,å°è¯•å‡çº§ä»»åŠ¡å¼•ç”¨ï¼Œæ ¹æ®ä»»åŠ¡çŠ¶æ€å¤„ç†ï¼ˆ`Interruptible`状æ€çš„ä»»åŠ¡å°†çŠ¶æ€æ”¹ä¸º`Ready`),并通过`try_wake_interruptible`å°è¯•唤醒任务,记录唤醒数é‡ï¼Œè‹¥è¾¾åˆ°`limit`åˆ™åœæ¢ã€‚ + +- **è¶…æ—¶ç‰å¾…æ± **`TimeoutWaitQueue` + + :用于处ç†ç‰å¾…超时情况,å…许进程或线程设置超时时间,超时未唤醒则触å‘超时逻辑。其方法如下: + + - `new`:创建新的`TimeoutWaitQueue`实例。 + - `add_task`ï¼šå°†å¸¦æœ‰è¶…æ—¶æ—¶é—´çš„ä»»åŠ¡æ·»åŠ åˆ°è¶…æ—¶ç‰å¾…队列,将任务包装æˆ`TimeoutWaiter`ç»“æž„å¹¶æŒ‰è¶…æ—¶æ—¶é—´é¡ºåºæ’å…¥äºŒè¿›åˆ¶å †ã€‚ + - `wake_expired`:唤醒超时ç‰å¾…队列ä¸å·²è¿‡æœŸçš„任务,获å–`TASK_MANAGER`é”,é历任务列表,检查任务超时时间,未过期则放回队列,过期则å°è¯•å‡çº§ä»»åŠ¡å¼•ç”¨ï¼Œè‹¥ä»»åŠ¡å˜åœ¨ä¸”状æ€ä¸º`Interruptible`,则改为`Ready`,并通过`wake_interruptible`唤醒任务。 + +#### 进程退出 + +1. `sys_exit`**系统调用** + - 当应用调用`sys_exit`ç³»ç»Ÿè°ƒç”¨ä¸»åŠ¨é€€å‡ºæˆ–æ‰§è¡Œå‡ºé”™ç”±å†…æ ¸ç»ˆæ¢æ—¶ï¼Œå†…æ ¸è°ƒç”¨`exit_current_and_run_next`函数退出当å‰è¿›ç¨‹å¹¶åˆ‡æ¢åˆ°ä¸‹ä¸€ä¸ªè¿›ç¨‹ã€‚`exit_current_and_run_next`函数以退出ç ä¸ºå‚æ•°ï¼Œå°†å½“å‰è¿›ç¨‹çŠ¶æ€æ”¹ä¸º`Zombie`,写入退出ç 到`TCB`,将当å‰è¿›ç¨‹çš„å进程挂到åˆå§‹è¿›ç¨‹`initproc`下,清空å进程å‘é‡ï¼Œå›žæ”¶å½“å‰è¿›ç¨‹å 用的部分资æºï¼ˆè°ƒç”¨`recycle_data_pages`函数清空地å€ç©ºé—´ä¸çš„逻辑段列表),最åŽè°ƒç”¨`schedule`触å‘调度与任务切æ¢ã€‚ + - 示例代ç : + +```rust +pub fn sys_exit(exit_code: i32) ->! { + exit_current_and_run_next(exit_code); + panic!("Unreachable in sys_exit!"); +} + +pub fn exit_current_and_run_next(exit_code: i32) { + let task = take_current_task().unwrap(); + let mut inner = task.inner_exclusive_access(); + inner.task_status = TaskStatus::Zombie; + inner.exit_code = exit_code; + { + let mut initproc_inner = INITPROC.inner_exclusive_access(); + for child in inner.children.iter() { + child.inner_exclusive_access().parent = Some(Arc::downgrade(&INITPROC)); + initproc_inner.children.push(child.clone()); + } + } + inner.children.clear(); + inner.memory_set.recycle_data_pages(); + drop(inner); + drop(task); + let mut _unused = TaskContext::zero_init(); + schedule(&mut _unused as *mut _); +} + +impl MemorySet { + pub fn recycle_data_pages(&mut self) { + self.areas.clear(); + } +} +``` + + 2.`sys_wait4`**系统调用(父进程回收å进程资æºï¼‰** + +- `sys_wait4`函数用于父进程回收å进程资æºï¼Œå…¶å‚数包括指定进程的`pid`ã€å˜å‚¨é€€å‡ºç 的用户空间区域指针`status`ã€å‡½æ•°æ‰§è¡Œæ–¹å¼é€‰é¡¹`option`å’Œå˜å‚¨è¿›ç¨‹èµ„æºå 用信æ¯çš„`ru`指针。函数逻辑如下: + + - 判æ–当å‰è¿›ç¨‹æ˜¯å¦æœ‰ç¬¦åˆè¦æ±‚çš„åè¿›ç¨‹ï¼ˆæ ¹æ®ä¼ 入的`pid`判æ–ï¼‰ï¼Œè‹¥æ— åˆ™è¿”å›ž`ECHILD`。 + + - 若有符åˆè¦æ±‚çš„å进程,判æ–其䏿˜¯å¦æœ‰åƒµå°¸è¿›ç¨‹ï¼Œè‹¥æœ‰åˆ™è®°å½•其在å进程å‘é‡ä¸çš„ä¸‹æ ‡ï¼›è‹¥æ— åˆ™æ ¹æ®`option`ä¸çš„`WNOHANG`æ ‡å¿—å¤„ç†ï¼ˆè‹¥æœ‰è¯¥æ ‡å¿—,返回`SUCCESS`ï¼›è‹¥æ— åˆ™åˆ‡æ¢è‡³ä¸‹ä¸€ä¸ªè¿›ç¨‹æ‰§è¡Œï¼‰ã€‚ + + - 将僵尸å进程从å‘é‡ä¸ç§»é™¤ï¼Œç¡®è®¤è¿™æ˜¯å¯¹è¯¥å进程控制å—çš„å”¯ä¸€ä¸€æ¬¡å¼ºå¼•ç”¨ï¼Œç„¶åŽæ”¶é›†å进程信æ¯ï¼ˆå¦‚退出ç ç‰ï¼‰ï¼Œæœ€åŽä»¥å›žæ”¶çš„å进程`PID`作为函数返回值返回。 + +- 示例代ç : + +```rust +pub fn sys_wait4(pid: isize, status: *mut u32, option: u32, ru: *mut Rusage) -> isize { + let option = WaitOption::from_bits(option).unwrap(); + info!("[sys_wait4] pid: {}, option: {:?}", pid, option); + let task = current_task().unwrap(); + let token = task.get_user_token(); + loop { + // find a child process + let mut inner = task.acquire_inner_lock(); + if inner + .children + .iter() + .find(|p| pid == -1 || pid as usize == p.getpid()) + .is_none() + { + return ECHILD; + } + inner + .children + .iter() + .filter(|p| pid == -1 || pid as usize == p.getpid()) + .for_each(|p| { + trace!( + "[sys_wait4] found child pid: {}, status: {:?}", + p.pid.0, + p.acquire_inner_lock().task_status + ); + }); + let pair = inner.children.iter().enumerate().find(|(_, p)| { + // ++++ temporarily hold child PCB lock + pid == -1 || pid as usize == p.getpid() + }); + if let Some((idx, _)) = pair { + // drop last TCB of child + let child = inner.children.remove(idx); + // confirm that child will be deallocated after being removed from children list + assert_eq!(Arc::strong_count(&child), 1); + // if main thread exit + if child.pid.0 == child.tgid { + let found_pid = child.getpid(); + // ++++ temporarily hold child lock + let exit_code = child.acquire_inner_lock().exit_code; + // ++++ release child PCB lock + if!status.is_null() { + // this may NULL!!! + match translated_refmut(token, status) { + Ok(word) => *word = exit_code, + Err(errno) => return errno, + }; + } + return found_pid as isize; + } + } else { + drop(inner); + if option.contains(WaitOption::WNOHANG) { + return SUCCESS; + } else { + block_current_and_run_next(); + debug!("[sys_wait4] --resumed--"); + } + } + } +} +``` + + 3.`sys_kill`**系统调用(进程间的`kill`机制)** + +- `sys_kill`系统调用用于一个进程 â€œæ€æ»â€ 其他进程,函数接å—目的进程的`pid`和信å·`sig`ä¸¤ä¸ªå‚æ•°ã€‚å®žçŽ°é€»è¾‘ä¸ºæ‰¾å‡ºè¦ â€œæ€æ»â€ 的进程,赋予指定信å·é‡ï¼Œè‹¥è¿›ç¨‹å¤„于阻塞æ€åˆ™å”¤é†’它,让其自我终结。目å‰è¯¥ç³»ç»Ÿè°ƒç”¨ä»…æ˜¯åˆæ¥å®žçŽ°ï¼Œæœªæœ€ç»ˆå®Œå–„ã€‚ +- 示例代ç : + +```rust +pub fn sys_kill(pid: usize, sig: usize) -> isize { + let signal = match Signals::from_signum(sig) { + Ok(signal) => signal, + Err(_) => return EINVAL, + }; + if pid > 0 { + if let Some(task) = find_task_by_tgid(pid) { + if!signal.is_empty() { + let mut inner = task.acquire_inner_lock(); + inner.add_signal(signal); + // wake up target process if it is sleeping + if inner.task_status == TaskStatus::Interruptible { + inner.task_status = TaskStatus::Ready; + drop(inner); + wake_interruptible(task); + } + } + SUCCESS + } else { + ESRCH + } + } else if pid == 0 { + todo!() + } else if (pid as isize) == -1 { + todo!() + } else { // (pid as isize) < -1 + todo!() + } +} +``` + +### 文件系统 + +#### 概述 + +1. **文件抽象** + - **文件æ“作接å£å®šä¹‰**:在`os/fs/file_trait.rs`ä¸å®šä¹‰äº†æ–‡ä»¶æ“作的接å£`File` trait,包å«äº†ä¸€ç³»åˆ—方法,如`deep_clone`用于深度å¤åˆ¶æ–‡ä»¶ï¼Œ`readable`å’Œ`writable`åˆ¤æ–æ–‡ä»¶æ˜¯å¦å¯è¯»å¯å†™ï¼Œ`read`å’Œ`write`实现文件的读写æ“作,`get_size`ã€`get_stat`ã€`get_file_type`èŽ·å–æ–‡ä»¶çš„基本信æ¯ï¼ˆå¤§å°ã€ç»Ÿè®¡ä¿¡æ¯ã€æ–‡ä»¶ç±»åž‹ï¼‰ç‰ã€‚这些方法为文件æ“作æä¾›äº†ç»Ÿä¸€çš„æŠ½è±¡ï¼Œä¸åŒçš„æ–‡ä»¶ç³»ç»Ÿå®žçްå¯ä»¥æ ¹æ®è‡ªèº«ç‰¹ç‚¹æ¥å…·ä½“实现这些方法。 + - **文件结构实现**:以`OSInode`为例(在`os/fs/inode.rs`ä¸å®šä¹‰ï¼‰ï¼Œå®ƒå®žçŽ°äº†`File` trait,其结构包å«`readable`ã€`writable`ã€`special_use`ã€`append`ç‰å—段,用于表示文件的读写属性ã€ç‰¹æ®Šç”¨é€”å’Œè¿½åŠ æ¨¡å¼ç‰ã€‚`inner`å—æ®µæŒ‡å‘`Inode`,记录文件详细内容,通过`Arc`指针实现硬链接机制,确ä¿å¤šä¸ª`OSInode`坿Œ‡å‘相åŒçš„`InodeImpl`,并且在所有硬链接释放åŽï¼Œæ–‡ä»¶ä¿¡æ¯æ‰è¢«å½»åº•释放。 +2. **文件系统的目录结构** + - **ç›®å½•æ ‘èŠ‚ç‚¹ç»“æž„**:文件结构`OSInode`ä¸çš„`dirnode_ptr`指å‘`DirectoryTreeNode`ç›®å½•æ ‘èŠ‚ç‚¹ç»“æž„ï¼ˆåœ¨`os/fs/directory_tree.rs`ä¸å®šä¹‰ï¼‰ï¼Œè¯¥ç»“æž„æœ¬è´¨ä¸Šæ˜¯ä¸€ç§ Inode 节点,内部记录了目录å—符串指å‘的文件信æ¯ï¼ŒåŒ…括`spe_usage`(用于记录目录的使用情况)ã€`name`(目录å称)ã€`filesystem`ï¼ˆæŒ‡å‘æ‰€å±žæ–‡ä»¶ç³»ç»Ÿï¼‰ã€`file`(指å‘对应文件)ã€`selfptr`å’Œ`father`ï¼ˆç”¨äºŽæž„å»ºç›®å½•æ ‘ç»“æž„ï¼‰ã€`children`(用于å˜å‚¨å目录或文件节点)ç‰å—段。 + - **目录节点å‘é‡ä¸Žæ ¹ç›®å½•节点**ï¼šå†…æ ¸å…¨å±€ç»´æŠ¤äº†`DIRECTORY_VEC`目录节点å‘é‡ï¼ˆåœ¨`os/fs/directory_tree.rs`ä¸å®šä¹‰ï¼‰ï¼Œç”¨äºŽè®°å½•当å‰ç³»ç»Ÿæ‰€åœ¨çš„ç›®å½•ï¼ŒåŒæ—¶è®°å½•äº†æ ¹ç›®å½•èŠ‚ç‚¹`ROOT`,其目录为空å—ç¬¦ä¸²ã€‚å†…æ ¸æä¾›äº†`insert_directory_vec`ã€`delete_directory_vec`ã€`update_directory_vec`ç‰æŽ¥å£ï¼Œç”¨äºŽæ–¹ä¾¿åœ°å®žçŽ°ç›®å½•è·³è½¬ç‰æ“作,基于这些方法,è¡ç”Ÿå‡ºäº†ä¸€ç³»åˆ—基本文件æ“作方法,如`mkdir`ã€`cd`ã€`open`ã€`create`ã€`delete`ã€`rename`ç‰ã€‚ +3. **虚拟文件系统** + - **多层次文件系统结构** + - **ç£ç›˜å—设备接å£å±‚**:在`easy-fs/src/block_dev.rs`ä¸å®šä¹‰äº†`BlockDevice` trait,æä¾›äº†å¯¹å—设备进行读写的æ“作接å£ï¼ŒåŒ…括`read_block`å’Œ`write_block`方法,分别用于从å—è®¾å¤‡è¯»å–æ•°æ®åˆ°å†…å˜ç¼“冲区和将内å˜ç¼“冲区数æ®å†™å›žå—设备,数æ®ä»¥å—为å•ä½è¿›è¡Œè¯»å†™ã€‚NPUcore 通过 K210 ä¾èµ–ä¸çš„ GPIO ç«¯å£ SPI 串å£åº•层支æŒï¼Œåœ¨`os/src/drivers/block/sdcard.rs`ä¸å¯¹`SDCardWrapper`实现了`BlockDevice` trait,实现了对 SD å¡çš„直接读写æ“作,并设置了 I/O 故障时的最大é‡è¯•次数为 5。 + - **å—缓å˜å±‚**:ä½äºŽ`easy-fs/src/block_cache.rs`,主è¦ç›®çš„æ˜¯æé«˜æ–‡ä»¶ç³»ç»Ÿæ€§èƒ½å’Œæ•ˆçŽ‡ã€‚é€šè¿‡åœ¨å†…å˜ä¸ç¼“å˜ç£ç›˜å—,å‡å°‘ç£ç›˜ I/O æ“ä½œï¼ŒåŠ é€Ÿæ•°æ®è®¿é—®ï¼Œåˆå¹¶å†™æ“作,å‡å°‘é‡å¤æ•°æ®è¯»å–,æä¾›ä¸€è‡´æ€§å’ŒåŒæ¥æœºåˆ¶ï¼Œæ”¯æŒå¼‚æ¥å†™æ“作,å‡è½»ç£ç›˜è´Ÿè½½ã€‚定义了`Cache` trait 用于缓å˜å¯¹è±¡çš„基本æ“作,包括`read`ã€`modify`å’Œ`sync`方法,分别用于åªè¯»è®¿é—®ç¼“å˜ã€ä¿®æ”¹ç¼“å˜å’Œå°†ç¼“å˜æ•°æ®å†™å›žç£ç›˜ã€‚`CacheManager` trait 用于管ç†ç¼“å˜ï¼Œ`BlockCacheManager`å’Œ`PageCacheManager` trait 进一æ¥å°è£…了`CacheManager`,分别用于管ç†å—缓å˜å’Œé¡µç¼“å˜ï¼Œæä¾›äº†èŽ·å–缓å˜å—的方法,如`try_get_block_cache`å’Œ`get_block_cache`。 + - **ç£ç›˜æ•°æ®ç»“构层**:NPUcore çš„`easy-fs`文件系统使用 fat32 实现,该层包å«ç®¡ç†æ–‡ä»¶ç³»ç»Ÿçš„超级å—ã€ç´¢å¼•节点ä½å›¾åŒºã€æ•°æ®å—ä½å›¾åŒºã€ç´¢å¼•节点区和数æ®å—区ç‰ã€‚在`layout.rs`ä¸æè¿°äº†ç›¸å…³ fat 文件系统所需的数æ®ç»“构,如`BPB`ã€`FSInfo`ã€`FATDirEnt`ç‰ï¼Œ`bitmap.rs`ä¸å®šä¹‰äº†`FAT`结构体用于维护 fat 表,实现了如`get_next_clus_num`ã€`get_all_clus_num`ã€`alloc`ã€`free`ç‰æ–¹æ³•,用于管ç†ç°‡çš„分é…和释放。 + - **ç®€å•æ–‡ä»¶ç³»ç»Ÿå±‚**:ä½äºŽ`efs.rs`,逻辑上介于 VFS å’Œ fat32 文件系统之间,用于维护数æ®åŒºï¼Œæ–¹ä¾¿ VFS æ“作。定义了`EasyFileSystem`结构体,包å«`block_device`(å—设备指针)ã€`fat`(fat 指针)ã€`data_area_start_block`(数æ®åŒºå¼€å§‹çš„ç£ç›˜ç¼–å·ï¼‰ã€`root_clus`ï¼ˆæ ¹ç›®å½•çš„ç°‡å·ï¼‰ã€`sec_per_clus`(æ¯ä¸ªç°‡çš„æ‰‡åŒºæ•°ï¼‰ã€`byts_per_sec`(æ¯ä¸ªæ‰‡åŒºçš„å—节数)ç‰å—段,实现了`first_sector_of_cluster`(计算给定簇的第一个扇区编å·ï¼‰ã€`open`(打开文件系统)ã€`alloc_blocks`ï¼ˆåˆ†é…æ–°çš„å—ï¼‰ç‰æ–¹æ³•。 + - **虚拟文件系统层**:ä½äºŽæ–‡ä»¶ç³»ç»Ÿå±‚次的最高层,æä¾›æ–‡ä»¶å’Œ I 节点的抽象,å¯ç›´æŽ¥è¢«å†…æ ¸æ“作,å±è”½ä¸åŒæ–‡ä»¶ç³»ç»Ÿçš„差异,为上层æä¾›ç»Ÿä¸€æŽ¥å£ã€‚在`vfs.rs`ä¸å®šä¹‰äº†ç›¸å…³æ•°æ®ç»“构,如`FileContent`用于æè¿°æ–‡ä»¶å†…容,包å«`size`(文件大å°ï¼‰ã€`clus_list`(文件包å«çš„ç°‡å·ï¼‰ã€`file_cache_mgr`(文件的 cache 管ç†å™¨ï¼‰ã€`hint`(维护目录文件的特殊目录项)ç‰å—段;`Inode`用于æè¿°æ–‡ä»¶ä¿¡æ¯ï¼ŒåŒ…å«`inode_lock`(读写é”)ã€`file_content`ï¼ˆæŒ‡å‘æ–‡ä»¶å†…容)ã€`file_cache_mgr`(指å‘管ç†è¯¥ inode çš„ PageCacheManager)ã€`file_type`(文件类型)ã€`parent_dir`(指å‘父目录的 inode åŠä½ç½®ï¼‰ã€`fs`ï¼ˆæŒ‡å‘æ‰€å±žç®€å•文件系统)ã€`time`(文件相关时间属性)ã€`deleted`ï¼ˆæ ‡è¯†æ˜¯å¦é‡Šæ”¾æ–‡ä»¶å†…容区域)ç‰å—段,并实现了文件创建ã€åˆ 除ã€è¯»å†™ã€ä¿®æ”¹å¤§å°ã€éåŽ†å’ŒæŸ¥è¯¢ç‰æ“作方法;`DirIter`是用于目录项的è¿ä»£å™¨ï¼Œ`DirWalker`是基于`DirIter`的目录文件è¿ä»£å™¨ï¼Œç”¨äºŽè¿ä»£ç›®å½•æ¡ç›®ã€‚ + - **VFS** **接å£** + - **超级å—**:用于ä¿å˜æ–‡ä»¶ç³»ç»Ÿçš„æ‰€æœ‰å…ƒæ•°æ®ï¼Œæ˜¯æ–‡ä»¶ç³»ç»Ÿçš„ä¿¡æ¯åº“,代表一个文件系统,文件系统的元数æ®ä¿®æ”¹ä¼šåæ˜ åœ¨è¶…çº§å—上,超级å—对象常驻内å˜å¹¶è¢«ç¼“å˜ï¼Œä»¥é“¾å¼æ–¹å¼ç»´æŠ¤ï¼Œä¸ºæ‰€æœ‰è¿›ç¨‹å¯è§ã€‚ + - **目录项**:管ç†è·¯å¾„的目录项,å˜å‚¨ç›®å½•下文件的 inode å·å’Œæ–‡ä»¶åç‰ä¿¡æ¯ï¼Œå†…éƒ¨ä¸ºæ ‘å½¢ç»“æž„ï¼Œæ“ä½œç³»ç»Ÿé€šè¿‡ä»Žæ ¹ç›®å½•å¼€å§‹æŒ‰å±‚æ¬¡è§£æžè·¯å¾„æ¥æ£€ç´¢æ–‡ä»¶ã€‚ + - **inode**ï¼šå˜æ”¾å…·ä½“文件的一般信æ¯ï¼Œæ˜¯æ–‡ä»¶çš„å”¯ä¸€æ ‡è¯†ï¼Œä¸€ä¸ª inode 对应一个文件,通过 inode 坿‰¾åˆ°æ–‡ä»¶åœ¨ç£ç›˜æ‰‡åŒºçš„ä½ç½®ï¼Œinode 模å—å¯é“¾æŽ¥åˆ° address_space 模å—ï¼Œæ–¹ä¾¿æŸ¥æ‰¾æ–‡ä»¶æ•°æ®æ˜¯å¦å·²ç¼“å˜ã€‚ + - **打开文件列表模å—**ï¼šåŒ…å«æ‰€æœ‰å†…æ ¸å·²æ‰“å¼€çš„æ–‡ä»¶ï¼Œæ‰“å¼€çš„æ–‡ä»¶å¯¹è±¡ç”± open ç³»ç»Ÿè°ƒç”¨åœ¨å†…æ ¸ä¸åˆ›å»ºï¼Œä¹Ÿå«æ–‡ä»¶å¥æŸ„,列表ä¸çš„æ¯ä¸ªè¡¨é¡¹æ˜¯ä¸€ä¸ªç»“æž„ä½“`struct file`,å˜å‚¨æ–‡ä»¶çš„å„ç§çжæ€å‚数。 + - **file_operations**:模å—维护一个数æ®ç»“构,是一系列函数指针的集åˆï¼ŒåŒ…嫿‰€æœ‰å¯ä½¿ç”¨çš„系统调用函数,如 openã€readã€writeã€mmap ç‰ï¼Œæ¯ä¸ªæ‰“开文件å¯é€šè¿‡è¿žæŽ¥åˆ°è¯¥æ¨¡å—,实现对文件的å„ç§æ“作。 + - **address_space**:表示文件在页缓å˜ä¸å·²ç¼“å˜çš„物ç†é¡µï¼Œæ˜¯é¡µç¼“å˜å’Œå¤–éƒ¨è®¾å¤‡ä¸æ–‡ä»¶ç³»ç»Ÿçš„æ¡¥æ¢ï¼Œå…³è”了内å˜ç³»ç»Ÿå’Œæ–‡ä»¶ç³»ç»Ÿï¼Œå†…éƒ¨ç»´æŠ¤æ ‘ç»“æž„æŒ‡å‘物ç†é¡µç»“æž„`page`ï¼ŒåŒæ—¶é€šè¿‡`host`æŒ‡é’ˆæŒ‡å‘ inode èŽ·å–æ–‡ä»¶å…ƒæ•°æ®ã€‚ +4. **文件共享与** **PIPE** + - **软链接与硬链接**:在 NPUcore ä¸ï¼Œ`OSInode`包å«`inner: Arc<InodeImpl>`,指å‘`Inode`,实现了 Linux 的硬链接。多个`OSInode`坿Œ‡å‘相åŒçš„`InodeImpl`,文件数æ®ç©ºé—´åªå 用一份。`OSInode`实现了`Drop` traitï¼Œå½“ç¡¬é“¾æŽ¥å…¨éƒ¨åˆ é™¤åŽï¼Œ`drop`方法会å‡å°‘目录项的引用计数,计数为 0 时触å‘回收机制,释放文件空间。 + - **ç®¡é“æœºåˆ¶** + - **管é“定义与结构**:管é“用于在具有父åå…³ç³»çš„è¿›ç¨‹é—´ä¼ é€’æ•°æ®ï¼Œåœ¨ NPUcore ä¸ï¼Œç®¡é“的原型为`Pipe`结构体(在`os/src/process/pipe.rs`ä¸å®šä¹‰ï¼‰ï¼ŒåŒ…å«`readable`å’Œ`writable`å—æ®µè¡¨ç¤ºç®¡é“端的读写属性,`buffer`å—æ®µæŒ‡å‘`PipeRingBuffer`管é“自身,`PipeRingBuffer`是一个固定长度为 32 çš„`u8`循环队列,包å«`arr`ï¼ˆæ•°æ®æ•°ç»„)ã€`head`(头指针)ã€`tail`(尾指针)ã€`status`(队列状æ€ï¼‰ã€`write_end`(写端弱引用数目)ç‰å—段,通过头尾指针判æ–队列状æ€ã€‚ + - **管é“创建与系统调用**:`make_pipe`函数创建管é“,返回管é“的两端(读端和写端)。`sys_pipe`ç³»ç»Ÿè°ƒç”¨é€šè¿‡ä¼ å…¥ç©ºç™½æ–‡ä»¶æè¿°ç¬¦åœ°å€`pipe`,为其创建管é“ã€å†™ç«¯ä¸Žè¯»ç«¯çš„æ–‡ä»¶æè¿°ç¬¦ï¼Œå°†æ–‡ä»¶æè¿°ç¬¦å˜å…¥è¿›ç¨‹æŽ§åˆ¶å—的文件æè¿°ç¬¦åˆ—表ä¸ï¼Œå¹¶å°†åœ°å€å†™å…¥`pipe`。管é“两端实现了`File` trait,å¯åƒæ–‡ä»¶ä¸€æ ·è¿›è¡Œè¯»å†™æ“作。 + - **管é“缓冲区读写**:管é“缓冲区读写方法类似循环队列的`pop`å’Œ`push`æ“作,`write_byte`方法å‘缓冲区写入数æ®ï¼Œ`read_byte`æ–¹æ³•ä»Žç¼“å†²åŒºè¯»å–æ•°æ®ï¼ŒåŒæ—¶å®šä¹‰äº†`available_read`å’Œ`available_write`方法分别指出当å‰å¯è¯»å’Œå¯å†™çš„æ•°ç›®ï¼Œ`all_write_ends_closed`方法判æ–管é“写端是å¦å…¨éƒ¨å…³é—。 + - **管é“å…³é—**:通过系统调用`sys_close`å…³é—管é“的两端,将文件æè¿°ç¬¦æ ‡è®°ä¸ºç©ºï¼Œå¯¼è‡´`Arc`引用被销æ¯ï¼Œå½“管é“两端都关é—åŽï¼Œ`buffer`的引用计数为 0,管é“自身被销æ¯ã€‚ + +#### 文件相关系统调用代ç åŠè§£é‡Š + +1. ##### **open** **系统调用** + + - **用户æ€ä»£ç ** + + - 在`user/src/syscall.rs`ä¸ï¼Œ`sys_open`函数用于å‘èµ·æ‰“å¼€æ–‡ä»¶çš„ç³»ç»Ÿè°ƒç”¨ï¼Œå®ƒæŽ¥å—æ–‡ä»¶å`path`å’Œæ‰“å¼€æ ‡å¿—`flags`ä½œä¸ºå‚æ•°ï¼Œå°†å…¶å°è£…åŽé€šè¿‡`syscall`å‡½æ•°ä¼ é€’ç»™å†…æ ¸ã€‚ + + ```rust + pub fn sys_open(path: &str, flags: u32) -> isize { + syscall(SYSCALL_OPEN, [path.as_ptr() as usize, flags as usize, 0]) + } + ``` + + - 在`user/src/lib.rs`ä¸ï¼Œä½¿ç”¨`bitflags!`å®å®šä¹‰äº†`OpenFlags`结构体,将`u32`类型的`flags`包装为更易使用的结构体,方便设置和检查打开文件的模å¼ï¼Œå¦‚åªè¯»ã€åªå†™ã€è¯»å†™ã€è¿½åŠ ã€åˆ›å»ºã€æˆªæ–ç‰ã€‚ + + ```rust + bitflags! { + pub struct OpenFlags: u32 { + const RDONLY = 0; + const WRONLY = 1 << 0; + const RDWR = 1 << 1; + const CREATE = 1 << 6; + const TRUNC = 1 << 9; + } + } + ``` + + - 在`user/src/user_call.rs`ä¸ï¼Œ`open`函数是对`sys_open`的进一æ¥å°è£…ï¼Œå°†ç”¨æˆ·ä¼ å…¥çš„`OpenFlags`类型的`flags`转æ¢ä¸º`u32`åŽä¼ 递给`sys_open`,使得用户å¯ä»¥æ›´æ–¹ä¾¿åœ°ä½¿ç”¨æ‰“开文件的功能。 + + ```rust + pub fn open(path: &str, flags: OpenFlags) -> isize { + sys_open(path, flags.bits) + } + ``` + + - **å†…æ ¸æ€ä»£ç **:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_open`系统调用会调用`sys_openat`å‡½æ•°ï¼Œå¹¶ä¼ å…¥`AT_FDCWD`(当å‰å·¥ä½œç›®å½•ï¼‰ã€æ–‡ä»¶åã€æ‰“å¼€æ ‡å¿—å’Œé»˜è®¤æƒé™`0o777u32`。 + + `sys_openat`å‡½æ•°ä¼šæ ¹æ®ä¼ å…¥çš„å‚æ•°é€‰æ‹©è¦æ‰“开的文件æè¿°ç¬¦ï¼Œå¹¶å°è¯•打开文件,如果æˆåŠŸåˆ™å°†æ–°æ‰“å¼€çš„æ–‡ä»¶æè¿°ç¬¦æ’入到当å‰ä»»åŠ¡çš„æ–‡ä»¶æè¿°ç¬¦è¡¨ä¸ï¼Œå¹¶è¿”回新文件æè¿°ç¬¦çš„æ•´æ•°å€¼ï¼›å¦‚果失败则返回相应的错误ç 。 + + ```rust + SYSCALL_OPEN => sys_openat(AT_FDCWD, args[0] as *const u8, args[1] as u32, 0o777u32), + ``` + +2. ##### **close** **系统调用** + + - **用户æ€ä»£ç **:在`user/src/syscall.rs`ä¸ï¼Œ`sys_close`å‡½æ•°æŽ¥å—æ–‡ä»¶æè¿°ç¬¦`fd`ä½œä¸ºå‚æ•°ï¼Œé€šè¿‡`syscall`å‡½æ•°å°†å…³é—æ–‡ä»¶çš„è¯·æ±‚ä¼ é€’ç»™å†…æ ¸ã€‚ + + ```rust + pub fn sys_close(fd: usize) -> isize { + syscall(SYSCALL_CLOSE, [fd]) + } + ``` + + - **å†…æ ¸æ€ä»£ç **:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_close`函数首先获å–当å‰ä»»åŠ¡çš„å¼•ç”¨ï¼Œç„¶åŽèŽ·å–任务的文件表é”,通过文件æè¿°ç¬¦`fd`从文件表ä¸èŽ·å–æ–‡ä»¶æè¿°ç¬¦çš„å¼•ç”¨ã€‚å¦‚æžœèŽ·å–æˆåŠŸï¼Œå°†æ–‡ä»¶æè¿°ç¬¦è¡¨ä¸å¯¹åº”的项设置为`None`,释放资æºå¹¶è¿”回`SUCCESS`;如果获å–失败,则返回相应的错误ç 。 + + ```rust + pub fn sys_close(fd: usize) -> isize { + info!("[sys_close] fd: {}", fd); + let task = current_task().unwrap(); + let mut fd_table = task.files.lock(); + match fd_table.remove(fd) { + Ok(_) => SUCCESS, + Err(errno) => errno, + } + } + ``` + +3. ##### **read** **系统调用** + + - **用户æ€ä»£ç **:在`user/src/syscall.rs`ä¸ï¼Œ`sys_read`å‡½æ•°æŽ¥å—æ–‡ä»¶æè¿°ç¬¦`fd`ã€ç¼“冲区`buf`å’Œè¦è¯»å–çš„å—节数`count`ä½œä¸ºå‚æ•°ï¼Œé€šè¿‡`syscall`å‡½æ•°å°†è¯»å–æ–‡ä»¶æ•°æ®çš„è¯·æ±‚ä¼ é€’ç»™å†…æ ¸ã€‚ + + ```rust + pub fn sys_read(fd: usize, buf: usize, count: usize) -> isize { + syscall(SYSCALL_READ, [fd, buf, count]) + } + ``` + + - **å†…æ ¸æ€ä»£ç ** + + - 在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_read`函数首先获å–当å‰ä»»åŠ¡çš„å¼•ç”¨ï¼Œç„¶åŽèŽ·å–任务的文件表é”,通过文件æè¿°ç¬¦`fd`从文件表ä¸èŽ·å–æ–‡ä»¶æè¿°ç¬¦çš„引用。如果文件ä¸å¯è¯»ï¼Œåˆ™è¿”回错误ç `EBADF`。接ç€èŽ·å–当å‰ä»»åŠ¡çš„ç”¨æˆ·ä»¤ç‰Œï¼Œå°†ç”¨æˆ·ç©ºé—´çš„ç¼“å†²åŒºåœ°å€å’Œé•¿åº¦è½¬æ¢ä¸ºå†…æ ¸å¯ä»¥æ“作的`UserBuffer`对象,然åŽè°ƒç”¨æ–‡ä»¶æè¿°ç¬¦çš„`read_user`方法从文件ä¸è¯»å–æ•°æ®åˆ°ç”¨æˆ·æä¾›çš„缓冲区ä¸ï¼ŒæˆåŠŸæ—¶è¿”å›žè¯»å–çš„å—节数,失败时返回相应的错误ç 。 + + ```rust + pub fn sys_read(fd: usize, buf: usize, count: usize) -> isize { + let task = current_task().unwrap(); + let fd_table = task.files.lock(); + let file_descriptor = match fd_table.get_ref(fd) { + Ok(file_descriptor) => file_descriptor, + Err(errno) => return errno, + }; + // fd is not open for reading + if!file_descriptor.readable() { + return EBADF; + } + let token = task.get_user_token(); + file_descriptor.read_user( + None, + UserBuffer::new({ + match translated_byte_buffer(token, buf as *const u8, count) { + Ok(buffer) => buffer, + Err(errno) => return errno, + } + }), + ) as isize + } + ``` + +4. ##### **write** **系统调用** + + - **用户æ€ä»£ç **:在`user/src/syscall.rs`ä¸ï¼Œ`sys_write`å‡½æ•°æŽ¥å—æ–‡ä»¶æè¿°ç¬¦`fd`ã€ç¼“冲区`buf`å’Œè¦å†™å…¥çš„å—节数`count`ä½œä¸ºå‚æ•°ï¼Œé€šè¿‡`syscall`函数将写入文件数æ®çš„è¯·æ±‚ä¼ é€’ç»™å†…æ ¸ã€‚ + + ```rust + pub fn sys_write(fd: usize, buf: usize, count: usize) -> isize { + syscall(SYSCALL_WRITE, [fd, buf, count]) + } + ``` + + - **å†…æ ¸æ€ä»£ç ** + + - 在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_write`函数首先获å–当å‰ä»»åŠ¡çš„å¼•ç”¨ï¼Œç„¶åŽèŽ·å–任务的文件表é”,通过文件æè¿°ç¬¦`fd`从文件表ä¸èŽ·å–æ–‡ä»¶æè¿°ç¬¦çš„引用。如果文件ä¸å¯å†™ï¼Œåˆ™è¿”回错误ç `EBADF`。接ç€èŽ·å–当å‰ä»»åŠ¡çš„ç”¨æˆ·ä»¤ç‰Œï¼Œå°†ç”¨æˆ·ç©ºé—´çš„ç¼“å†²åŒºåœ°å€å’Œé•¿åº¦è½¬æ¢ä¸ºå†…æ ¸å¯ä»¥æ“作的`UserBuffer`对象,然åŽè°ƒç”¨æ–‡ä»¶æè¿°ç¬¦çš„`write_user`方法将用户æä¾›çš„缓冲区ä¸çš„æ•°æ®å†™å…¥åˆ°ä¸Žæ–‡ä»¶æè¿°ç¬¦å¯¹åº”的文件ä¸ï¼ŒæˆåŠŸæ—¶è¿”å›žå†™å…¥çš„å—节数,失败时返回相应的错误ç 。 + + ```rust + pub fn sys_write(fd: usize, buf: usize, count: usize) -> isize { + let task = current_task().unwrap(); + let fd_table = task.files.lock(); + let file_descriptor = match fd_table.get_ref(fd) { + Ok(file_descriptor) => file_descriptor, + Err(errno) => return errno, + }; + if!file_descriptor.writable() { + return EBADF; + } + let token = task.get_user_token(); + file_descriptor.write_user( + None, + UserBuffer::new({ + match translated_byte_buffer(token, buf as *const u8, count) { + Ok(buffer) => buffer, + Err(errno) => return errno, + } + }), + ) as isize + } + ``` + +5. ##### **fstat** **å’Œ** **fstatat** **系统调用** + + - **用户æ€ä»£ç ** + + - 在`user/src/syscall.rs`ä¸ï¼Œ`sys_fstat`å‡½æ•°æŽ¥å—æ–‡ä»¶æè¿°ç¬¦`fd`和缓冲区`statbuf`ä½œä¸ºå‚æ•°ï¼Œç”¨äºŽèŽ·å–æ‰“开文件的状æ€ä¿¡æ¯å¹¶å°†å…¶å˜å‚¨åˆ°`statbuf`ä¸ï¼Œé€šè¿‡`syscall`å‡½æ•°å°†è¯·æ±‚ä¼ é€’ç»™å†…æ ¸ã€‚ + + ```rust + pub fn sys_fstat(fd: usize, statbuf: *mut u8) -> isize { + syscall(SYSCALL_FSTAT, [fd, statbuf as usize]) + } + ``` + + - 在`user/src/syscall.rs`ä¸ï¼Œ`sys_fstatat`函数接å—目录文件æè¿°ç¬¦`dirfd`ã€æ–‡ä»¶è·¯å¾„`path`ã€ç¼“冲区`buf`å’Œæ ‡å¿—`flags`ä½œä¸ºå‚æ•°ï¼Œç”¨äºŽèŽ·å–æŒ‡å®šç›®å½•下文件的状æ€ä¿¡æ¯å¹¶å°†å…¶å˜å‚¨åˆ°`buf`ä¸ï¼Œé€šè¿‡`syscall`å‡½æ•°å°†è¯·æ±‚ä¼ é€’ç»™å†…æ ¸ã€‚ + + ```rust + pub fn sys_fstatat(dirfd: usize, path: *const u8, buf: *mut u8, flags: u32) -> isize { + syscall(SYSCALL_FSTATAT, [dirfd, path as usize, buf as usize, flags]) + } + ``` + + - **å†…æ ¸æ€ä»£ç ** + + - 在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_fstat`函数首先获å–当å‰ä»»åŠ¡çš„å¼•ç”¨ï¼Œç„¶åŽèŽ·å–ä»»åŠ¡çš„ç”¨æˆ·ä»¤ç‰Œã€‚æŽ¥ç€æ ¹æ®æ–‡ä»¶æè¿°ç¬¦`fd`获å–对应的文件æè¿°ç¬¦å¯¹è±¡ï¼Œå¦‚æžœ`fd`为`AT_FDCWD`(当å‰å·¥ä½œç›®å½•),则获å–当å‰ä»»åŠ¡æ–‡ä»¶ç³»ç»Ÿçš„å·¥ä½œèŠ‚ç‚¹ï¼›å¦åˆ™ä»Žæ–‡ä»¶æè¿°ç¬¦è¡¨ä¸èŽ·å–。然åŽè¯»å–文件的状æ€ä¿¡æ¯å¹¶å¤åˆ¶åˆ°ç”¨æˆ·æä¾›çš„`statbuf`缓冲区ä¸ï¼Œå¦‚æžœå¤åˆ¶å¤±è´¥åˆ™è¿”回错误ç `EFAULT`,æˆåŠŸåˆ™è¿”å›ž`SUCCESS`。 + + ```rust + pub fn sys_fstat(fd: usize, statbuf: *mut u8) -> isize { + let task = current_task().unwrap(); + let token = task.get_user_token(); + info!("[sys_fstat] fd: {}", fd); + let file_descriptor = match fd { + AT_FDCWD => task.fs.lock().working_inode.as_ref().clone(), + fd => { + let fd_table = task.files.lock(); + match fd_table.get_ref(fd) { + Ok(file_descriptor) => file_descriptor.clone(), + Err(errno) => return errno, + } + } + }; + if copy_to_user(token, &file_descriptor.get_stat(), statbuf as *mut Stat).is_err() { + log::error!("[sys_fstat] Failed to copy to {:?}", statbuf); + return EFAULT; + }; + SUCCESS + } + ``` + + - 在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_fstatat`函数首先获å–当å‰ä»»åŠ¡çš„ç”¨æˆ·ä»¤ç‰Œï¼Œå°†ç”¨æˆ·æä¾›çš„æ–‡ä»¶è·¯å¾„`path`从用户空间地å€è½¬æ¢ä¸ºå†…æ ¸ç©ºé—´å¯å¤„ç†çš„æ ¼å¼ï¼Œå¦‚果转æ¢å¤±è´¥åˆ™è¿”回错误ç 。接ç€è§£æžç”¨æˆ·æä¾›çš„æ ‡å¿—`flags`ï¼Œå¦‚æžœåŒ…å«æœªçŸ¥ä½åˆ™è®°å½•è¦å‘Šå¹¶è¿”回错误ç ã€‚ç„¶åŽæ ¹æ®ç›®å½•文件æè¿°ç¬¦`dirfd`获å–对应的文件æè¿°ç¬¦å¯¹è±¡ï¼Œå¦‚æžœ`dirfd`为`AT_FDCWD`(当å‰å·¥ä½œç›®å½•),则获å–当å‰ä»»åŠ¡æ–‡ä»¶ç³»ç»Ÿçš„å·¥ä½œèŠ‚ç‚¹ï¼›å¦åˆ™ä»Žæ–‡ä»¶æè¿°ç¬¦è¡¨ä¸èŽ·å–。接ç€å°è¯•以åªè¯»æ–¹å¼æ‰“开文件,如果文件ä¸å˜åœ¨æˆ–æ— æ³•æ‰“å¼€åˆ™è¿”å›žç›¸åº”é”™è¯¯ç ,æˆåŠŸæ‰“å¼€åŽèŽ·å–æ–‡ä»¶çš„状æ€ä¿¡æ¯å¹¶å¤åˆ¶åˆ°ç”¨æˆ·æä¾›çš„`buf`缓冲区ä¸ï¼Œå¦‚æžœå¤åˆ¶å¤±è´¥åˆ™è¿”回错误ç `EFAULT`,æˆåŠŸåˆ™è¿”å›ž`SUCCESS`。 + + ```rust + pub fn sys_fstatat(dirfd: usize, path: *const u8, buf: *mut u8, flags: u32) -> isize { + let token = current_user_token(); + let path = match translated_str(token, path) { + Ok(path) => path, + Err(errno) => return errno, + }; + let flags = match FstatatFlags::from_bits(flags) { + Some(flags) => flags, + None => { + warn!("[sys_fstatat] unknown flags"); + return EINVAL; + } + }; + info!( + "[sys_fstatat] dirfd: {}, path: {:?}, flags: {:?}", + dirfd as isize, path, flags, + ); + let task = current_task().unwrap(); + let file_descriptor = match dirfd { + AT_FDCWD => task.fs.lock().working_inode.as_ref().clone(), + fd => { + let fd_table = task.files.lock(); + match fd_table.get_ref(fd) { + Ok(file_descriptor) => file_descriptor.clone(), + Err(errno) => return errno, + } + } + }; + match file_descriptor.open(&path, OpenFlags::O_RDONLY, false) { + Ok(file_descriptor) => { + if copy_to_user(token, &file_descriptor.get_stat(), buf as *mut Stat).is_err() { + log::error!("[sys_fstatat] Failed to copy to {:?}", buf); + return EFAULT; + }; + SUCCESS + } + Err(errno) => errno, + } + } + ``` + +#### è™šæ‹Ÿæ–‡ä»¶ç³»ç»ŸåŠæŽ¥å£ä»£ç åŠè§£é‡Š + +1. ##### **VFS** **接å£å®žçް** + + - **sys_openat** **接å£**:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_openat`函数接收目录æè¿°ç¬¦`dirfd`ã€è·¯å¾„`path`ã€æ‰“å¼€æ ‡å¿—ä½`flags`和文件æƒé™`mode`ä½œä¸ºå‚æ•°ã€‚å®ƒæ ¹æ®`dirfd`é€‰æ‹©è¦æ‰“开的文件æè¿°ç¬¦ï¼Œé€šè¿‡æ–‡ä»¶æè¿°ç¬¦çš„`open`方法å°è¯•打开文件。如果打开æˆåŠŸï¼Œå°†æ–°æ‰“å¼€çš„æ–‡ä»¶æè¿°ç¬¦æ’入到当å‰ä»»åŠ¡çš„æ–‡ä»¶æè¿°ç¬¦è¡¨ä¸ï¼Œå¹¶è¿”回新文件æè¿°ç¬¦çš„æ•´æ•°å€¼ï¼›å¦‚果失败,则返回相应的错误ç 。 + + ```rust + pub fn sys_openat(dirfd: usize, path: *const u8, flags: u32, mode: u32) -> isize { + // 函数体实现 + } + ``` + + - **sys_close** **接å£**:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_close`å‡½æ•°æŽ¥å—æ–‡ä»¶æè¿°ç¬¦`fd`ä½œä¸ºå‚æ•°ï¼Œå°†è¿›ç¨‹æŽ§åˆ¶å—ä¸çš„æ–‡ä»¶æè¿°ç¬¦è¡¨ä¸å¯¹åº”的项设置为`None`,释放资æºã€‚这会导致内层的引用计数类型`Arc`被销æ¯ï¼Œå‡å°‘文件的引用计数,当引用计数为 0 时,文件所å 用的资æºä¼šè¢«è‡ªåŠ¨å›žæ”¶ã€‚ + + ```rust + pub fn sys_close(fd: usize) -> isize { + // 函数体实现 + } + ``` + + - **sys_read** **接å£**:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_read`å‡½æ•°æ ¹æ®æ–‡ä»¶æè¿°ç¬¦`fd`在文件æè¿°ç¬¦è¡¨ä¸æ‰¾åˆ°ç›¸åº”的文件æè¿°ç¬¦å¯¹è±¡ï¼Œç„¶åŽä½¿ç”¨æ–‡ä»¶æè¿°ç¬¦çš„`read_user`方法å°è¯•从文件ä¸è¯»å–æ•°æ®åˆ°ç”¨æˆ·ç©ºé—´çš„缓冲区`buf`ä¸ï¼Œè¯»å–çš„å—节数由`count`指定。 + + ```rust + pub fn sys_read(fd: usize, buf: usize, count: usize) -> isize { + // 函数体实现 + } + ``` + + - **sys_write** **接å£**:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_write`å‡½æ•°æ ¹æ®æ–‡ä»¶æè¿°ç¬¦`fd`在文件æè¿°ç¬¦è¡¨ä¸æ‰¾åˆ°ç›¸åº”的文件æè¿°ç¬¦å¯¹è±¡ï¼Œç„¶åŽä½¿ç”¨æ–‡ä»¶æè¿°ç¬¦çš„`write_user`方法å°è¯•将用户空间缓冲区`buf`ä¸çš„æ•°æ®å†™å…¥åˆ°æ–‡ä»¶ä¸ï¼Œå†™å…¥çš„å—节数由`count` + + 指定。 + + ```rust + pub fn sys_write(fd: usize, buf: usize, count: usize) -> isize { + // 函数体实现 + } + ``` + + - **sys_fstat** **接å£**:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_fstat`å‡½æ•°æ ¹æ®æ–‡ä»¶æè¿°ç¬¦`fd`在文件æè¿°ç¬¦è¡¨ä¸æ‰¾åˆ°ç›¸åº”的文件æè¿°ç¬¦å¯¹è±¡ï¼Œç„¶åŽé€šè¿‡æ–‡ä»¶æè¿°ç¬¦æä¾›çš„æ–¹æ³•èŽ·å–æ–‡ä»¶ä¿¡æ¯ï¼Œå¹¶å°†å…¶å†™å…¥ç¼“冲区`statbuf`ä¸ã€‚ + + ```rust + pub fn sys_fstat(fd: usize, statbuf: *mut u8) -> isize { + // 函数体实现 + } + ``` + + - **sys_mount** **接å£**:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_mount`å‡½æ•°å®žçŽ°äº†æ–‡ä»¶ç³»ç»Ÿçš„æŒ‚è½½åŠŸèƒ½ï¼ŒæŽ¥æ”¶è¦æŒ‚载的文件系统的æºè·¯å¾„æˆ–æ ‡è¯†`source`ã€æŒ‚è½½ç›®æ ‡ä½ç½®`target`ã€æ–‡ä»¶ç³»ç»Ÿç±»åž‹`filesystemtype`ã€æŒ‚è½½é€‰é¡¹å’Œæ ‡å¿—`mountflags`ä»¥åŠæŒ‚载所需的其他数æ®`data`ä½œä¸ºå‚æ•°ã€‚é€šè¿‡è¿™äº›å‚æ•°ï¼Œå‡½æ•°æ‰§è¡ŒæŒ‚è½½æ“ä½œï¼Œå°†æŒ‡å®šçš„æ–‡ä»¶ç³»ç»ŸæŒ‚è½½åˆ°ç›®æ ‡ä½ç½®ã€‚ + + ```rust + pub fn sys_mount(source: *const u8, target: *const u8, filesystemtype: *const u8, mountflags: usize, data: *const u8,) -> isize { + // 函数体实现 + } + ``` + + - **sys_lseek** **接å£**:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_lseek`å‡½æ•°æ ¹æ®æ–‡ä»¶æè¿°ç¬¦`fd`在文件æè¿°ç¬¦è¡¨ä¸æ‰¾åˆ°ç›¸åº”的文件æè¿°ç¬¦å¯¹è±¡ï¼Œç„¶åŽä»¥`whence`为å移的基准,`offset`为åç§»é‡ï¼Œå¯¹æ–‡ä»¶æŒ‡é’ˆè¿›è¡Œå®šä½æ“作,并返回æ“作åŽçš„æ–‡ä»¶æŒ‡é’ˆä½ç½®ã€‚ + + ```rust + pub fn sys_lseek(fd: usize, offset: isize, whence: u32) -> isize { + // 函数体实现 + } + ``` + + - **sys_mkdirat 接å£**:在`os/src/syscall/mod.rs`ä¸ï¼Œ`sys_mkdirat`函数接å—目录文件æè¿°ç¬¦`dirfd`ã€è·¯å¾„`path`和文件æƒé™`mode`ä½œä¸ºå‚æ•°ï¼Œç”¨äºŽåœ¨æŒ‡å®šç›®å½•ä¸‹åˆ›å»ºæ–°çš„ç›®å½•ã€‚å‡½æ•°æ ¹æ®`dirfd`找到相应的目录,然åŽåœ¨è¯¥ç›®å½•下创建å为`path`的新目录,æƒé™ç”±`mode`指定。如果创建æˆåŠŸï¼Œè¿”å›ž`SUCCESS`;如果失败,返回相应的错误ç 。 + +## é‡è¦ç³»ç»Ÿè°ƒç”¨è§£é‡Š + +### sbrk系统调用 + +功能概述: + +> sbrk 系统调用主è¦ç”¨äºŽåЍæ€è°ƒæ•´è¿›ç¨‹çš„å †ç©ºé—´å¤§å°ã€‚它å¯ä»¥æ ¹æ®ä¼ å…¥çš„å‚æ•°ï¼Œå¢žåŠ æˆ–ç¼©å°å †çš„内å˜åŒºåŸŸï¼Œä¸ºè¿›ç¨‹æä¾›çµæ´»çš„内å˜ç®¡ç†åŠŸèƒ½ã€‚ + +å‡½æ•°åŽŸåž‹ä¸Žå‚æ•°å«ä¹‰ï¼š + +> 1.函数原型: +> pub fn sbrk(&mut self, heap_pt: usize, heap_bottom: usize, increment: isize) -> usize +> 2.傿•°å«ä¹‰ï¼š +> self : 所在的地å€ç©ºé—´MemorySet +> heap_pt : 当å‰å †é¡¶æŒ‡é’ˆ +> heap_bottom : å †åº•æŒ‡é’ˆ +> increment : å †ç©ºé—´å¤§å°çš„å˜åŒ–é‡ï¼Œå¯æ£å¯è´Ÿå¯é›¶ +> 返回值 : 改å˜åŽæ–°çš„å †é¡¶æŒ‡é’ˆ + +实现原ç†ä¸Žç›¸å…³å‡½æ•°è°ƒç”¨ï¼š + +> 1.实现ä¾èµ–:sbrk 的实现ä¾èµ–于 MemorySet 接å£ä¸‹çš„ mmap å’Œ munmap 函数。mmap ç”¨äºŽæ‰©å¤§å †ç©ºé—´ï¼Œå®ƒèƒ½å¤Ÿå°†æ–‡ä»¶æˆ–åŒ¿åå†…å˜æ˜ 射到进程的地å€ç©ºé—´ï¼›munmap 用于缩å°å †ç©ºé—´ï¼Œå–æ¶ˆå·²å»ºç«‹çš„å†…å˜æ˜ 射。 +> 2.æ ¸å¿ƒé€»è¾‘ï¼šåœ¨ sbrk 函数ä¸ï¼Œé¦–先判æ–incrementçš„æ£è´Ÿæ€§ã€‚如果increment大于 0ï¼Œä¼šè¿›ä¸€æ¥æ£€æŸ¥æ‰©å¤§åŽçš„å †åœ°å€æ˜¯å¦è¶…过进程地å€ç©ºé—´é™åˆ¶ã€‚若未超过,则调用 mmap å‡½æ•°è¿›è¡Œå †ç©ºé—´çš„æ‰©å¤§æ“ä½œï¼Œå¹¶è¿”å›žæ–°çš„å †é¡¶æŒ‡é’ˆï¼›è‹¥è¶…è¿‡é™åˆ¶ï¼Œåˆ™è¿”å›žåŽŸå †é¡¶æŒ‡é’ˆã€‚å½“incrementå°äºŽ 0 时,会检查缩å°åŽçš„å †åœ°å€æ˜¯å¦å°äºŽå †åº•指针。若ä¸å°äºŽï¼Œåˆ™è°ƒç”¨ munmap å‡½æ•°è¿›è¡Œå †ç©ºé—´çš„ç¼©å°æ“作;若å°äºŽï¼Œåˆ™ä¸è¿›è¡Œç¼©å°æ“ä½œï¼Œç›´æŽ¥è¿”å›žåŽŸå †é¡¶æŒ‡é’ˆã€‚ + +**ä¸€å®šè¦æ³¨æ„下é¢çš„傿•°ä¼ 递:** + + + +è¿™æ ·ä¼ é€’å‚æ•°å¯ä»¥ä¿è¯ä¸è®ºæ˜¯å¢žåŠ è¿˜æ˜¯å‡å°‘å †ç©ºé—´ï¼Œå‡ä¿è¯å †é¡¶åœ¨å †åº•上é¢ï¼Œåˆšå¼€å§‹å°±æ˜¯è¿™é‡Œæ²¡å†™å¯¹ï¼Œå¯¼è‡´å½“increment为负数时出错。 + +### mmap系统调用 + +功能概述: + +> mmap ç³»ç»Ÿè°ƒç”¨ç”¨äºŽå°†æ–‡ä»¶æ˜ å°„åˆ°è¿›ç¨‹çš„åœ°å€ç©ºé—´ä¸ï¼Œå®žçŽ°è¿›ç¨‹å¯¹æ–‡ä»¶çš„ç›´æŽ¥è¯»å†™æ“作,就åƒè¯»å†™å†…å˜ä¸€æ ·ã€‚它还å¯ä»¥åˆ›å»ºåŒ¿åå†…å˜æ˜ å°„ï¼Œç”¨äºŽè¿›ç¨‹é—´å…±äº«å†…å˜æˆ–进程内部的高效内å˜ç®¡ç†ã€‚ + +函数ç¾åä¸Žå‚æ•°å«ä¹‰ï¼š + +> 函数ç¾å:pub fn sys_mmap(start: usize, len: usize, prot: usize, flags: usize, fd: usize, offset: usize) -> isize +> 傿•°å«ä¹‰ +> startï¼šæŒ‡å‘æ¬²æ˜ 射的内å˜èµ·å§‹åœ°å€ï¼Œé€šå¸¸è®¾ä¸º NULL,让系统自动选定地å€ï¼Œæ˜ å°„æˆåŠŸåŽè¿”回该地å€ã€‚ +> len:代表将文件ä¸å¤šå¤§çš„éƒ¨åˆ†æ˜ å°„åˆ°å†…å˜ã€‚ +> protï¼šæ˜ å°„åŒºåŸŸçš„ä¿æŠ¤æ–¹å¼ï¼Œå¦‚å¯è¯»ã€å¯å†™ã€å¯æ‰§è¡Œç‰ã€‚ +> flagsï¼šç”¨äºŽæŒ‡å®šæ˜ å°„åŒºåŸŸçš„ç‰¹æ€§ï¼Œå¦‚ MAP_SHAREDï¼ˆå…±äº«æ˜ å°„ï¼‰ã€MAP_PRIVATEï¼ˆç§æœ‰æ˜ 射)ã€MAP_ANONYMOUSï¼ˆåˆ›å»ºåŒ¿åæ˜ 射)ç‰ã€‚ +> fdï¼šè¦æ˜ 射到内å˜ä¸çš„æ–‡ä»¶æè¿°ç¬¦ï¼Œä½¿ç”¨åŒ¿åå†…å˜æ˜ 射时设为 -1。 +> offsetï¼šæ–‡ä»¶æ˜ å°„çš„åç§»é‡ï¼Œé€šå¸¸è®¾ç½®ä¸º 0,必须是分页大å°çš„æ•´æ•°å€ã€‚offsetï¼šæ–‡ä»¶æ˜ å°„çš„åç§»é‡ï¼Œé€šå¸¸è®¾ç½®ä¸º 0,必须是分页大å°çš„æ•´æ•°å€ã€‚ + +实现过程与æ¥éª¤ï¼š + +> 1.找到最åŽä¸€æ¬¡ mmap æ˜ å°„åŒºåŸŸï¼šé€šè¿‡æŸ¥æ‰¾è¿›ç¨‹æ‰€ç”³è¯·çš„ç”¨æˆ·åœ°å€ç©ºé—´ä¸æœ€åŽä¸€ä¸ªç¬¦åˆè¦æ±‚çš„ vm_area_struct 结构体,获å–å…¶ä¸‹æ ‡ï¼Œè¯¥ç»“æž„ä½“ç”¨äºŽæè¿°è¿›ç¨‹åœ°å€ç©ºé—´ä¸çš„一个区域,包å«èµ·å§‹å’Œç»“æŸåœ°å€ç‰ä¿¡æ¯ã€‚ +> 2.èŽ·å–æ˜ 射区域的起始地å€ï¼šæ ¹æ® flags 傿•°åˆ¤æ–是å¦è®¾ç½®äº† MAP_FIXEDã€‚å¦‚æžœè®¾ç½®äº†ï¼Œä¼šå…ˆå–æ¶ˆå·²å˜åœ¨çš„æ˜ 射,然åŽä½¿ç”¨ç”¨æˆ·æŒ‡å®šçš„ start 地å€ï¼›å¦‚æžœæœªè®¾ç½®ï¼Œåˆ™æ ¹æ®æœ€åŽä¸€æ¬¡ mmap æ˜ å°„åŒºåŸŸçš„æƒ…å†µç¡®å®šèµ·å§‹åœ°å€ã€‚如果设置了 MAP_PRIVATE 或 MAP_ANONYMOUS,且相关æ¡ä»¶æ»¡è¶³ï¼Œä¼šå°†æ–°æ˜ 射区域与最åŽä¸€æ¬¡ mmap æ˜ å°„åŒºåŸŸåˆå¹¶ï¼›å¦åˆ™ï¼Œå°†æœ€åŽä¸€æ¬¡ mmap æ˜ å°„åŒºåŸŸçš„æœ«å°¾ä½œä¸ºæ–°æ˜ å°„åŒºåŸŸçš„èµ·å§‹åœ°å€ã€‚最åŽï¼Œæ ¹æ®ç”¨æˆ·æŒ‡å®šçš„ len 傿•°ç¡®å®šæ–°æ˜ 射区域的末尾地å€ã€‚ +> 3.åˆ¤æ–æ˜¯å¦æ˜¯æ–‡ä»¶æ˜ 射并处ç†ï¼šå¦‚æžœ flags 傿•°ä¸ä¸åŒ…å« MAP_ANONYMOUSï¼Œè¯´æ˜Žæ˜¯æ–‡ä»¶æ˜ å°„ã€‚æ¤æ—¶ï¼Œä¼šèŽ·å– fd_tableï¼Œå¹¶æ ¹æ® fd 傿•°æ‰¾åˆ°å¯¹åº”的文件æè¿°ç¬¦ï¼Œæ£€æŸ¥æ–‡ä»¶çš„å¯è¯»æ€§ã€‚如果å¯è¯»ï¼Œè®¾ç½®æ–‡ä»¶åç§»é‡å¹¶å°†ç›¸å…³ä¿¡æ¯ç½®å…¥æ–°åˆ›å»ºçš„ MapArea 结构体ä¸ã€‚ +> 4.å°†æ–°æ˜ å°„åŒºåŸŸåŠ å…¥åˆ° vector ä¸ï¼šå°†æ–°åˆ›å»ºçš„ MapArea ç»“æž„ä½“åŠ å…¥åˆ°å…ˆå‰çš„ vector ä¸ï¼ŒåŒæ—¶ä¿æŒ vector çš„æœ‰åºæ€§ï¼Œç¡®ä¿æ˜ 射区域按照地å€é¡ºåºæŽ’列。 + +### sys_getpid系统调用 + +1.功能概述 + +> sys_getpid 是一个系统调用函数,其主è¦åŠŸèƒ½æ˜¯èŽ·å–当å‰è¿›ç¨‹çš„进程 ID(PID)。在 NPUcore ä¸ï¼Œæ¯ä¸ªè¿›ç¨‹éƒ½æœ‰å”¯ä¸€çš„ PIDï¼Œç”±å†…æ ¸åˆ†é…ä¸”ä¸ºæ£æ•´æ•°ï¼Œè¿™ä¸ª PID å¯ç”¨äºŽå”¯ä¸€æ ‡è¯†è¿›ç¨‹ã€‚ + +2.执行过程 + +> 该函数的执行过程相对简å•ï¼Œä¸»è¦æ˜¯ä»Žå†…æ ¸ä¸æ£€ç´¢å½“å‰è¿›ç¨‹çš„ ID 并返回。 + +3.返回值 + +> 若函数æˆåŠŸæ‰§è¡Œï¼Œå°†è¿”å›žå½“å‰è¿›ç¨‹çš„ PID。 +> 若执行失败,则返回 - 1,表示出现错误。 + +4.应用场景和æ„义 + +> 获å–进程 ID 是进程间通信和控制的基础。例如,父进程通过 fork () 函数创建å进程åŽï¼Œå进程å¯ä»¥è°ƒç”¨ getpid () 获å–自己的 PID,进而通过进程间通信方å¼ä¸Žçˆ¶è¿›ç¨‹äº¤äº’。 +> 还å¯ä»¥åˆ©ç”¨è¿›ç¨‹ ID 呿Œ‡å®šè¿›ç¨‹å‘é€ä¿¡å·ï¼Œå®žçŽ°å¯¹è¿›ç¨‹çš„æŽ§åˆ¶ã€‚ä¾‹å¦‚ï¼Œé€šè¿‡ kill () å‡½æ•°ç»“åˆ PID å¯ä»¥å‘特定进程å‘é€ä¿¡å·æ¥æŽ§åˆ¶å…¶è¡Œä¸ºã€‚ + +process.rs文件的第264è¡Œæ·»åŠ ç›¸åº”çš„å‡½æ•°ä½“ï¼š + + +### getrusage系统调用 + +1.功能 + +> getrusage 系统调用的主è¦åŠŸèƒ½æ˜¯èŽ·å–进程的相关资æºä¿¡æ¯ã€‚这些资æºä¿¡æ¯åŒ…括用户开销时间ã€ç³»ç»Ÿå¼€é”€æ—¶é—´ã€æŽ¥æ”¶çš„ä¿¡å·é‡ç‰ã€‚ + +2.相关结构体 + +> Rusage 结构体定义了获å–资æºä¿¡æ¯çš„ç›¸å…³å—æ®µã€‚ +> ru_utime:用于记录用户 CPU 时间。 +> ru_stime:用于记录系统 CPU 时间。 +> 还有多个未实现(NOT IMPLEMENTEDï¼‰çš„å—æ®µï¼Œå¦‚ru_maxrss(最大驻留集大å°ï¼‰ã€ru_ixrss(共享内å˜å¤§å°ç§¯åˆ†ï¼‰ç‰ï¼Œè¿™äº›å—æ®µç›®å‰æ²¡æœ‰å…·ä½“实现,但代表了å¯ä»¥èŽ·å–的潜在资æºä¿¡æ¯ã€‚ + +3.傿•° + +> who: +> 当who为 0 时,表示获å–当å‰è¿›ç¨‹çš„资æºä¿¡æ¯ã€‚ +> 当who为 - 1 时,表示获å–å进程的资æºä¿¡æ¯ï¼Œä½†è¿™éƒ¨åˆ†å¯ä»¥ä¸å®žçŽ°ã€‚ +> usage:这是一个指å‘å˜æ”¾èµ„æºä½¿ç”¨ä¿¡æ¯çš„ Rusage 结构体指针,用于å˜å‚¨èŽ·å–到的资æºä¿¡æ¯ã€‚ + +4.æ„义和用途 + +> 通过 getrusage 系统调用,æ“作系统å¯ä»¥æ–¹ä¾¿åœ°èŽ·å–进程在è¿è¡Œè¿‡ç¨‹ä¸çš„å„ç§èµ„æºæ¶ˆè€—情况。这些信æ¯å¯¹äºŽç³»ç»Ÿæ€§èƒ½åˆ†æžã€èµ„æºç®¡ç†å’Œä¼˜åŒ–ç‰æ–¹é¢å…·æœ‰é‡è¦æ„义。例如,通过了解用户 CPU 时间和系统 CPU 时间,å¯ä»¥åˆ†æžè¿›ç¨‹åœ¨ç”¨æˆ·æ€å’Œå†…æ ¸æ€çš„è¿è¡Œæ•ˆçŽ‡ï¼›é€šè¿‡æŽ¥æ”¶çš„ä¿¡å·é‡ç‰ä¿¡æ¯ï¼Œå¯ä»¥æŽŒæ¡è¿›ç¨‹çš„外部交互情况ç‰ã€‚ + +补充os/src/syscall/process.rs文件内第1017行处的getrusage系统调用函数体: + + + +### fork与exec系统调用 + +一ã€fork 系统调用 +1.作用 + +> 在 NPUcore ä¸ï¼Œé™¤äº†å†…æ ¸åŠ è½½çš„ç¬¬ä¸€ä¸ªåˆå§‹è¿›ç¨‹ initproc 外,其余所有进程å‡ç”±åˆå§‹è¿›ç¨‹ initproc 通过 fork 系统调用创建。也就是说,fork 用于创建新的进程,新进程是调用 fork 的进程(父进程)的副本。 + +2.调用时机 + +> 它在创建新进程的过程ä¸è¢«è°ƒç”¨ï¼Œä½äºŽåˆå§‹è¿›ç¨‹ initproc å·²ç»åˆ›å»ºä¹‹åŽï¼Œæ˜¯åˆ›å»ºæ–°è¿›ç¨‹çš„ç¬¬äºŒæ¥æ“作。 + +3.åŽŸç† + +> 调用 fork åŽï¼Œæ–°è¿›ç¨‹ä¼šå¤åˆ¶çˆ¶è¿›ç¨‹çš„大部分资æºï¼ŒåŒ…括内å˜ç©ºé—´ã€æ‰“开的文件æè¿°ç¬¦ç‰ã€‚æ–°è¿›ç¨‹å’Œçˆ¶è¿›ç¨‹å‡ ä¹Žæ‹¥æœ‰ç›¸åŒçš„内容,但它们有ä¸åŒçš„è¿›ç¨‹æ ‡è¯†ç¬¦ï¼ˆPID)。 + +4.与其他æ“作的关系 + +> 新进程创建åŽï¼Œè¿˜éœ€è¦è¿›ä¸€æ¥çš„æ“ä½œæ‰èƒ½ä½¿å…¶ç‹¬ç«‹è¿è¡Œã€‚å› ä¸ºæ–°è¿›ç¨‹æ¤æ—¶åªæ˜¯çˆ¶è¿›ç¨‹çš„一个副本,并没有自己独立的程åºä»£ç å’Œæ•°æ®æ–‡ä»¶ï¼Œè¿™å°±éœ€è¦åŽç»çš„ exec 系统调用。 + +二ã€exec 系统调用 +1.作用 + +> 在调用 fork 创建新进程åŽï¼Œexec ç³»ç»Ÿè°ƒç”¨ç”¨äºŽè®©æ–°è¿›ç¨‹åŠ è½½ç‹¬ç«‹çš„ç¨‹åºä»£ç å’Œæ•°æ®æ–‡ä»¶ã€‚å®ƒä¼šç”¨æ–°çš„ç¨‹åºæ›¿æ¢å½“å‰è¿›ç¨‹çš„ä»£ç æ®µã€æ•°æ®æ®µç‰å†…容,使新进程开始执行新的程åºã€‚ + +2.调用时机 + +> 在通过 fork 创建新进程之åŽï¼Œæ–°è¿›ç¨‹éœ€è¦åŠ è½½è‡ªå·±çš„ç¨‹åºä»£ç å’Œæ•°æ®æ—¶è°ƒç”¨ exec 系统调用。 + +3.åŽŸç† + +> exec ä¼šåŠ è½½æŒ‡å®šçš„å¯æ‰§è¡Œæ–‡ä»¶ï¼Œå¹¶é‡æ–°åˆå§‹åŒ–进程的执行环境。它ä¸ä¼šåˆ›å»ºæ–°çš„进程,而是改å˜çŽ°æœ‰è¿›ç¨‹çš„æ‰§è¡Œè·¯å¾„ï¼Œä½¿å…¶å¼€å§‹æ‰§è¡Œæ–°çš„ç¨‹åºã€‚ + +4.与其他æ“作的关系 + +> 与 fork 系统调用紧密相关,fork 负责创建新进程,而 exec è´Ÿè´£è®©æ–°è¿›ç¨‹åŠ è½½å¹¶æ‰§è¡Œæ–°çš„ç¨‹åºã€‚二者结åˆå®žçŽ°äº†ä»ŽçŽ°æœ‰è¿›ç¨‹åˆ›å»ºæ–°è¿›ç¨‹å¹¶ä½¿å…¶æ‰§è¡Œç‰¹å®šç¨‹åºçš„完整过程。 + +补充os/src/syscall/process.rs文件内第487行处的sys_fork系统调用函数体: + + + +补充os/src/syscall/process.rs文件内第495行处的sys_exevce系统调用函数体: + +> 这部分较多,就ä¸å†æˆªå›¾å±•示。 + +### clone系统调用 + +1.与 fork 的关系åŠä¼˜åŠ¿ + +> fork 系统调用是 clone ç³»ç»Ÿè°ƒç”¨åœ¨ç‰¹å®šå‚æ•°è®¾ç½®ä¸‹çš„简化形å¼ã€‚clone 系统调用相较于 forkï¼Œå…¶ä¼˜åŠ¿æ˜¾è‘—ã€‚å®ƒæ”¯æŒæ›´å¤šå‚数,这使得它能够在更广泛的场景ä¸å‘挥作用,æä¾›äº†æ›´å¼ºå¤§çš„进程创建与管ç†èƒ½åŠ›ã€‚ + +2.实现多线程åŠè¿›ç¨‹ç®¡ç†ä¼˜åŠ¿ + +> 1.多线程实现机制: +> 利用 clone ç³»ç»Ÿè°ƒç”¨ï¼Œå†…æ ¸æ— éœ€å•ç‹¬æž„å»ºå¤æ‚的多线程机制å³å¯å®žçް “多线程†功能。当执行 clone 系统调用时,会创建一个新的 TCB(任务控制å—)。 +> 线程与进程的本质区别在于所关è”的数æ®ã€‚若新创建的 TCB 所指å‘的数æ®ä¸Žå…¶ä»–实体共享内å˜ç©ºé—´å’Œä¿¡å·ï¼Œé‚£ä¹ˆå®ƒå°±è¢«è§†ä¸ºä¸€ä¸ªçº¿ç¨‹ï¼›å之,则为一个独立的进程。 +> 2.å¯¹å†…æ ¸ç®¡ç†çš„优化: +> è¿™ç§æ–¹å¼ç®€åŒ–äº†å†…æ ¸ç®¡ç†æ‰§è¡Œæ€è¿›ç¨‹çš„夿‚度,将进程(或线程)组织æˆç®€å•çš„æ ‘çŠ¶ç»“æž„ï¼Œä¾¿äºŽå†…æ ¸è¿›è¡Œé«˜æ•ˆçš„ç®¡ç†ä¸Žè°ƒåº¦ã€‚ +> å®ƒä¸¥æ ¼é™åˆ¶äº†çº¿ç¨‹åˆ›å»ºçš„范围,åªèƒ½åˆ›å»ºä¸Žå½“å‰è¿›ç¨‹å…±äº«ä¸Šä¸‹æ–‡çš„线程,有效防æ¢äº†è¿œç¨‹çº¿ç¨‹çš„创建,从而更好地实现了资æºéš”离。这确ä¿äº†åŒä¸€è¿›ç¨‹å†…的资æºå…±äº«é«˜æ•ˆä¸”å®‰å…¨ï¼ŒåŒæ—¶é¿å…了ä¸åŒè¿›ç¨‹é—´èµ„æºçš„ä¸å½“交互,增强了系统的稳定性和安全性。 + +3.clone ç³»ç»Ÿè°ƒç”¨å‚æ•°è§£é‡Šï¼š +clone 系统调用在 NPUcore ä¸çš„函数ç¾å为: + +```rust +pub fn sys_clone(flags: u32,stack: *const u8,ptid: *mut u32,tls: usize,ctid: *mut u32) -> isize +``` + +1.flags 傿•° + +> 结构组æˆï¼šflags 傿•°ç»¼åˆäº†å…‹éš†æ ‡å¿— CloneFlags å’Œå进程结æŸä¿¡å· exit_signal 两部分内容。 + +2.CloneFlags å…·ä½“æ ‡å¿—å«ä¹‰ï¼š + +> 1.CLONE_VM:用于控制父å进程间内å˜ç©ºé—´çš„共享模å¼ã€‚若设置,父å进程共享åŒä¸€å†…å˜ç©ºé—´ï¼Œä¸€æ–¹å¯¹å†…å˜çš„写æ“作对å¦ä¸€æ–¹å¯è§ï¼›è‹¥æœªè®¾ç½®ï¼Œå进程拥有父进程内å˜ç©ºé—´çš„独立副本。 +> 2.CLONE_FS:决定父å进程是å¦å…±äº«æ–‡ä»¶ç³»ç»Ÿç›¸å…³è®¾ç½®ï¼ŒåŒ…æ‹¬æ ¹ç›®å½•ã€å½“å‰ç›®å½•åŠæ–‡ä»¶æŽ©ç (umask)ç‰ã€‚ +> 3.CLONE_FILES:确定父å进程是å¦å…±äº«æ–‡ä»¶æè¿°ç¬¦è¡¨ï¼Œå½±å“进程对文件的æ“作æƒé™å’Œèµ„æºå…±äº«æ–¹å¼ã€‚ +> 4.CLONE_SIGHAND:控制父å进程是å¦å…±äº«ä¿¡å·å¤„ç†è¡¨ï¼Œå†³å®šçˆ¶å进程对信å·çš„å“åº”å’Œå¤„ç†æ–¹å¼æ˜¯å¦ç›¸åŒã€‚ +> 5.CLONE_THREADï¼šè¯¥æ ‡å¿—å†³å®šæ–°åˆ›å»ºçš„å®žä½“æ˜¯çº¿ç¨‹è¿˜æ˜¯ç‹¬ç«‹è¿›ç¨‹ï¼ˆä»Žçº¿ç¨‹ç»„è§’åº¦ï¼‰ã€‚è‹¥è®¾ç½®ï¼Œæ–°å®žä½“è¢«è§†ä¸ºçˆ¶è¿›ç¨‹çš„çº¿ç¨‹ï¼Œä¸Žçˆ¶è¿›ç¨‹å…±äº«çº¿ç¨‹ç»„ ID(TGID);若未设置,新实体æˆä¸ºç‹¬ç«‹çº¿ç¨‹ç»„,其 TGID ç‰äºŽè‡ªèº«çº¿ç¨‹ ID(TID)。 +> 6.exit_signal å«ä¹‰ï¼šç”¨äºŽæŒ‡å®šå进程退出时å‘父进程å‘é€çš„ä¿¡å·ã€‚当 flags 的低å—èŠ‚ä¸æŒ‡å®šçš„ä¿¡å·ä¸æ˜¯SIGCHLD时,父进程在使用wait()ç‰å¾…å进程退出时需指定__WALL或WCLONE选项。若未指定信å·ï¼ˆå³å€¼ä¸º 0),å进程退出åŽä¸ä¼šå‘父进程å‘é€ä¿¡å·ã€‚ + +3.stack 傿•° + +> stack 傿•°çš„主è¦ä½œç”¨æ˜¯æŒ‡å®šåè¿›ç¨‹ä½¿ç”¨çš„æ ˆçš„ä½ç½®ã€‚由于å进程和调用进程在内å˜ç®¡ç†ä¸Šå˜åœ¨ç‰¹æ®Šå…³ç³»ï¼ˆå¯èƒ½å…±äº«å†…å˜ï¼‰ï¼Œå进程ä¸èƒ½ç›´æŽ¥ä½¿ç”¨è°ƒç”¨è¿›ç¨‹çš„æ ˆã€‚å› æ¤ï¼Œè°ƒç”¨è¿›ç¨‹å¿…é¡»æå‰ä¸ºåè¿›ç¨‹åˆ†é…æ ˆå†…å˜ç©ºé—´ï¼Œå¹¶å°†æŒ‡å‘该空间起始ä½ç½®ï¼ˆæ ˆé¡¶ï¼‰çš„æŒ‡é’ˆä¼ 递给 clone () å‡½æ•°ã€‚éœ€è¦æ³¨æ„的是,处ç†å™¨çš„æ ˆç”Ÿé•¿æ–¹å‘通常是å‘下的,å³ä»Žé«˜åœ°å€å‘低地å€ç”Ÿé•¿ï¼Œæ‰€ä»¥ stack 傿•°æŒ‡å‘的是为åè¿›ç¨‹æ ˆåˆ†é…的内å˜ç©ºé—´çš„æœ€é«˜åœ°å€ã€‚然而,clone () 函数本身并没有æä¾›ä¸€ç§ç›´æŽ¥çš„æ–¹å¼è®©è°ƒç”¨è€…å‘ŠçŸ¥å†…æ ¸æ‰€åˆ†é…æ ˆç©ºé—´çš„大å°ã€‚ + +4.ptid å’Œ ctid 傿•° + +> 1.与特定 CloneFlags æ ‡å¿—çš„å…³è”ï¼šè¿™ä¸¤ä¸ªå‚æ•°ä¸Ž CloneFlags ä¸çš„CLONE_CHILD_SETTIDå’ŒCLONE_PARENT_SETTIDæ ‡å¿—å¯†åˆ‡ç›¸å…³ã€‚ +> 2.傿•°åŠŸèƒ½ï¼šCLONE_CHILD_SETTIDæ ‡å¿—ä½¿å¾—åœ¨ ctid 所指å‘的内å˜ä½ç½®ä¿å˜æ–°åˆ›å»ºå进程(或线程)的线程 ID。æ¤ä¿å˜æ“作在 clone 调用返回控制到å进程的用户空间之å‰å®Œæˆï¼Œä½†åœ¨ clone 调用返回父进程之å‰ï¼Œè¯¥ä¿å˜æ“ä½œçš„å®Œæˆæƒ…况与CLONE_VMæ ‡å¿—ç›¸å…³ï¼ˆå¯èƒ½æœªå®Œæˆï¼‰ã€‚CLONE_PARENT_SETTIDæ ‡å¿—åˆ™åœ¨çˆ¶è¿›ç¨‹ä¸ï¼Œå°†æ–°åˆ›å»ºå进程(或线程)的线程 ID ä¿å˜åˆ° ptid 所指å‘的内å˜ä½ç½®ï¼Œä¿å˜æ“作在 clone 调用将控制返回给用户空间之å‰å®Œæˆã€‚ + +5.tls 傿•° + +> tls 傿•°ä¸Ž CloneFlags ä¸çš„CLONE_SETTLSæ ‡å¿—ç›¸å…³ã€‚CLONE_SETTLSæ ‡å¿—ç”¨äºŽå°†çº¿ç¨‹æœ¬åœ°å˜å‚¨ï¼ˆThread Local Storage,TLS)的值ä¿å˜åˆ° tls å—æ®µä¸ã€‚TLS å…许æ¯ä¸ªçº¿ç¨‹æ‹¥æœ‰ç‹¬ç«‹çš„æ•°æ®å‰¯æœ¬ï¼Œè¿™äº›æ•°æ®åœ¨æ•´ä¸ªçº¿ç¨‹ç”Ÿå‘½å‘¨æœŸå†…都å¯ä»¥è¢«è®¿é—®ï¼Œå¹¶ä¸”对于æ¯ä¸ªçº¿ç¨‹éƒ½æ˜¯ç‹¬ç«‹çš„,ä¸å—其他线程的影å“ã€‚é€šè¿‡è¿™ä¸ªå‚æ•°ï¼Œå¯ä»¥ä¸ºæ–°åˆ›å»ºçš„å进程(或线程)设置特定的 TLS 值,从而实现线程级别的数æ®éš”离和共享特定于线程的数æ®ã€‚例如,在多线程编程ä¸ï¼Œä¸åŒçº¿ç¨‹å¯èƒ½éœ€è¦ä½¿ç”¨ä¸åŒçš„æ•°æ®åº“连接对象,这些对象å¯ä»¥å˜å‚¨åœ¨ TLS ä¸ï¼Œä»¥ç¡®ä¿æ¯ä¸ªçº¿ç¨‹éƒ½èƒ½ç‹¬ç«‹åœ°è®¿é—®å’Œç®¡ç†è‡ªå·±çš„æ•°æ®åº“连接。 + +补充os/src/syscall/process.rs文件内第442行处的sys_clone系统调用函数体: + + + +### 文件mmap系统调用的MAP_PRIVATE + + + +在os/src/mm/memory_set.rs:883处补全mmap系统调用: + + + +### open系统调用 + + + +在os/src/syscall/fs.rs:663处补全openat系统调用: + + + +### fstat系统调用 + + + +在os/src/syscall/fs.rs:523/527处补全fstat/fstatat系统调用: + + + + + + + +### linkat系统调用 + + + +在os/src/syscall/fs.rs:814处补全sys_linkat系统调用: + + + + +### unlinkat系统调用 + + + +在os/src/syscall/fs.rs:815处补全sys_unlinkat系统调用: + + + + +### read系统调用与virtioå—è®¾å¤‡é©±åŠ¨æ˜ å°„ + + + +å‚照文件os/src/drivers/block/virtio_blk.rsä¸çš„write函数完æˆread()函数: + + + \ No newline at end of file