作者 | 马超
出品 | CSDN(ID:CSDNnews)

继Python之后,Rust最近也火爆得出了圈,目前Rust在Serverless等很多云原生领域已经稳定占据了C位,那么让Rust更进一步去开发操作系统的内核,就成为很多Rust粉丝心中的终极梦想,而Rust官方也一直有想法使Rust语言成为下一代操作系统的标准,在https://github.com/rust-osdev/上各种基于Rust开发的如BootLoader等工具已经发展比较齐全了,目前相对比较成熟的Rust操作系统有基于X86架构的Redox和清华大学的基于RISC-V架构芯片的rCore OS。

不过Rust想跨越C语言这座高山却并不容易,因为C语言就是为了实现操作系统而设计的。但是C语言作为一种诞生于半个世纪之前的语言,目前的确在很多方面的理念上已经落后于时代了,C语言本质上只是对于计算机硬件行为的一种抽象,瑞奇和汤普森两位天才引入的指针概念,小小的指针也大大地推进了整个IT行业的发展。

但是C 语言成也指针败也指针,指针的高效使得C语言成为各类语言的性能标杆,但指针带来的内存泄露,也是各大操作系统中的主要安全隐患。而Rust语言具有与C语言有着基本相同的运行性能,而且大幅增加了安全性。也有人将Rust称为安全版的C语言,因此让Rust到目前最流行的操作系统Linux当中去一显身手,也就颇为顺理成章了。

谷歌是率先在操作系统领域放弃C语言的科技巨头,也是Rust For Linux项目背后的主要推动力量,因为谷歌的Fuschia作为新一代操作系统内核Ziron中,很多关键模块都使用C++来开发。

从目前的情况来看,谷歌是不打算再用C语言作为未来操作系统的主体开发语言,虽然在Fuschia中使用了很多Rust代码,但是Fuschia毕竟还是个小众的试验性项目,如果能在真正的国民操作系统Linux上尝试Rust,才能真正试出来 Rust这门编程语言在操作系统内核开发方面到底是个什么成色。

目前Linux的创始人林纳斯对于Rust For Linux项目,也持正面看法,他表示:“我对这个项目很感兴趣,但我认为这是那些对 Rust 非常兴奋的人推动的,我想看看它然后在实践中最终如何工作。

就个人而言,我暂时不会推动 Rust 化,不过考虑到承诺的优势以及能够避免一些安全隐患,我对它持开放态度。但我也知道,有时承诺并不能实现”。在林纳斯表达这番言论以后,Rust进入Linux内核的项目也取得不少的积极进展。

GPIO驱动-RFL的最新进展

几天前一名来自于谷歌的Rust开发者Wedson Almeida Filho,发布了一个RUST版本ARM PL061 GPIO驱动,详见:https://github.com/wedsonaf。

Rust的GPIO驱动中对于Device ID表进行了构建,Rust强制开发人员决定数据类型,而且程序员管理变量的生命周期,因此驱动整个机制是类型安全的,而且更容易使用。由于代码很多,我们先把这两种语言的比较典型的对应函数实现,做一下对比:
C语言的 pl061_direction_input函数实现如下:

static int pl061_direction_input(struct gpio_chip *gc, unsigned offset)
{struct pl061 *pl061 = gpiochip_get_data(gc);unsigned long flags;unsigned char gpiodir;raw_spin_lock_irqsave(&pl061->lock, flags);gpiodir = readb(pl061->base + GPIODIR);gpiodir &= ~(BIT(offset));writeb(gpiodir, pl061->base + GPIODIR);raw_spin_unlock_irqrestore(&pl061->lock, flags);return 0;
}

Rust的 pl061_direction_input函数实现如下:


fn direction_input(data: &Ref<DeviceData>, offset: u32) -> Result {let _guard = data.lock();
let pl061 = data.resources().ok_or(Error::ENXIO)?;
let mut gpiodir = pl061.base.readb(GPIODIR);
gpiodir &= !bit(offset);
pl061.base.writeb(gpiodir, GPIODIR);
Ok(())
}

通过这两种语言的对比也可以看到,Rust中的lock锁是与具体要保护的数据是有强绑定关系的,开发者要调用data.lock()将锁进行锁定,只有这样才能受锁保护的数据才能被访问,程序员在锁使用的方面很难犯错误,而C语言的代码则需要显式配对使用raw_spin_lock_irqsave(&pl061->lock,flags);与raw_spin_unlock_irqrestore(&pl061->lock,flags)两个API才能达到类似效果,而且C语言中在加锁后,释放锁的操作是开发者必须要小心注意的问题,如果没有被及时释放锁还会造成很大的问题,因此从这方面说Rust的确是安全语言不过正如林纳斯所说,RustFor Linux目前还处在初始的探索阶段,Rust的首要目标应该是操作系统外围的驱动程序,因为驱动和整个内核比起来体积小,而且相对独立。但是想深入到Linux的核心部分,Rust要做的事情还很多。

