0%

Rustlings 总结

接触训练营之前,一直在写C++,Rust名声在外,因此接触Rust更像是换一种视角来观察C++的好方法。
为了快速上手Rustlings,我先花了几十分钟粗略阅读了一遍菜鸟教程,对Rust的语法和基本概念有了基本的了解。
为了快速上手Rustlings,我先花了几十分钟浏览了一下菜鸟教程,对Rust的语法和基本概念有了一个初步的认识。Rustlings是了解一门语言的极佳途径,它通过练习题的形式,使我深入接触到Rust的各个方面,包括其核心设计理念,以及C++缺少的、非常重要的功能——例如Cargo包管理器等Rust相关生态。如果当初我在学习C++时也能有这样的资源,那该有多好!
当然,作为一门系统级编程语言,Rust对程序员的要求非常高。相比之下,Rust的入门难度确实和C++不在一个层次。然而,在Rust的发展过程中可以明显看到它吸取了C++的一些设计理念,这也让这两门优秀的语言在不断借鉴中相互提升。

第一阶段总结

我的rust入门

学了很久编程,但是终究不是科班出身,感觉对很多问题理解还不是很到位,本科毕业的暑假,被老师叫去提前进组,基础有点薄弱,于是也开始学起了操作系统,恰巧看到了rcore这个教程,可惜时间有限没有看太多,这次训练营算是重新跟着复习一遍。

rustlings的题目并不是很难,很快就刷完了,感觉难点主要在rust语法的不熟悉。在此之前,听说过很多次rust是新时代的c语言,rust重写内核,rust重写一切….真正学习来才发现rust相较于其他语言的优势。

效率

rust与c语言一样,都是偏向于底层开发,能够生成裸机直接运行的机器码,执行效率高(网上有许多rust嵌入式教程,或许后面应该再学学这方面)。

在开发效率方面,相比于c语言,rust的现代化语法,真的要舒服很多。自我感觉rust有很多用起来很爽的部分,比如说模式匹配。相比于c语言,rust也有现代化的包管理工具cargo。

安全

在学习rust之前,看到很多博主说rust安全,用了之后才一点一点感悟到。rust的所有权机制,还有生命周期的概念,避免了一系列问题。

现代

现代化的编程语言概念,现代化的包管理工具,舒服!

rCore 二阶段总结报告

遇到的问题

因为有Rust基础,所以在第一阶段大概花了三四个小时完成了Rustlings。但是是第一次参加rCore训练营,所以在进入第二阶段后,感觉到了进展十分缓慢,在每个Lab中都或多或少被一些问题所困扰。

得到的收获

第二阶段的几个Lab相互衔接,在完成一个个Lab的过程中能感觉到对于操作系统的逐渐了解和深入,做完了后面的部分回过头来看前面的部分有时候还会有新的理解。在熟读文档和完成实验的互相作用下,我相信自己的能力得到了一定的提升。但是有些实验虽然通过了,但是仔细一想还是有侥幸的部分,在以后可能需要小心注意。

第一阶段报告

在加入这个课程的时候已经学习 rust 小半年了,rustling 原项目也是完整的写过一次,所以第一阶段很快就通过了。第一阶段的 rustling 是魔改版,确实让我学到了很多我之前不太了解的东西。

第二阶段报告

这个阶段的学习直接戳中我的知识盲区,汇编、操作系统这些我是一点不会。

困难

应该说都是困难?

卡我最久的应该是内存分页和文件系统了,这种一层一层抽象上来的我看的是眼花缭乱,物理结构和程序结构的转换,在此基础上的再一层抽象在当时给了我很大的阅读困难。

收获

首先这几次学习解开了我之前的误区和疑惑,特别是系统调用这一方面,我之前都不知道原来特权级这个概念,不知道为什么汇编需要在操作系统支持下运行。现在我知道很多操作是需要系统提供接口,需要用户态和内核态的切换。

这是我第二次写这个体量的 rust 项目,编写过程中经常写出很多哭笑不得的代码,比如在持有锁的前提下再次请求锁导致死锁,在单次借用后不 drop 再次借用导致 panic。
通过这次的学习,我的 rust 编程能力无疑得到了提升,我可以明显感觉到我的代码可读性比之前好不少,对于写注释也更加得心应手。

在学习过程中与群友的讨论中,我也对其中的汇编代码理解更深,通过我在本机的多次测试,也加深了我对任务切换、特权级跳转的认识。

这五个 lab 的代码难度确实不是很高,主要难点都在于理解 os 的组织形式,没有搞清楚 os 的其他代码就难以下手,但是理清思路之后写起来就没有什么难度。

Rust OS 一阶段学习总结

@FinishTime: 2024-09-19 00:35:51

个人背景概述

我是一名软件工程专业的大三本科生,曾参与过 2023 年秋冬季训练营和 2024 年春夏季训练营。并且在 2024 季春夏训练营中,取得了通过的成绩。
今年的秋冬季训练营,我想冲一冲优秀,多做一些项目,多为国内操作系统和开源做出贡献。

今年一阶段学习时间表

  • 2024-09-18 大约 3.5 小时,重新完成 rustlings 的官方基础习题(前 94 题)。之后,又用了大约 2 小时,完成了后续的习题(95-110)。

一阶段学习内容概述

我按照“rust 语言圣经”上的讲解顺序,复习之前的知识点。
由于我在那段时间之前,在参加 InfiniTensor 的 AI 训练营,所以 rust 的基础语法等根本没有落下,这使得我在完成 rustlings 的习题时,几乎没有遇到什么问题。

只有到后续的习题中,我遇到了一些问题,主要是和 智能指针 有关的内容。这些部分我一直不是很理解的。但是因为我的经验,我还是能写出代码的。

总结

在第一阶段的学习中,我巩固了我所掌握的 rust 基础,我更是深深的意识到:Talk is cheap, show me the code!。实践是最好的老师!

Rust rCore 二阶段学习总结

@FinishTime: 2024-10-15 18:44:32

二阶段学习时间表

  • 2024-10-08 开始实验,轻车熟路,一天晚上完事了大部分的 ch3。
  • 2024-10-09 凌晨 ch3 debug 完毕,下午进行提交完毕。
  • 2024-10-09 晚上 ch4 提交完毕。
  • 2024-10-11 ch5 提交完毕。
  • 2024-10-13 ch6 提交完毕。
  • 2024-10-15 ch8 提交完毕。撰写报告完毕。

问题复盘

通过上面的学习时间表可以看出,我虽然是第二次做大实验,但仍然每一部分都需要 1 到 2 天时间。虽然不是将大段时间全部投入,但可能也是比较慢了。
以下是我实验过程中的问题复盘。

ch3: 本地测例初始化问题

在 ch3 里,我遇到了两个问题,第一个是本地测例的初始化问题。

由于我是第二次参与训练营,所以在实验时,我就直接去看指导书的习题部分,在尝试开始实现时,在 rust-anaylzer 的使用上时发生了错误,插件因为找不到某些依赖库,拒绝提供服务。

我去查看了插件的报错信息,发现找不到 user 目录。而我在源代码仓库,也确实没看到源代码里有 user 目录。后续,我在自行尝试解决无果后,去微信群问了助教。得到的回答是 看文档。然后我去重新看了文档,找到了一个下载 user 的方法。这个问题是由于我的粗心导致的。

ch3: 时间初始化问题

ch3 的第二个问题是,os 时间初始化问题。

在我实现的 os 里,在时间初始化,采用的是 直接在任务加载时便初始化为当前系统时间。这显然是错误的。但它的报错并不友好。

此问题的表现为:在直接指定 BASE=1 执行测试用例时,能够通过测试用例。指定 BASE=0 时,也能够通过测试。但指定 BASE=2 时,竟然不能通过测试!?同时,这种情况下,qemu 会出现“卡死”,让人一直等下去。

我通过细细阅读报错,发现 qemu 卡死是因为有一个用户测例 panic 导致的。经过分析的测例执行逻辑为:

1
2
3
我分析,ch3里,qemu在跑测试用例的时候,qemu的退出机制是,当全部测试用例成功时,才会退出。

如果有测例没过,他会接着执行别的测试用例,但最后全部测试用例执行完后,就不会退出了,还没有信息提示。

能够定位位置,之后的工作就要简单多了。我发现了问题所在,然后将时间改为 Option 类型,以 None 来初始化,在为某任务进行 sys_call 计数时进行判断,如果为 None,则进行初始化。这样,问题就解决了。

后续,我看到交流群里有个同学,和我遇到了一样的问题,于是,我也帮助了他。

ch6: 又一次卡了一小点

在 ch6 时,平心而论,要求实现的逻辑并不是很复杂,只是需要层层的传递,最后由“easy-fs”进行实际干活即可。但我再次遇到了一个极为恶心的问题。

在春夏季训练营,我曾经遇到了“File is shorter than the first ELf header part”的问题,翻译过来就是,文件比文件描述符还短。我发现,只有 ch5_spawn0,也就是 helloworld 的测例出现了这个问题。