内存模型-最大的阻碍

由于Rust特有的变量生命周期及借用等机制,所有变量在内存中都是可移动的,这对于引用Linux的数据结构来说是会有问题的。如果要固定变量的内存地址,就需要引入unsafe的Rust代码,这样的话Rust的安全优势也将荡然无存。用上文GPIO驱动作者Filho的话来说,现有Rust驱动程序中的许多不安全代码都源于这个可移动的问题。解决这个问题主要是找到正确的抽象,但是目前这个抽象模型还没有看到。

而且内存模型的问题还远不止数据的申请、释放与内存布局,在多核时代内存模型还增加了操作系统在保证执行顺序与并发灵活性之间复杂的取舍策略。

简单的讲当下最新的编译器、操作系统及处理器等等底层技术栈,都会进行某种程度上对于代码进行重排,以获取执行效率的优化比如relu函数的实现代码


if (x>0)    y = x;elsey = 0;

就可能被编译器优化为以下的代码:

y=0if (x>0)    y = x;

也就是说y会被提前赋值。
再比如以下代码


x=*p;y= *(p+1);

也很可能在执行时被CPU进行合并读取操作,也就是x与y被同时调入内存,按照CPU伪指令执行如下:


{x,y}=Load{p,p+1}

这些重排操作在单核情况下基本没有问题,但在现在的多核并行工作的时代就可能引发风险,在内存模型的建模机制上Rust和Linux并不相同,所以这也在很多方面造成了二者之间的融合问题,这个问题在Rust为Linux开发应用程序时几乎并不存在,但是当Rust想和C语言融为一体共同成为Linux的组成部分时就会被急剧的放大。

当然内存模型这个话题不是本文所能说清楚的,后面笔者还计划撰写文章对于Linux内存模型进行专题介绍,这里不加赘述了。

panic、alloc到底如何实现

在Linux当中一旦内核态的代码执行中出现不可恢复的错误,一般是通过panic操作来记录相关信息及调用栈,但由于Rust的内存申请与释放机制,其编译器通常会隐藏内存分配的操作,这就很可能使panic!()的调用出现问题。而且在某些驱动程序中,内存分配失败不应该直接使内核产生panic,因此Rust在申请内存失败后如果直接调用panic!,可能也是错误的。

而且在Linux标准接口中的内存分配alloc API也需要为Rust For Linux项目做好准备,像Rust中原生自带的数据类型中如Vec等,都无法通过稳定版本的Linux alloc接口分配内存,从目前非稳定版本的实现来看,实现alloc这些标准接口,很可能会大量引入很多unsafe的Rust代码,这将使Rust的价值大大降低。因此从细节上看Linux还要为Rust的入驻做更充分的准备。

稳定内联汇编-Rust操作系统的必游之路

其实即使是C语言也无法单独完成开发一整套操作系统的任务,汇编语言在很多情况下是操作系统所必须的,因为有一些关键操作必须直接调用CPU底层的指令才能执行,目前Rust在开启#!(feature(asm))的情况下倒是也可以支持内联汇编,例子如下:

#![no_std]#![feature(asm)]pub mod bits;pub mod mutex;pub mod ia_32e;#[cfg(test)]mod tests;pub  fn nop(){unsafe{       asm!("xor %eax, %eax"       :       :       : "{eax}"       :       );    }}fn main(){unsafe{       nop();    }}

灵魂拷问-少林与逍遥派的联手,真的会有那么好的效果吗

有关于Rust ForLinux的项目,笔者比较担心用C语言和Rust共同编写Linux内核会使Linux的可理解性和可学习性进一步降低,甚至看起来有点不伦不类,从某种程度上讲Rust For Linux就像用中文、英文双语穿插写《论语》、《圣经》一样会令人非常难以理解,甚至会降低著作的经典程度。

正如笔者在前文《Java、Go、Rust大比拼,高并发时代谁能称雄?》中所介绍的一样,Linux之所以能取得如此的成功,很大程度上是依靠C语言有如少林般的江湖地位,C语言像少林一样佛门广开,广结善缘,无论是扫地僧还是火工头陀都是门下的弟子,也正是在众多开发者的共同努力下,Linux项目才成为了当今世界上最受欢迎,贡献人数最多、使用人数也是最多的操作系统。

但Rust难的却像是火星语,Rust中多路通道在使用之前要clone,带锁的哈希表用之前要先unwrap,种种用法和C、Java完全不同,从这个角度上讲Rust很像逍遥派,想入门非常难,但只要能出师,写的程序能通过编译,那你百分百是一位高手,所以这是一门下限很高,上限同样也很高的极致语言。