而这一次,我又遇到了这个问题。然后,我通过微信群的聊天记录,找到了当时一位热心同学给我的解答,即,此情况可能是由于 rust 的智能优化导致的,只需要把一个位置,由 [u8; 512] 改为一个 Vec 即可。

还好我留有聊天记录,再次感谢当时的那位同学!

ch8: 系统时间系统调用未实现

来到了 ch8,我没有看到指导书文档里,写着的 “除 sys_get_time 以外”,所以,我就没有合并我之前的代码。但问题是,在我实现了 ch8 的内容后,进行测例,有两个始终过不去,就是那两个死锁相关的。而且,它没有报错提醒。这使我很懵,是不是我的银行家算法写的有问题?

在一次又一次地尝试为银行家算法进行 debug 后,我发现,好像我的算法没问题啊。于是,我又一次详细阅读测试代码,发现:这里面有个sleep(500),这是调了哪个 sys_call?我查了,发现是获得系统时间的那个。但我没有合并之前的代码,导致其会进入死循环。由此,我才改好了问题。

总结

第二次来 rCore,感觉熟能生巧了一些,之前很多不太理解的部分,已经慢慢构不成威胁了。果然,实践能够带动理论!但我也因为自己的粗心,导致了一些不必要的麻烦。这是需要我进行反省的。

展望

这一次的三阶段,将会涉及到“组件化”。希望我能尽快完成相关内容,及早进入后续项目内容的学习!希望能够冲一冲优秀!

总结

在这之前做过官方的rustlings的练习,重做了前100题,只用了两天中的空闲时间,对于基础的语法和类型系统的相关性质已经相当熟悉了。
与本次练习不同的是增加了数据结构与算法相关的部分,虽然使用标准测试的方式进行代码审查会让数据结构的实现不够严谨,但是通过给出的工具函数进行实现也大致复习了一下数据结构的相关知识,熟悉了一下八大排序以及大根小根堆的处理方式,由于给出的目标实现函数的参数限制,使用非递归完成了很多数据结构的基本实现,这是之前从来没有过的。

遇到的问题

rust是一门内存安全的语言,因此我在编程过程中比较注重程序的内存占用以及与之有关的一些变量管理技术和方法,在做完练习之后感触最深的是有很多地方是因为类型选型的考虑步骤,导致必要时候还是需要进行多余的拷贝,或许有更好的处理这类优化问题的方法,但是目前对此还不够清楚,需要在之后的学习中不断深化。

新的思考

暂时没有,就是找这个blog的仓库脑子一下子短路了hhh,赶紧进行下一阶段吧,两个月挑战第二阶段 + 项目实现(危)。

第三阶段总结报告

没想到为期40天的第三阶段这么快就结束了。现在回想一下这四十天几乎每天都在准备考试和参加训练营两个任务之间时间片轮转。但是很庆幸我还是走到了训练营的尾声。

在第三阶段的项目六:基于协程异步机制的操作系统/驱动中,我了解到了我之前只是略有耳闻的异步,收获到了很多新知识。

首先我先阅读了《200行代码讲透RUST FUTURES》。在这里我又接触到了许多的新概念:绿色线程、Future、执行器、唤醒器。。。现在回想,看的过程实在是非常折磨,不仅要重新回顾本就不扎实的Rust语法,还要把多线程多协程带来的混乱执行流捋清楚。但是当我把它看完了之后,我才豁然开朗,我才明白Executor、Waker、Reactor、Future是如何协同工作以提高计算机的使用效率的。这为我后续阅读Embassy以及完成最终的成果打下了坚实的理论基础。

在《200行代码讲透RUST FUTURES》提供的理论知识的加持下,我进一步阅读了《Embassy Book》。当回到我最熟悉的领域时,总是让人心旷神怡。在阅读《Embassy Book》的全过程中,我并没有遇到太多的障碍(可能这就是专业对口的优势吧),但是我却无时无刻不在感叹Embassy作者对Rust语言的了解程度、他对丑陋的硬件近乎完美的封装以及Embassy向用户提供的友好接口。这让我觉得Embassy好像并不是一个嵌入式运行时库,而更像是一个开销更低的操作系统。