正如著名的Linux开发者Greg Kroah Hartman所说,他虽然喜欢将Rust引入内核开发的想法,但这项工作还有很长的路要走,由于Rust语言的学习成本极高,因此要求开发人员至少在5年内使用Rust编写代码是不可能的。笔者的看法基本与Hartman相同,虽然Rust For Linux前任很光明,但是道路肯定会是曲折的。

用 Rust 开发 Linux,可行吗?相关推荐

  1. Rust开发环境搭建(Linux)

    1.使用Rustup安装 执行如下命令 curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh 执行结果如下: 在这里使用默认的安 ...

  2. [译]使用 Rust 开发一个简单的 Web 应用,第 4 部分 —— CLI 选项解析

    原文地址:A Simple Web App in Rust, Part 4 -- CLI Option Parsing 原文作者:Joel's Journal 译文出自:掘金翻译计划 本文永久链接:g ...

  3. rust开发环境_Rust 环境搭建

    Rust 环境搭建 Rust 支持很多的集成开发环境(IDE)或开发专用的文本编辑器. 本教程将使用 Visual Studio Code 作为我们的开发环境(Eclipse 有专用于 Rust 开发 ...

  4. 谷歌强推 Rust 进驻 Linux 内核,与主要开发者签订合同!

    整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 上个月底谷歌的"三儿子" Fuchsia OS 正式推出,一时众人的目光皆为其吸引. 其实自 2016 年 Fuch ...

  5. Rust for Linux 源码导读 | Ref 引用计数容器 原创

    引子 2022 年,我们很可能会看到 Linux 内核中的实验性 Rust 编程语言支持成为主流.2021.12.6 早上发出了更新的补丁,介绍了在内核中处理 Rust 的初始支持和基础设施. 这次更 ...

  6. Warp:一款融资 23000000 美元,基于 Rust 开发、支持 GPU 加速的 21 世纪终端工具...

    公众号关注 「奇妙的 Linux 世界」 设为「星标」,每天带你玩转 Linux ! Warp 是一个完全原生的.GPU 加速的基于 Rust 开发的终端工具,速度非常快,完全从头重新设计,Warp ...

  7. 使用 rust 开发 stm32:前言

    更多分享内容可访问我的个人博客 https://www.niuiic.top/ 本系列教程全部置于stm32专栏. 本文为使用 rust 开发 stm32 系列教程前言. Why Rust Rust ...

  8. clion浏览linux代码,手把手教你使用 Clion 开发 Linux C++ 项目

    手把手教你使用 Clion 开发 Linux C++ 项目 关于CLion CLion是一款专为开发C及C++所设计的跨平台IDE.它是以IntelliJ为基础设计的,包含了许多智能功能来提高开发人员 ...

  9. 我开发Linux服务程序的工作环境搭配

    嗯,这是和平同学的点题作文了,呵呵,他非要了解我是怎么开发Linux程序的,主要是这个工作环境是如何的? 原始问题如下: 问: 老师,可以写一篇文章介绍一下如何使用vim搭建好用的linux开发环境吗 ...

最新文章

  1. Python数据类型之字符串
  2. Dotfuscator使用教程
  3. LeetCode 404. 左叶子之和思考分析
  4. Spring Boot一个极简且完整的后台框架
  5. 如何构建尽可能小的容器镜像?
  6. 如何消除代码山中那一大坨参数列表
  7. virtio 网络的演化:原始virtio > vhost-net(内核态) > vhost-user(DPDK) > vDPA
  8. Java实现简单计算器
  9. 最全PR曲线、ROC曲线以及AUC计算公式详解
  10. uni 加入图标_uniapp如何更改图标
  11. CMOS、TTL门电路基础
  12. 计算机教室联想系统管理员密码,联想怎么清除bios超级管理员密码的方法
  13. Linux zip与unzip:通过正则式解压压缩包内指定的文件
  14. 超级计算机神威太湖之光储蓄量,中国超级计算机神威太湖之光世界最快,且总量排名榜单第一...
  15. QChart动态生成图表(曲线)
  16. AI耳机要想“复制”智能音箱的爆红,还要迈过哪些坎?
  17. android应用app开发
  18. plc里的二进制 用计算机,PLC中常用数制及如何转换
  19. Hibernate ORM映射中关clob及blob类型对应bo类 注解写法
  20. 深度学习中的Momentum算法原理

热门文章

  1. ARP协议以及攻击欺骗和防御
  2. Java:jar包和war包区别
  3. flex4 日期类型字符串转日期类型(string转Date)
  4. ActionScript 与后台交互 RemoteObject
  5. 解决网页中Waiting (TTFB)数据加载过慢的问题
  6. [bzoj1552][Cerc2007]robotic sort[bzoj3506][Cqoi2014]排序机械臂
  7. android权限列表
  8. spring所需包下载
  9. 奇怪的比赛--蓝桥杯
  10. ubuntu 下 maven安装