接下来就到了我觉得很有意义的部分。在这一小阶段,我对Embassy源码进行了逐步的调试,尝试理解Embassy的执行流。在Embassy中,有许多宏。Embassy的作者通过这些宏能够暴露给使用者干净、高效的接口,但是这对于我这种初学Rust,并且想理解Embassy执行流的人而言无疑是令人厌烦的。因为它隐藏了太多协程的细节(Rust语法对我而言也是很大的问题),所以我只能从头开始对Embassy源码进行调试。通过调试工具的帮助,我揭开了Embassy神秘的面纱:从创建执行器,到创建协程池;从创建主任务,到协程的不断循环执行。在此时我才真正领悟了Embassy的强大之处。

终于到了coding部分。我与我的队友一起分工合作,成功使用Rust重构了uC/OS II的线程调度模块,并在uC/OS II的线程支持下应用了Embassy的协程机制。这使得Embassy的执行器对MCU不在是独占的,而是可以基于线程的调度算法进行轮转。并且在线程的支持下实现协程,进一步提高了我们的系统的并发度。而且有了线程的调度机制,我们也可以实现不同线程的协程在任意点切换。

现在回想我在阶段三中完成的任务我才发现这些内容是多么地有意义。我了解到了Rust中的协程的实现机制,也了解到了Rust协程的一个实际应用——Embassy,最终我基于这些理论知识成功将Rust的协程使用起来,让我基本了解了一个能有效提高计算机系统性能的“秘籍“。

三阶段固然有意义,但是如果没有他人的帮助,我绝对坚持不到现在。

首先需要感谢我的队友。从三阶段一开始,我们就一直在交流关于Rust Future的各种细节。而到了调试Embassy的部分以及后面的coding,我们也都紧密配合。在调试Embassy的部分,如果没有他的学习成果,我很有可能就会被Embassy高级的Rust语法劝退;在coding部分,如果没有我们共同的努力,我们肯定不会在这么短的时间内使用一个我们都不熟悉的Rust重构一个操作系统的灵魂——线程调度模块,并且在这个基础上使用Embassy的协程机制。

最后还需要感谢向勇老师。在向勇老师的悉心指导下,我和我的队友明确了我们将来的目标。我们希望在堆栈池的支持下,实现线程内部的协程抢占。并且在这个基础上进一步完善我们在阶段三产出的阶段性成果,并将其应用在我们的四轴飞行器中。

再次回顾我的阶段三全过程,虽然我做事情不多,但是我仍收获颇丰。我相信不紧不慢依旧能走向未来。希望我今后也能保持着对异步、对Rust、对OS的满腔热爱,笃行不辍,履践致远。

转眼间训练营都结束了,这里大致总结一下我的第三阶段。

我第三阶段选择的课题是跨内核驱动开发,具体的要求,就是实现一个驱动,其能够在arceos和linux上运行,且其纯驱动代码部分不必修改。

一个设备在操作系统看来无非就是一些寄存器的集合,根据设备手册,我们可以知道如何通过修改和读取寄存器来控制和了解设备状态,对任何一个操作系统来说,都是如此,这也是纯驱动(也就是直接操作寄存器)代码不必修改的原因。

但是,对不同的内核,我们还需要不同的驱动适配器,比如,在linux中,我们需要向内核注册这一个设备(比如注册成杂项设备),并将设备抽象成一个文件,实现抽象的read和write方法。

此外,不同的内核地址映射的方法可能不同,在适配器中我们需要调用各自内核映射地址的接口,得到对应寄存器的地址,然后就可以使用纯驱动部分代码了。

在这个阶段里,我实现了一个GPIO点灯驱动,并在linux和arceos里成功运行,在这个过程中,知道了如何为linux编写驱动,rust是如何与kernel相配合的,以及在开发过程中由于踩各种坑被迫学习了一些关于linux kernel是如何编译的知识。

训练营结束之际,想感谢各位老师的帮助,各位同学的陪伴,也想感谢坚持到最后的自己。

学习内容:

rust异步编程,阅读200行代码讲透RUST FUTURES、rust圣经异步模块、embassy book,向勇老师的视频《并发与处理器、操作系统和编程语言》。

成果:

使用Tokio模块实现豆瓣图书爬虫。

学习心得:

通过阅读资料,学习rust 异步,针对IO密集型程序,异步相比多线程能够有较大的性能提升。rust 语言通过async和await 支持通过接近同步代码形式编写异步程序。rust 异步需要使用异步运行时,标准库并没有提供,常用的第三方库Tokio。
将异步移植到OS里面,遇到一些问题和困惑。1、ArceOS引入异步的话,是否只要引入异步运行时就可以;2、引入的运行时是否能用运行在标准库的运行时。
在继续学习,后续努力在ArceOS 网络模块引入异步时。